Repository: tetratelabs/wazero
Pull request #1982 (2024-01-30 19:19:04)

wazevo(amd64): fixes Brnz+Fcmp lowering


Patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/cond.go b/internal/engine/wazevo/backend/isa/amd64/cond.go
index f26f3a03..75cbeab7 100644
--- a/internal/engine/wazevo/backend/isa/amd64/cond.go
+++ b/internal/engine/wazevo/backend/isa/amd64/cond.go
@@ -1,6 +1,10 @@
 package amd64
 
-import "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+import (
+	"fmt"
+
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+)
 
 type cond byte
 
@@ -109,18 +113,12 @@ func condFromSSAIntCmpCond(origin ssa.IntegerCmpCond) cond {
 
 func condFromSSAFloatCmpCond(origin ssa.FloatCmpCond) cond {
 	switch origin {
-	case ssa.FloatCmpCondEqual:
-		return condZ
-	case ssa.FloatCmpCondNotEqual:
-		return condNZ
-	case ssa.FloatCmpCondLessThan:
-		return condB
 	case ssa.FloatCmpCondGreaterThanOrEqual:
 		return condNB
 	case ssa.FloatCmpCondGreaterThan:
 		return condNBE
-	case ssa.FloatCmpCondLessThanOrEqual:
-		return condBE
+	case ssa.FloatCmpCondEqual, ssa.FloatCmpCondNotEqual, ssa.FloatCmpCondLessThan, ssa.FloatCmpCondLessThanOrEqual:
+		panic(fmt.Sprintf("cond %s must be treated as a special case", origin))
 	default:
 		panic("unreachable")
 	}
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index 6900db3b..beb81794 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -225,9 +225,17 @@ func (m *machine) LowerConditionalBranch(b *ssa.Instruction) {
 		cvalInstr := cvalDef.Instr
 
 		f1, f2, and := m.lowerFcmpToFlags(cvalInstr)
+		isBrz := b.Opcode() == ssa.OpcodeBrz
+		if isBrz {
+			f1 = f1.invert()
+		}
 		if f2 == condInvalid {
 			m.insert(m.allocateInstr().asJmpIf(f1, newOperandLabel(target)))
 		} else {
+			if isBrz {
+				f2 = f2.invert()
+				and = !and
+			}
 			jmp1, jmp2 := m.allocateInstr(), m.allocateInstr()
 			m.insert(jmp1)
 			m.insert(jmp2)


Test patch:
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index 7244107d..013d83d2 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -606,6 +606,16 @@ func TestE2E(t *testing.T) {
 				{params: []uint64{0x00000000, 0x11111111, 0x11111111, 0xffffffff}, expResults: []uint64{0x11001100, 0xff11ff11}},
 			},
 		},
+		{
+			name: "float_le",
+			m:    testcases.FloatLe.Module,
+			calls: []callCase{
+				{params: []uint64{math.Float64bits(1.0)}, expResults: []uint64{1, 1}},
+				{params: []uint64{math.Float64bits(0.0)}, expResults: []uint64{1, 1}},
+				{params: []uint64{math.Float64bits(1.1)}, expResults: []uint64{0, 0}},
+				{params: []uint64{math.Float64bits(math.NaN())}, expResults: []uint64{0, 0}},
+			},
+		},
 	} {
 		tc := tc
 		t.Run(tc.name, func(t *testing.T) {
@@ -1234,7 +1244,7 @@ func TestSpectestV1(t *testing.T) {
 		{name: "binary"},
 		{name: "binary-leb128"},
 		{name: "call"},
-		//{name: "call_indirect"},
+		{name: "call_indirect"},
 		{name: "comments"},
 		{name: "custom"},
 		//{name: "conversions"},
@@ -1318,7 +1328,7 @@ func TestSpectestV2(t *testing.T) {
 		{"i64"},
 		{"br"},
 		{"call"},
-		//{"call_indirect"},
+		{"call_indirect"},
 		//{"conversions"},
 		{"global"},
 		{"if"},
diff --git a/internal/engine/wazevo/testcases/testcases.go b/internal/engine/wazevo/testcases/testcases.go
index b5582f2b..f7b98929 100644
--- a/internal/engine/wazevo/testcases/testcases.go
+++ b/internal/engine/wazevo/testcases/testcases.go
@@ -1184,6 +1184,34 @@ var (
 			wasm.OpcodeEnd,
 		}, []wasm.ValueType{}),
 	}
+	FloatLe = TestCase{
+		Name: "float_le",
+		Module: SingleFunctionModule(wasm.FunctionType{
+			Params:  []wasm.ValueType{f64},
+			Results: []wasm.ValueType{i64, i64},
+		}, []byte{
+			wasm.OpcodeLocalGet, 0,
+			wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 240, 63, // 1.0
+			wasm.OpcodeF64Le,
+			wasm.OpcodeIf, blockSignature_vv,
+			wasm.OpcodeI64Const, 1,
+			wasm.OpcodeLocalGet, 0,
+			wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 240, 63, // 1.0
+			wasm.OpcodeF64Le,
+			wasm.OpcodeI64ExtendI32U,
+			wasm.OpcodeReturn,
+			wasm.OpcodeElse,
+			wasm.OpcodeI64Const, 0,
+			wasm.OpcodeLocalGet, 0,
+			wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 240, 63, // 1.0
+			wasm.OpcodeF64Le,
+			wasm.OpcodeI64ExtendI32U,
+			wasm.OpcodeReturn,
+			wasm.OpcodeEnd,
+			wasm.OpcodeUnreachable,
+			wasm.OpcodeEnd,
+		}, []wasm.ValueType{}),
+	}
 	MinMaxFloat = TestCase{
 		Name: "min_max_float",
 		Module: SingleFunctionModule(wasm.FunctionType{