Skip to content

Commit

Permalink
winch: Add saturating conversion instructions (#7909)
Browse files Browse the repository at this point in the history
This commit adds support for the saturating conversions instructions.
  • Loading branch information
saulecabrera committed Feb 9, 2024
1 parent 1f6e901 commit 2c6f386
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 512 deletions.
1 change: 0 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
if testsuite == "spec_testsuite" {
let denylist = [
"br_table",
"conversions",
"global",
"table_fill",
"table_get",
Expand Down
497 changes: 0 additions & 497 deletions tests/misc_testsuite/winch/conversions.wast

This file was deleted.

4 changes: 3 additions & 1 deletion winch/codegen/src/isa/aarch64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
masm::{
CalleeKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind,
MacroAssembler as Masm, OperandSize, RegImm, RemKind, RoundingMode, SPOffset, ShiftKind,
StackSlot, TrapCode,
StackSlot, TrapCode, TruncKind,
},
};
use cranelift_codegen::{settings, Final, MachBufferFinalized, MachLabel};
Expand Down Expand Up @@ -379,6 +379,7 @@ impl Masm for MacroAssembler {
_dst: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
_kind: TruncKind,
) {
todo!()
}
Expand All @@ -390,6 +391,7 @@ impl Masm for MacroAssembler {
_tmp_fpr: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
_kind: TruncKind,
) {
todo!()
}
Expand Down
6 changes: 4 additions & 2 deletions winch/codegen/src/isa/x64/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,11 +615,12 @@ impl Assembler {
tmp_xmm: Reg,
src_size: OperandSize,
dst_size: OperandSize,
saturating: bool,
) {
self.emit(Inst::CvtFloatToSintSeq {
dst_size: dst_size.into(),
src_size: src_size.into(),
is_saturating: false,
is_saturating: saturating,
src: src.into(),
dst: dst.into(),
tmp_gpr: tmp_gpr.into(),
Expand All @@ -637,11 +638,12 @@ impl Assembler {
tmp_xmm2: Reg,
src_size: OperandSize,
dst_size: OperandSize,
saturating: bool,
) {
self.emit(Inst::CvtFloatToUintSeq {
dst_size: dst_size.into(),
src_size: src_size.into(),
is_saturating: false,
is_saturating: saturating,
src: src.into(),
dst: dst.into(),
tmp_gpr: tmp_gpr.into(),
Expand Down
6 changes: 5 additions & 1 deletion winch/codegen/src/isa/x64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{

use crate::masm::{
DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm, OperandSize,
RegImm, RemKind, RoundingMode, ShiftKind, TrapCode, TRUSTED_FLAGS, UNTRUSTED_FLAGS,
RegImm, RemKind, RoundingMode, ShiftKind, TrapCode, TruncKind, TRUSTED_FLAGS, UNTRUSTED_FLAGS,
};
use crate::{
abi::ABI,
Expand Down Expand Up @@ -1021,6 +1021,7 @@ impl Masm for MacroAssembler {
dst: Reg,
src_size: OperandSize,
dst_size: OperandSize,
kind: TruncKind,
) {
self.asm.cvt_float_to_sint_seq(
src,
Expand All @@ -1029,6 +1030,7 @@ impl Masm for MacroAssembler {
regs::scratch_xmm(),
src_size,
dst_size,
kind.is_checked(),
);
}

Expand All @@ -1039,6 +1041,7 @@ impl Masm for MacroAssembler {
tmp_fpr: Reg,
src_size: OperandSize,
dst_size: OperandSize,
kind: TruncKind,
) {
self.asm.cvt_float_to_uint_seq(
src,
Expand All @@ -1048,6 +1051,7 @@ impl Masm for MacroAssembler {
tmp_fpr,
src_size,
dst_size,
kind.is_checked(),
);
}

Expand Down
29 changes: 28 additions & 1 deletion winch/codegen/src/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ pub(crate) enum MemMoveDirection {
LowToHigh,
}

/// Classifies how to treat float-to-int conversions.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum TruncKind {
/// Saturating conversion. If the source value is greater than the maximum
/// value of the destination type, the result is clamped to the
/// destination maximum value.
Checked,
/// An exception is raised if the source value is greater than the maximum
/// value of the destination type.
Unchecked,
}

impl TruncKind {
/// Returns true if the truncation kind is checked.
pub(crate) fn is_checked(&self) -> bool {
*self == TruncKind::Checked
}
}

/// Representation of the stack pointer offset.
#[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)]
pub struct SPOffset(u32);
Expand Down Expand Up @@ -676,7 +695,14 @@ pub(crate) trait MacroAssembler {

/// Emits one or more instructions to perform a signed truncation of a
/// float into an integer.
fn signed_truncate(&mut self, src: Reg, dst: Reg, src_size: OperandSize, dst_size: OperandSize);
fn signed_truncate(
&mut self,
src: Reg,
dst: Reg,
src_size: OperandSize,
dst_size: OperandSize,
kind: TruncKind,
);

/// Emits one or more instructions to perform an unsigned truncation of a
/// float into an integer.
Expand All @@ -687,6 +713,7 @@ pub(crate) trait MacroAssembler {
tmp_fpr: Reg,
src_size: OperandSize,
dst_size: OperandSize,
kind: TruncKind,
);

/// Emits one or more instructions to perform a signed convert of an
Expand Down
115 changes: 106 additions & 9 deletions winch/codegen/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::abi::{RetArea, ABI};
use crate::codegen::{control_index, Callee, CodeGen, ControlStackFrame, FnCall};
use crate::masm::{
DivKind, ExtendKind, FloatCmpKind, IntCmpKind, MacroAssembler, MemMoveDirection, OperandSize,
RegImm, RemKind, RoundingMode, SPOffset, ShiftKind,
RegImm, RemKind, RoundingMode, SPOffset, ShiftKind, TruncKind,
};
use crate::stack::{TypedReg, Val};
use cranelift_codegen::ir::TrapCode;
Expand Down Expand Up @@ -231,6 +231,15 @@ macro_rules! def_unsupported {
(emit F32Store $($rest:tt)*) => {};
(emit F64Load $($rest:tt)*) => {};
(emit F64Store $($rest:tt)*) => {};
(emit I32TruncSatF32S $($rest:tt)*) => {};
(emit I32TruncSatF32U $($rest:tt)*) => {};
(emit I32TruncSatF64S $($rest:tt)*) => {};
(emit I32TruncSatF64U $($rest:tt)*) => {};
(emit I64TruncSatF32S $($rest:tt)*) => {};
(emit I64TruncSatF32U $($rest:tt)*) => {};
(emit I64TruncSatF64S $($rest:tt)*) => {};
(emit I64TruncSatF64U $($rest:tt)*) => {};


(emit $unsupported:tt $($rest:tt)*) => {$($rest)*};
}
Expand Down Expand Up @@ -1162,7 +1171,7 @@ where

self.context
.convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S32, dst_size);
masm.signed_truncate(src, dst, S32, dst_size, TruncKind::Unchecked);
});
}

Expand All @@ -1174,7 +1183,7 @@ where
WasmValType::I32,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size);
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size, TruncKind::Unchecked);
},
);
}
Expand All @@ -1184,7 +1193,7 @@ where

self.context
.convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S64, dst_size);
masm.signed_truncate(src, dst, S64, dst_size, TruncKind::Unchecked);
});
}

