Repository: tetratelabs/wazero
Pull request #1978 (2024-01-30 00:05:14)

wazevo(amd64): fixes copy condition


Patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr.go b/internal/engine/wazevo/backend/isa/amd64/instr.go
index e0988450..23e88c27 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr.go
@@ -460,7 +460,16 @@ func (i *instruction) AssignDef(reg regalloc.VReg) {
 // IsCopy implements regalloc.Instr.
 func (i *instruction) IsCopy() bool {
 	k := i.kind
-	return k == movRR || (k == xmmUnaryRmR && i.op1.kind == operandKindReg)
+	if k == movRR {
+		return true
+	}
+	if k == xmmUnaryRmR {
+		if i.op1.kind == operandKindReg {
+			sse := sseOpcode(i.u1)
+			return sse == sseOpcodeMovss || sse == sseOpcodeMovsd || sse == sseOpcodeMovdqu
+		}
+	}
+	return false
 }
 
 func resetInstruction(i *instruction) {
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index b7be9650..edbcaffe 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -320,6 +320,8 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) {
 		m.lowerRound(instr, roundingModeNearest)
 	case ssa.OpcodeFmin, ssa.OpcodeFmax:
 		m.lowerFminFmax(instr)
+	case ssa.OpcodeFcopysign:
+		m.lowerFcopysign(instr)
 	case ssa.OpcodeSqrt:
 		m.lowerSqrt(instr)
 	case ssa.OpcodeUndefined:
@@ -1636,3 +1638,38 @@ func (m *machine) lowerFminFmax(instr *ssa.Instruction) {
 
 	m.copyTo(tmp, rd)
 }
+
+func (m *machine) lowerFcopysign(instr *ssa.Instruction) {
+	x, y := instr.Arg2()
+	if !x.Type().IsFloat() {
+		panic("BUG")
+	}
+
+	_64 := x.Type().Bits() == 64
+
+	xDef, yDef := m.c.ValueDefinition(x), m.c.ValueDefinition(y)
+	rm := m.getOperand_Reg(xDef)
+	rn := m.getOperand_Reg(yDef)
+	rd := m.c.VRegOf(instr.Return())
+
+	// Clear the non-sign bits of src via AND with the mask.
+	var opAnd, opOr sseOpcode
+	var mask uint64
+	if _64 {
+		mask, opAnd, opOr = 0x8000000000000000, sseOpcodeAndpd, sseOpcodeOrpd
+	} else {
+		mask, opAnd, opOr = 0x80000000, sseOpcodeAndps, sseOpcodeOrps
+	}
+
+	tmp := m.c.AllocateVReg(x.Type())
+	m.lowerFconst(tmp, mask, _64)
+
+	and := m.allocateInstr().asXmmRmR(opAnd, rn, tmp)
+	m.insert(and)
+
+	// Finally, copy the sign bit of src to dst.
+	or := m.allocateInstr().asXmmRmR(opOr, rm, tmp)
+	m.insert(or)
+
+	m.copyTo(tmp, rd)
+}


Test patch:
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index a5011578..f313bb61 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -300,6 +300,8 @@ func TestE2E(t *testing.T) {
 						math.Float64bits(2),
 						math.Float64bits(1),
 
+						math.Float64bits(-25),
+
 						uint64(math.Float32bits(-25)),
 						uint64(math.Float32bits(25)),
 
@@ -313,6 +315,8 @@ func TestE2E(t *testing.T) {
 						uint64(math.Float32bits(1)),
 						uint64(math.Float32bits(2)),
 						uint64(math.Float32bits(1)),
+
+						uint64(math.Float32bits(-25)),
 					},
 				},
 			},
@@ -1239,10 +1243,10 @@ func TestSpectestV1(t *testing.T) {
 		{name: "elem"},
 		//{name: "endianness"},
 		{name: "exports"},
-		//{name: "f32"},
+		{name: "f32"},
 		//{name: "f32_bitwise"},
 		{name: "f32_cmp"},
-		//{name: "f64"},
+		{name: "f64"},
 		//{name: "f64_bitwise"},
 		{name: "f64_cmp"},
 		{name: "fac"},
diff --git a/internal/engine/wazevo/testcases/testcases.go b/internal/engine/wazevo/testcases/testcases.go
index 2a15eb63..b5582f2b 100644
--- a/internal/engine/wazevo/testcases/testcases.go
+++ b/internal/engine/wazevo/testcases/testcases.go
@@ -1090,8 +1090,8 @@ var (
 		Module: SingleFunctionModule(wasm.FunctionType{
 			Params: []wasm.ValueType{f64, f64, f64, f32, f32, f32},
 			Results: []wasm.ValueType{
-				f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64,
-				f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32,
+				f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64,
+				f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32,
 			},
 		}, []byte{
 			wasm.OpcodeLocalGet, 0,
@@ -1132,6 +1132,11 @@ var (
 			wasm.OpcodeLocalGet, 2,
 			wasm.OpcodeF64Trunc,
 
+			wasm.OpcodeLocalGet, 0,
+			wasm.OpcodeLocalGet, 1,
+			wasm.OpcodeF64Neg,
+			wasm.OpcodeF64Copysign,
+
 			// 32-bit floats.
 			wasm.OpcodeLocalGet, 3,
 			wasm.OpcodeF32Neg,
@@ -1171,6 +1176,11 @@ var (
 			wasm.OpcodeLocalGet, 5,
 			wasm.OpcodeF32Trunc,
 
+			wasm.OpcodeLocalGet, 3,
+			wasm.OpcodeLocalGet, 4,
+			wasm.OpcodeF32Neg,
+			wasm.OpcodeF32Copysign,
+
 			wasm.OpcodeEnd,
 		}, []wasm.ValueType{}),
 	}