diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7e3a9ed5f..7133a2789 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2822,7 +2822,69 @@ impl FunctionCodeGenerator for X64FunctionCode { a, &mut self.machine, &mut self.value_stack, - Assembler::emit_vminss, + |a, src1, src2, dst| { + let loc1 = Location::XMM(src1); + let loc2 = match src2 { + XMMOrMemory::XMM(x) => Location::XMM(x), + XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), + }; + // TODO: use temp_gpr (or at least check that src2 isn't + // XMMOrMemory that uses AX or DX. + a.emit_mov(Size::S32, loc1, Location::GPR(GPR::RAX)); + a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); + // TODO: we can skip this when dst is an XMM reg. + let tmp_xmm = if src1 == XMM::XMM0 { + if src2 == XMMOrMemory::XMM(XMM::XMM1) { + XMM::XMM2 + } else { + XMM::XMM1 + } + } else { + XMM::XMM0 + }; + match src2 { + XMMOrMemory::XMM(x) => { + a.emit_mov(Size::S64, Location::XMM(x), Location::XMM(tmp_xmm)) + } + XMMOrMemory::Memory(base, disp) => a.emit_mov( + Size::S64, + Location::Memory(base, disp), + Location::XMM(tmp_xmm), + ), + }; + a.emit_ucomiss(XMMOrMemory::XMM(src1), tmp_xmm); + let do_vminss = a.get_label(); + a.emit_jmp(Condition::NotEqual, do_vminss); + a.emit_jmp(Condition::ParityEven, do_vminss); + a.emit_cmp(Size::S32, Location::GPR(GPR::RAX), Location::GPR(GPR::RDX)); + a.emit_jmp(Condition::Equal, do_vminss); + static NEG_ZERO: u128 = 0x80000000; + match src2 { + XMMOrMemory::XMM(x) => { + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(GPR::RDX), + ); + a.emit_mov(Size::S64, Location::Memory(GPR::RDX, 0), Location::XMM(x)); + } + XMMOrMemory::Memory(base, disp) => { + // TODO: What if base == RDX? + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(GPR::RDX), + ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RDX, 0), + Location::Memory(base, disp), + ); + } + }; + a.emit_label(do_vminss); + a.emit_vminss(src1, src2, dst); + }, ), Operator::F32Eq => Self::emit_fp_cmpop_avx( a, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 2e747f7ec..d4030ce76 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -26,6 +26,8 @@ pub enum Condition { Equal, NotEqual, Signed, + ParityEven, + ParityOdd, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -36,7 +38,7 @@ pub enum Size { S64, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[allow(dead_code)] pub enum XMMOrMemory { XMM(XMM), @@ -602,6 +604,8 @@ impl Emitter for Assembler { Condition::Equal => jmp_op!(je, self, label), Condition::NotEqual => jmp_op!(jne, self, label), Condition::Signed => jmp_op!(js, self, label), + Condition::ParityEven => jmp_op!(jp, self, label), + Condition::ParityOdd => jmp_op!(jnp, self, label), } } fn emit_jmp_location(&mut self, loc: Location) { @@ -625,6 +629,8 @@ impl Emitter for Assembler { Condition::Equal => trap_op!(je, self), Condition::NotEqual => trap_op!(jne, self), Condition::Signed => trap_op!(js, self), + Condition::ParityEven => trap_op!(jp, self), + Condition::ParityOdd => trap_op!(jnp, self), } } fn emit_set(&mut self, condition: Condition, dst: GPR) { diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index dee265684..dbc7677c5 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -465,7 +465,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E singlepass:fail:conversions.wast:241 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:242 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:f32.wast:1620 # AssertReturn - result F32(0) ("0x0") does not match expected F32(2147483648) ("0x80000000") singlepass:fail:f32.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f32.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f32.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) @@ -902,15 +901,6 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i32.wast:242 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:243 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") -singlepass:fail:i32.wast:244 # AssertReturn - result I32(15) ("0xf") does not match expected I32(16) ("0x10") -singlepass:fail:i32.wast:245 # AssertReturn - result I32(7) ("0x7") does not match expected I32(24) ("0x18") -singlepass:fail:i32.wast:246 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:247 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") -singlepass:fail:i32.wast:248 # AssertReturn - result I32(1) ("0x1") does not match expected I32(30) ("0x1e") -singlepass:fail:i32.wast:249 # AssertReturn - result I32(30) ("0x1e") does not match expected I32(1) ("0x1") -singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -920,15 +910,6 @@ singlepass:fail:i64.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i64.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i64.wast:242 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:243 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") -singlepass:fail:i64.wast:244 # AssertReturn - result I64(15) ("0xf") does not match expected I64(48) ("0x30") -singlepass:fail:i64.wast:245 # AssertReturn - result I64(7) ("0x7") does not match expected I64(56) ("0x38") -singlepass:fail:i64.wast:246 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:247 # AssertReturn - result I64(0) ("0x0") does not match expected I64(63) ("0x3f") -singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not match expected I64(62) ("0x3e") -singlepass:fail:i64.wast:249 # AssertReturn - result I64(62) ("0x3e") does not match expected I64(1) ("0x1") -singlepass:fail:i64.wast:252 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") singlepass:fail:if.wast:440 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error