Expand All @@ -1196,7 +1205,7 @@ where
WasmValType::I32,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size);
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size, TruncKind::Unchecked);
},
);
}
Expand All @@ -1206,7 +1215,7 @@ where

self.context
.convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S32, dst_size);
masm.signed_truncate(src, dst, S32, dst_size, TruncKind::Unchecked);
});
}

Expand All @@ -1218,7 +1227,7 @@ where
WasmValType::I64,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size);
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size, TruncKind::Unchecked);
},
);
}
Expand All @@ -1228,7 +1237,7 @@ where

self.context
.convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S64, dst_size);
masm.signed_truncate(src, dst, S64, dst_size, TruncKind::Unchecked);
});
}

Expand All @@ -1240,7 +1249,7 @@ where
WasmValType::I64,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size);
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size, TruncKind::Unchecked);
},
);
}
Expand Down Expand Up @@ -1944,6 +1953,94 @@ where
self.emit_wasm_store(&memarg, OperandSize::S64)
}

fn visit_i32_trunc_sat_f32_s(&mut self) {
use OperandSize::*;

self.context
.convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S32, dst_size, TruncKind::Checked);
});
}

fn visit_i32_trunc_sat_f32_u(&mut self) {
use OperandSize::*;

self.context.convert_op_with_tmp_reg(
self.masm,
WasmValType::I32,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size, TruncKind::Checked);
},
);
}

fn visit_i32_trunc_sat_f64_s(&mut self) {
use OperandSize::*;

self.context
.convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S64, dst_size, TruncKind::Checked);
});
}

fn visit_i32_trunc_sat_f64_u(&mut self) {
use OperandSize::*;

self.context.convert_op_with_tmp_reg(
self.masm,
WasmValType::I32,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size, TruncKind::Checked);
},
);
}

fn visit_i64_trunc_sat_f32_s(&mut self) {
use OperandSize::*;

self.context
.convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S32, dst_size, TruncKind::Checked);
});
}

fn visit_i64_trunc_sat_f32_u(&mut self) {
use OperandSize::*;

self.context.convert_op_with_tmp_reg(
self.masm,
WasmValType::I64,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S32, dst_size, TruncKind::Checked);
},
);
}

fn visit_i64_trunc_sat_f64_s(&mut self) {
use OperandSize::*;

self.context
.convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
masm.signed_truncate(src, dst, S64, dst_size, TruncKind::Checked);
});
}

fn visit_i64_trunc_sat_f64_u(&mut self) {
use OperandSize::*;

self.context.convert_op_with_tmp_reg(
self.masm,
WasmValType::I64,
RegClass::Float,
|masm, dst, src, tmp_fpr, dst_size| {
masm.unsigned_truncate(src, dst, tmp_fpr, S64, dst_size, TruncKind::Checked);
},
);
}

wasmparser::for_each_operator!(def_unsupported);
}

Expand Down

0 comments on commit 2c6f386

Please sign in to comment.