Repository: tetratelabs/wazero
Pull request #103 (2021-12-31 01:50:43)

jit: support for all comparison instructions


Patch:
diff --git a/go.mod b/go.mod
index d5cc77c3..30872227 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,8 @@ go 1.16
 
 require (
 	// only used in wat benchmarks
-	github.com/bytecodealliance/wasmtime-go v0.31.0
-	github.com/stretchr/testify v1.5.1
+	github.com/bytecodealliance/wasmtime-go v0.32.0
+	github.com/stretchr/testify v1.7.0
 	// Once we reach some maturity, remove this dep and implement our own assembler.
 	github.com/twitchyliquid64/golang-asm v0.15.1
 )
diff --git a/go.sum b/go.sum
index 4e2c3809..b2ae9bb6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,15 @@
-github.com/bytecodealliance/wasmtime-go v0.31.0 h1:AbMdV1pwjw/0Ito5yARcGzY366cq5NIiDk5vpy1c2Lw=
-github.com/bytecodealliance/wasmtime-go v0.31.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
+github.com/bytecodealliance/wasmtime-go v0.32.0 h1:/GsrnJz2bfULAIZygN4vUElLYliQrx/o/1opP9X7Gck=
+github.com/bytecodealliance/wasmtime-go v0.32.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/wasm/jit/compiler.go b/wasm/jit/compiler.go
index b20e1fca..a553594a 100644
--- a/wasm/jit/compiler.go
+++ b/wasm/jit/compiler.go
@@ -25,6 +25,11 @@ type compiler interface {
 	compilePick(o *wazeroir.OperationPick) error
 	compileAdd(o *wazeroir.OperationAdd) error
 	compileSub(o *wazeroir.OperationSub) error
+	compileEq(o *wazeroir.OperationEq) error
+	compileNe(o *wazeroir.OperationNe) error
+	compileEqz(o *wazeroir.OperationEqz) error
+	compileLt(o *wazeroir.OperationLt) error
+	compileGt(o *wazeroir.OperationGt) error
 	compileLe(o *wazeroir.OperationLe) error
 	compileGe(o *wazeroir.OperationGe) error
 	compileLoad(o *wazeroir.OperationLoad) error
diff --git a/wasm/jit/engine.go b/wasm/jit/engine.go
index e32ebfbe..a4f0bc58 100644
--- a/wasm/jit/engine.go
+++ b/wasm/jit/engine.go
@@ -519,15 +519,15 @@ func (e *engine) compileWasmFunction(f *wasm.FunctionInstance) (*compiledWasmFun
 		case *wazeroir.OperationConstF64:
 			err = compiler.compileConstF64(o)
 		case *wazeroir.OperationEq:
-			err = fmt.Errorf("unsupported operation")
+			err = compiler.compileEq(o)
 		case *wazeroir.OperationNe:
-			err = fmt.Errorf("unsupported operation")
+			err = compiler.compileNe(o)
 		case *wazeroir.OperationEqz:
-			err = fmt.Errorf("unsupported operation")
+			err = compiler.compileEqz(o)
 		case *wazeroir.OperationLt:
-			err = fmt.Errorf("unsupported operation")
+			err = compiler.compileLt(o)
 		case *wazeroir.OperationGt:
-			err = fmt.Errorf("unsupported operation")
+			err = compiler.compileGt(o)
 		case *wazeroir.OperationLe:
 			err = compiler.compileLe(o)
 		case *wazeroir.OperationGe:
diff --git a/wasm/jit/jit_amd64.go b/wasm/jit/jit_amd64.go
index 19c26a30..c77b216a 100644
--- a/wasm/jit/jit_amd64.go
+++ b/wasm/jit/jit_amd64.go
@@ -781,6 +781,229 @@ func (c *amd64Compiler) compileSub(o *wazeroir.OperationSub) error {
 	return nil
 }
 
+func (c *amd64Compiler) compileEq(o *wazeroir.OperationEq) error {
+	return c.emitEqOrNe(o.Type, true)
+}
+
+func (c *amd64Compiler) compileNe(o *wazeroir.OperationNe) error {
+	return c.emitEqOrNe(o.Type, false)
+}
+
+func (c *amd64Compiler) emitEqOrNe(t wazeroir.UnsignedType, shouldEqual bool) error {
+	x2 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x2); err != nil {
+		return err
+	}
+
+	x1 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x1); err != nil {
+		return err
+	}
+
+	// Emit the compare instruction.
+	prog := c.newProg()
+	prog.From.Type = obj.TYPE_REG
+	prog.From.Reg = x1.register
+	prog.To.Type = obj.TYPE_REG
+	prog.To.Reg = x2.register
+	switch t {
+	case wazeroir.UnsignedTypeI32:
+		prog.As = x86.ACMPL
+	case wazeroir.UnsignedTypeI64:
+		prog.As = x86.ACMPQ
+	case wazeroir.UnsignedTypeF32:
+		prog.As = x86.ACOMISS
+	case wazeroir.UnsignedTypeF64:
+		prog.As = x86.ACOMISD
+	}
+	c.addInstruction(prog)
+
+	// TODO: emit NaN value handings for floats.
+
+	// x1 and x2 are temporary registers only used for the cmp operation. Release them.
+	c.locationStack.releaseRegister(x1)
+	c.locationStack.releaseRegister(x2)
+
+	// Finally, record that the result is on the conditional register.
+	var condReg conditionalRegisterState
+	if shouldEqual {
+		condReg = conditionalRegisterStateE
+	} else {
+		condReg = conditionalRegisterStateNE
+	}
+	loc := c.locationStack.pushValueOnConditionalRegister(condReg)
+	loc.setRegisterType(generalPurposeRegisterTypeInt)
+	return nil
+}
+
+func (c *amd64Compiler) compileEqz(o *wazeroir.OperationEqz) error {
+	v := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(v); err != nil {
+		return err
+	}
+
+	// Take the temporary register for holding the zero value.
+	zeroRegister, err := c.allocateRegister(v.registerType())
+	if err != nil {
+		return err
+	}
+
+	// First, we have to clear the register so the value becomes zero via XOR on itself.
+	xorZero := c.newProg()
+	xorZero.As = x86.AXORQ
+	xorZero.From.Type = obj.TYPE_REG
+	xorZero.From.Reg = zeroRegister
+	xorZero.To.Type = obj.TYPE_REG
+	xorZero.To.Reg = zeroRegister
+	c.addInstruction(xorZero)
+
+	// Emit the compare instruction.
+	prog := c.newProg()
+	prog.From.Type = obj.TYPE_REG
+	prog.From.Reg = zeroRegister
+	prog.To.Type = obj.TYPE_REG
+	prog.To.Reg = v.register
+	switch o.Type {
+	case wazeroir.UnsignedInt32:
+		prog.As = x86.ACMPL
+	case wazeroir.UnsignedInt64:
+		prog.As = x86.ACMPQ
+	}
+	c.addInstruction(prog)
+
+	// v is consumed by the cmp operation so release it.
+	c.locationStack.releaseRegister(v)
+
+	// Finally, record that the result is on the conditional register.
+	loc := c.locationStack.pushValueOnConditionalRegister(conditionalRegisterStateE)
+	loc.setRegisterType(generalPurposeRegisterTypeInt)
+	return nil
+}
+
+func (c *amd64Compiler) compileLt(o *wazeroir.OperationLt) error {
+	x2 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x2); err != nil {
+		return err
+	}
+
+	x1 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x1); err != nil {
+		return err
+	}
+
+	// Emit the compare instruction.
+	prog := c.newProg()
+	prog.From.Type = obj.TYPE_REG
+	prog.To.Type = obj.TYPE_REG
+	var resultConditionState conditionalRegisterState
+	switch o.Type {
+	case wazeroir.SignedTypeInt32:
+		resultConditionState = conditionalRegisterStateL
+		prog.As = x86.ACMPL
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeUint32:
+		resultConditionState = conditionalRegisterStateB
+		prog.As = x86.ACMPL
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeInt64:
+		resultConditionState = conditionalRegisterStateL
+		prog.As = x86.ACMPQ
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeUint64:
+		resultConditionState = conditionalRegisterStateB
+		prog.As = x86.ACMPQ
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeFloat32:
+		resultConditionState = conditionalRegisterStateB
+		prog.As = x86.ACOMISS
+		prog.From.Reg = x2.register
+		prog.To.Reg = x1.register
+	case wazeroir.SignedTypeFloat64:
+		resultConditionState = conditionalRegisterStateB
+		prog.As = x86.ACOMISD
+		prog.From.Reg = x2.register
+		prog.To.Reg = x1.register
+	}
+	c.addInstruction(prog)
+
+	// TODO: emit NaN value handings for floats.
+
+	// x1 and x2 are temporary registers only used for the cmp operation. Release them.
+	c.locationStack.releaseRegister(x1)
+	c.locationStack.releaseRegister(x2)
+
+	// Finally, record that the result is on the conditional register.
+	loc := c.locationStack.pushValueOnConditionalRegister(resultConditionState)
+	loc.setRegisterType(generalPurposeRegisterTypeInt)
+	return nil
+}
+
+func (c *amd64Compiler) compileGt(o *wazeroir.OperationGt) error {
+	x2 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x2); err != nil {
+		return err
+	}
+
+	x1 := c.locationStack.pop()
+	if err := c.ensureOnGeneralPurposeRegister(x1); err != nil {
+		return err
+	}
+
+	// Emit the compare instruction.
+	prog := c.newProg()
+	prog.From.Type = obj.TYPE_REG
+	prog.To.Type = obj.TYPE_REG
+	var resultConditionState conditionalRegisterState
+	switch o.Type {
+	case wazeroir.SignedTypeInt32:
+		resultConditionState = conditionalRegisterStateG
+		prog.As = x86.ACMPL
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeUint32:
+		resultConditionState = conditionalRegisterStateA
+		prog.As = x86.ACMPL
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeInt64:
+		resultConditionState = conditionalRegisterStateG
+		prog.As = x86.ACMPQ
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeUint64:
+		resultConditionState = conditionalRegisterStateA
+		prog.As = x86.ACMPQ
+		prog.From.Reg = x1.register
+		prog.To.Reg = x2.register
+	case wazeroir.SignedTypeFloat32:
+		resultConditionState = conditionalRegisterStateA
+		prog.As = x86.ACOMISS
+		prog.From.Reg = x2.register
+		prog.To.Reg = x1.register
+	case wazeroir.SignedTypeFloat64:
+		resultConditionState = conditionalRegisterStateA
+		prog.As = x86.ACOMISD
+		prog.From.Reg = x2.register
+		prog.To.Reg = x1.register
+	}
+	c.addInstruction(prog)
+
+	// TODO: emit NaN value handings for floats.
+
+	// x1 and x2 are temporary registers only used for the cmp operation. Release them.
+	c.locationStack.releaseRegister(x1)
+	c.locationStack.releaseRegister(x2)
+
+	// Finally, record that the result is on the conditional register.
+	loc := c.locationStack.pushValueOnConditionalRegister(resultConditionState)
+	loc.setRegisterType(generalPurposeRegisterTypeInt)
+	return nil
+}
+
 func (c *amd64Compiler) compileLe(o *wazeroir.OperationLe) error {
 	x2 := c.locationStack.pop()
 	if err := c.ensureOnGeneralPurposeRegister(x2); err != nil {


Test patch:
diff --git a/wasm/jit/jit_amd64_test.go b/wasm/jit/jit_amd64_test.go
index 227a0606..221cdf6c 100644
--- a/wasm/jit/jit_amd64_test.go
+++ b/wasm/jit/jit_amd64_test.go
@@ -1094,290 +1094,322 @@ func TestAmd64Compiler_compileAdd(t *testing.T) {
 	})
 }
 
-func TestAmd64Compiler_compileLe(t *testing.T) {
-	t.Run("int32", func(t *testing.T) {
-		for _, tc := range []struct {
-			x1, x2 int32
-			signed bool
-		}{
-			{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint32
-			{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
-			{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint32
-			{x1: 100, x2: 200, signed: true},
-			{x1: 100, x2: 100, signed: true},
-			{x1: 200, x2: 100, signed: true},
-		} {
-			var o *wazeroir.OperationLe
-			if tc.signed {
-				o = &wazeroir.OperationLe{Type: wazeroir.SignedTypeInt32}
-			} else {
-				o = &wazeroir.OperationLe{Type: wazeroir.SignedTypeUint32}
-			}
-			compiler := requireNewCompiler(t)
-			compiler.initializeReservedRegisters()
-			x1Reg := int16(x86.REG_R9)
-			x2Reg := int16(x86.REG_R10)
-			compiler.locationStack.pushValueOnRegister(x1Reg)
-			compiler.locationStack.pushValueOnRegister(x2Reg)
-			compiler.movIntConstToRegister(int64(tc.x1), x1Reg)
-			compiler.movIntConstToRegister(int64(tc.x2), x2Reg)
-			err := compiler.compileLe(o)
-			require.NoError(t, err)
-
-			require.NotContains(t, compiler.locationStack.usedRegisters, x1Reg)
-			require.NotContains(t, compiler.locationStack.usedRegisters, x2Reg)
-			// To verify the behavior, we push the flag value
-			// to the stack.
-			top := compiler.locationStack.peek()
-			require.True(t, top.onConditionalRegister() && !top.onRegister())
-			err = compiler.moveConditionalToGeneralPurposeRegister(top)
-			require.NoError(t, err)
-			require.True(t, !top.onConditionalRegister() && top.onRegister())
-			compiler.releaseRegisterToStack(top)
-			compiler.returnFunction()
-
-			// Generate the code under test.
-			code, _, err := compiler.generate()
-			require.NoError(t, err)
-			// Run code.
-			eng := newEngine()
-			mem := newMemoryInst()
-			jitcall(
-				uintptr(unsafe.Pointer(&code[0])),
-				uintptr(unsafe.Pointer(eng)),
-				uintptr(unsafe.Pointer(&mem.Buffer[0])),
-			)
-			// Check the stack.
-			require.Equal(t, uint64(1), eng.stackPointer)
-			if tc.signed {
-				require.Equal(t, int32(tc.x1) <= int32(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-			} else {
-				require.Equal(t, uint32(tc.x1) <= uint32(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-			}
-		}
-	})
-	t.Run("int64", func(t *testing.T) {
-		for _, tc := range []struct {
-			x1, x2 int64
-			signed bool
-		}{
-			{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint64
-			{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
-			{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint64
-			{x1: 100, x2: 200, signed: true},
-			{x1: 200, x2: 100, signed: true},
-			{x1: 1 << 56, x2: 100, signed: true},
-			{x1: 1 << 56, x2: 1 << 61, signed: true},
-			{x1: math.MaxInt64, x2: 100, signed: true},
-			{x1: math.MinInt64, x2: 100, signed: true},
-		} {
-			var o *wazeroir.OperationLe
-			if tc.signed {
-				o = &wazeroir.OperationLe{Type: wazeroir.SignedTypeInt64}
-			} else {
-				o = &wazeroir.OperationLe{Type: wazeroir.SignedTypeUint64}
-			}
-			compiler := requireNewCompiler(t)
-			compiler.initializeReservedRegisters()
-			x1Reg := int16(x86.REG_R9)
-			x2Reg := int16(x86.REG_R10)
-			compiler.locationStack.pushValueOnRegister(x1Reg)
-			compiler.locationStack.pushValueOnRegister(x2Reg)
-			compiler.movIntConstToRegister(tc.x1, x1Reg)
-			compiler.movIntConstToRegister(tc.x2, x2Reg)
-			err := compiler.compileLe(o)
-			require.NoError(t, err)
-			require.NotContains(t, compiler.locationStack.usedRegisters, x1Reg)
-			require.NotContains(t, compiler.locationStack.usedRegisters, x2Reg)
-			// To verify the behavior, we push the flag value
-			// to the stack.
-			top := compiler.locationStack.peek()
-			require.True(t, top.onConditionalRegister() && !top.onRegister())
-			err = compiler.moveConditionalToGeneralPurposeRegister(top)
-			require.NoError(t, err)
-			require.True(t, !top.onConditionalRegister() && top.onRegister())
-			compiler.releaseRegisterToStack(top)
-			compiler.returnFunction()
-
-			// Generate the code under test.
-			code, _, err := compiler.generate()
-			require.NoError(t, err)
-			// Run code.
-			eng := newEngine()
-			mem := newMemoryInst()
-			jitcall(
-				uintptr(unsafe.Pointer(&code[0])),
-				uintptr(unsafe.Pointer(eng)),
-				uintptr(unsafe.Pointer(&mem.Buffer[0])),
-			)
-			// Check the stack.
-			require.Equal(t, uint64(1), eng.stackPointer)
-			if tc.signed {
-				require.Equal(t, tc.x1 <= tc.x2, eng.stack[eng.stackPointer-1] == 1)
-			} else {
-				require.Equal(t, uint64(tc.x1) <= uint64(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-			}
-		}
-	})
-	t.Run("float32", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 float32
-		}{
-			{x1: 100, x2: -1.1},
-			{x1: -1, x2: 100},
-			{x1: 100, x2: 200},
-			{x1: 100.01234124, x2: 100.01234124},
-			{x1: 100.01234124, x2: -100.01234124},
-			{x1: 200.12315, x2: 100},
-			{x1: float32(math.Inf(1)), x2: 100},
-			{x1: float32(math.Inf(-1)), x2: 100},
-		} {
-			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
-				// Prepare operands.
-				compiler := requireNewCompiler(t)
-				compiler.initializeReservedRegisters()
-				err := compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x1})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x2})
-				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-
-				// Emit the Le instructions,
-				err = compiler.compileLe(&wazeroir.OperationLe{Type: wazeroir.SignedTypeFloat32})
-				require.NoError(t, err)
-
-				// At this point, these registers must be consumed.
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
-				// Plus the result must be pushed.
-				require.Equal(t, uint64(1), compiler.locationStack.sp)
-
-				// To verify the behavior, we push the flag value
-				// to the stack.
-				flag := compiler.locationStack.peek()
-				require.True(t, flag.onConditionalRegister() && !flag.onRegister())
-				err = compiler.moveConditionalToGeneralPurposeRegister(flag)
-				require.NoError(t, err)
-				require.True(t, !flag.onConditionalRegister() && flag.onRegister())
-				compiler.releaseRegisterToStack(flag)
-				compiler.returnFunction()
-
-				// Generate the code under test.
-				code, _, err := compiler.generate()
-				require.NoError(t, err)
-				// Run code.
-				eng := newEngine()
-				mem := newMemoryInst()
-				jitcall(
-					uintptr(unsafe.Pointer(&code[0])),
-					uintptr(unsafe.Pointer(eng)),
-					uintptr(unsafe.Pointer(&mem.Buffer[0])),
-				)
-				// Check the stack.
-				require.Equal(t, uint64(1), eng.stackPointer)
-				require.Equal(t, tc.x1 <= tc.x2, eng.stack[eng.stackPointer-1] == 1)
+func TestAmd64Compiler_emitEqOrNe(t *testing.T) {
+	for _, instruction := range []struct {
+		name string
+		isEq bool
+	}{
+		{name: "eq", isEq: true},
+		{name: "ne", isEq: false},
+	} {
+		instruction := instruction
+		t.Run(instruction.name, func(t *testing.T) {
+			t.Run("int32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 uint32
+				}{
+					{x1: 100, x2: math.MaxUint32},
+					{x1: math.MaxUint32, x2: math.MaxUint32},
+					{x1: math.MaxUint32, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100, x2: 100},
+					{x1: 200, x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the cmp target values.
+						err := compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						if instruction.isEq {
+							err = compiler.compileEq(&wazeroir.OperationEq{Type: wazeroir.UnsignedTypeI32})
+						} else {
+							err = compiler.compileNe(&wazeroir.OperationNe{Type: wazeroir.UnsignedTypeI32})
+						}
+						require.NoError(t, err)
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						if instruction.isEq {
+							require.Equal(t, tc.x1 == tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						} else {
+							require.Equal(t, tc.x1 != tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						}
+					})
+				}
 			})
-		}
-	})
-	t.Run("float64", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 float64
-		}{
-			{x1: 100, x2: -1.1},
-			{x1: -1, x2: 100},
-			{x1: 100, x2: 200},
-			{x1: 100.01234124, x2: 100.01234124},
-			{x1: 100.01234124, x2: -100.01234124},
-			{x1: 200.12315, x2: 100},
-			{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 100},
-			{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 1.37438953472e+11 /* = 1 << 37*/},
-			{x1: math.Inf(1), x2: 100},
-			{x1: math.Inf(-1), x2: 100},
-		} {
-			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
-				// Prepare operands.
-				compiler := requireNewCompiler(t)
-				compiler.initializeReservedRegisters()
-				err := compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x1})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x2})
-				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-
-				// Emit the Le instructions,
-				err = compiler.compileLe(&wazeroir.OperationLe{Type: wazeroir.SignedTypeFloat64})
-				require.NoError(t, err)
-
-				// At this point, these registers must be consumed.
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
-				// Plus the result must be pushed.
-				require.Equal(t, uint64(1), compiler.locationStack.sp)
-
-				// To verify the behavior, we push the flag value
-				// to the stack.
-				flag := compiler.locationStack.peek()
-				require.True(t, flag.onConditionalRegister() && !flag.onRegister())
-				err = compiler.moveConditionalToGeneralPurposeRegister(flag)
-				require.NoError(t, err)
-				require.True(t, !flag.onConditionalRegister() && flag.onRegister())
-				compiler.releaseRegisterToStack(flag)
-				compiler.returnFunction()
-
-				// Generate the code under test.
-				code, _, err := compiler.generate()
-				require.NoError(t, err)
-				// Run code.
-				eng := newEngine()
-				mem := newMemoryInst()
-				jitcall(
-					uintptr(unsafe.Pointer(&code[0])),
-					uintptr(unsafe.Pointer(eng)),
-					uintptr(unsafe.Pointer(&mem.Buffer[0])),
-				)
-				// Check the stack.
-				require.Equal(t, uint64(1), eng.stackPointer)
-				require.Equal(t, tc.x1 <= tc.x2, eng.stack[eng.stackPointer-1] == 1)
+			t.Run("int64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 uint64
+				}{
+					{x1: 1, x2: math.MaxUint64},
+					{x1: 100, x2: 200},
+					{x1: 200, x2: 100},
+					{x1: 1 << 56, x2: 100},
+					{x1: 1 << 56, x2: 1 << 61},
+					{x1: math.MaxUint64, x2: 100},
+					{x1: 0, x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the cmp target values.
+						err := compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						if instruction.isEq {
+							err = compiler.compileEq(&wazeroir.OperationEq{Type: wazeroir.UnsignedTypeI64})
+						} else {
+							err = compiler.compileNe(&wazeroir.OperationNe{Type: wazeroir.UnsignedTypeI64})
+						}
+						require.NoError(t, err)
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						if instruction.isEq {
+							require.Equal(t, tc.x1 == tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						} else {
+							require.Equal(t, tc.x1 != tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						}
+					})
+				}
 			})
-		}
-	})
+			t.Run("float32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float32
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: float32(math.Inf(1)), x2: 100},
+					{x1: 100, x2: float32(math.Inf(1))},
+					{x1: float32(math.Inf(1)), x2: float32(math.Inf(1))},
+					{x1: float32(math.Inf(-1)), x2: 100},
+					{x1: 100, x2: float32(math.Inf(-1))},
+					{x1: float32(math.Inf(-1)), x2: float32(math.Inf(-1))},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the cmp target values.
+						err := compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						if instruction.isEq {
+							err = compiler.compileEq(&wazeroir.OperationEq{Type: wazeroir.UnsignedTypeF32})
+						} else {
+							err = compiler.compileNe(&wazeroir.OperationNe{Type: wazeroir.UnsignedTypeF32})
+						}
+						require.NoError(t, err)
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						if instruction.isEq {
+							require.Equal(t, tc.x1 == tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						} else {
+							require.Equal(t, tc.x1 != tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						}
+					})
+				}
+			})
+			t.Run("float64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float64
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 1.37438953472e+11 /* = 1 << 37*/},
+					{x1: math.Inf(1), x2: 100},
+					{x1: math.Inf(-1), x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the cmp target values.
+						err := compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions
+						if instruction.isEq {
+							err = compiler.compileEq(&wazeroir.OperationEq{Type: wazeroir.UnsignedTypeF64})
+						} else {
+							err = compiler.compileNe(&wazeroir.OperationNe{Type: wazeroir.UnsignedTypeF64})
+						}
+						require.NoError(t, err)
+
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						if instruction.isEq {
+							require.Equal(t, tc.x1 == tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						} else {
+							require.Equal(t, tc.x1 != tc.x2, eng.stack[eng.stackPointer-1] == 1)
+						}
+					})
+				}
+			})
+		})
+	}
 }
 
-func TestAmd64Compiler_compileGe(t *testing.T) {
+func TestAmd64Compiler_compileEqz(t *testing.T) {
 	t.Run("int32", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 int32
-			signed bool
-		}{
-			{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint32
-			{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
-			{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint32
-			{x1: 100, x2: 200, signed: true},
-			{x1: 100, x2: 100, signed: true},
-			{x1: 200, x2: 100, signed: true},
+		for i, v := range []uint32{
+			0, 1 << 16, math.MaxUint32,
 		} {
+			v := v
 			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
 				compiler := requireNewCompiler(t)
 				compiler.initializeReservedRegisters()
-				err := compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x1)})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x2)})
+
+				// Push the cmp target value.
+				err := compiler.compileConstI32(&wazeroir.OperationConstI32{Value: v})
 				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-				var o *wazeroir.OperationGe
-				if tc.signed {
-					o = &wazeroir.OperationGe{Type: wazeroir.SignedTypeInt64}
-				} else {
-					o = &wazeroir.OperationGe{Type: wazeroir.SignedTypeUint64}
-				}
-				err = compiler.compileGe(o)
+				loc := compiler.locationStack.peek()
+
+				// Emit the eqz instructions.
+				err = compiler.compileEqz(&wazeroir.OperationEqz{Type: wazeroir.UnsignedInt32})
 				require.NoError(t, err)
+				// At this point, the target value must be consumed
+				// so the corresponding register must be marked unused.
+				require.NotContains(t, compiler.locationStack.usedRegisters, loc.register)
 
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
 				// To verify the behavior, we push the flag value
 				// to the stack.
 				top := compiler.locationStack.peek()
@@ -1389,7 +1421,6 @@ func TestAmd64Compiler_compileGe(t *testing.T) {
 				compiler.returnFunction()
 
 				// Generate the code under test.
-				// and the verification code (moving the result to the stack so we can assert against it)
 				code, _, err := compiler.generate()
 				require.NoError(t, err)
 				// Run code.
@@ -1402,48 +1433,31 @@ func TestAmd64Compiler_compileGe(t *testing.T) {
 				)
 				// Check the stack.
 				require.Equal(t, uint64(1), eng.stackPointer)
-				if tc.signed {
-					require.Equal(t, int32(tc.x1) >= int32(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-				} else {
-					require.Equal(t, uint32(tc.x1) >= uint32(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-				}
+				require.Equal(t, v == uint32(0), eng.stack[eng.stackPointer-1] == 1)
 			})
 		}
 	})
 	t.Run("int64", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 int64
-			signed bool
-		}{
-			{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint64
-			{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
-			{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint64
-			{x1: 100, x2: 200, signed: true},
-			{x1: 200, x2: 100, signed: true},
-			{x1: 1 << 56, x2: 100, signed: true},
-			{x1: 1 << 56, x2: 1 << 61, signed: true},
-			{x1: math.MaxInt64, x2: 100, signed: true},
-			{x1: math.MinInt64, x2: 100, signed: true},
+		for i, v := range []uint64{
+			0, 1 << 16, 1 << 36, math.MaxUint64,
 		} {
+			v := v
 			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
 				compiler := requireNewCompiler(t)
 				compiler.initializeReservedRegisters()
-				err := compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x1)})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x2)})
+
+				// Push the cmp target values.
+				err := compiler.compileConstI64(&wazeroir.OperationConstI64{Value: v})
 				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-				var o *wazeroir.OperationGe
-				if tc.signed {
-					o = &wazeroir.OperationGe{Type: wazeroir.SignedTypeInt64}
-				} else {
-					o = &wazeroir.OperationGe{Type: wazeroir.SignedTypeUint64}
-				}
-				err = compiler.compileGe(o)
+				loc := compiler.locationStack.peek()
+
+				// Emit the eqz instructions.
+				err = compiler.compileEqz(&wazeroir.OperationEqz{Type: wazeroir.UnsignedInt64})
 				require.NoError(t, err)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+				// At this point, the target value must be consumed
+				// so the corresponding register must be marked unused.
+				require.NotContains(t, compiler.locationStack.usedRegisters, loc.register)
+
 				// To verify the behavior, we push the flag value
 				// to the stack.
 				top := compiler.locationStack.peek()
@@ -1455,7 +1469,6 @@ func TestAmd64Compiler_compileGe(t *testing.T) {
 				compiler.returnFunction()
 
 				// Generate the code under test.
-				// and the verification code (moving the result to the stack so we can assert against it)
 				code, _, err := compiler.generate()
 				require.NoError(t, err)
 				// Run code.
@@ -1468,140 +1481,649 @@ func TestAmd64Compiler_compileGe(t *testing.T) {
 				)
 				// Check the stack.
 				require.Equal(t, uint64(1), eng.stackPointer)
-				if tc.signed {
-					require.Equal(t, tc.x1 >= tc.x2, eng.stack[eng.stackPointer-1] == 1)
-				} else {
-					require.Equal(t, uint64(tc.x1) >= uint64(tc.x2), eng.stack[eng.stackPointer-1] == 1)
-				}
+				require.Equal(t, v == uint64(0), eng.stack[eng.stackPointer-1] == 1)
 			})
 		}
 	})
-	t.Run("float32", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 float32
-		}{
-			{x1: 100, x2: -1.1},
-			{x1: -1, x2: 100},
-			{x1: 100, x2: 200},
-			{x1: 100.01234124, x2: 100.01234124},
-			{x1: 100.01234124, x2: -100.01234124},
-			{x1: 200.12315, x2: 100},
-			{x1: float32(math.Inf(1)), x2: 100},
-			{x1: float32(math.Inf(-1)), x2: 100},
-		} {
-			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
-				// Prepare operands.
-				compiler := requireNewCompiler(t)
-				compiler.initializeReservedRegisters()
-				err := compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x1})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x2})
-				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-
-				// Emit the Ge instructions,
-				err = compiler.compileGe(&wazeroir.OperationGe{Type: wazeroir.SignedTypeFloat32})
-				require.NoError(t, err)
-
-				// At this point, these registers must be consumed.
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
-				// Plus the result must be pushed.
-				require.Equal(t, uint64(1), compiler.locationStack.sp)
-
-				// To verify the behavior, we push the flag value
-				// to the stack.
-				flag := compiler.locationStack.peek()
-				require.True(t, flag.onConditionalRegister() && !flag.onRegister())
-				err = compiler.moveConditionalToGeneralPurposeRegister(flag)
-				require.NoError(t, err)
-				require.True(t, !flag.onConditionalRegister() && flag.onRegister())
-				compiler.releaseRegisterToStack(flag)
-				compiler.returnFunction()
+}
 
-				// Generate the code under test.
-				// and the verification code (moving the result to the stack so we can assert against it)
-				code, _, err := compiler.generate()
-				require.NoError(t, err)
-				// Run code.
-				eng := newEngine()
-				mem := newMemoryInst()
-				jitcall(
-					uintptr(unsafe.Pointer(&code[0])),
-					uintptr(unsafe.Pointer(eng)),
-					uintptr(unsafe.Pointer(&mem.Buffer[0])),
-				)
-				// Check the stack.
-				require.Equal(t, uint64(1), eng.stackPointer)
-				require.Equal(t, tc.x1 >= tc.x2, eng.stack[eng.stackPointer-1] == 1)
+func TestAmd64Compiler_compileLe_or_Lt(t *testing.T) {
+	for _, instruction := range []struct {
+		name      string
+		inclusive bool
+	}{
+		{name: "less_than_or_equal", inclusive: true},
+		{name: "less_than", inclusive: false},
+	} {
+		instruction := instruction
+		t.Run(instruction.name, func(t *testing.T) {
+			t.Run("int32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 int32
+					signed bool
+				}{
+					{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint32
+					{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
+					{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint32
+					{x1: 100, x2: 200, signed: true},
+					{x1: 100, x2: 100, signed: true},
+					{x1: 200, x2: 100, signed: true},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the target values.
+						err := compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						var targetType wazeroir.SignedType
+						if tc.signed {
+							targetType = wazeroir.SignedTypeInt32
+						} else {
+							targetType = wazeroir.SignedTypeUint32
+						}
+						if instruction.inclusive {
+							err = compiler.compileLe(&wazeroir.OperationLe{Type: targetType})
+						} else {
+							err = compiler.compileLt(&wazeroir.OperationLt{Type: targetType})
+						}
+						require.NoError(t, err)
+
+						// At this point, all the registesr must be consumed by cmp
+						// so they should be marked as unused.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						var exp bool
+						if tc.signed {
+							exp = tc.x1 < tc.x2
+						} else {
+							exp = uint32(tc.x1) < uint32(tc.x2)
+						}
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
 			})
-		}
-	})
-	t.Run("float64", func(t *testing.T) {
-		for i, tc := range []struct {
-			x1, x2 float64
-		}{
-			{x1: 100, x2: -1.1},
-			{x1: -1, x2: 100},
-			{x1: 100, x2: 200},
-			{x1: 100.01234124, x2: 100.01234124},
-			{x1: 100.01234124, x2: -100.01234124},
-			{x1: 200.12315, x2: 100},
-			{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 100},
-			{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 1.37438953472e+11 /* = 1 << 37*/},
-			{x1: math.Inf(1), x2: 100},
-			{x1: math.Inf(-1), x2: 100},
-		} {
-			t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
-				// Prepare operands.
-				compiler := requireNewCompiler(t)
-				compiler.initializeReservedRegisters()
-				err := compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x1})
-				require.NoError(t, err)
-				x1 := compiler.locationStack.peek()
-				err = compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x2})
-				require.NoError(t, err)
-				x2 := compiler.locationStack.peek()
-
-				// Emit the Ge instructions,
-				err = compiler.compileGe(&wazeroir.OperationGe{Type: wazeroir.SignedTypeFloat64})
-				require.NoError(t, err)
-
-				// At this point, these registers must be consumed.
-				require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
-				require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
-				// Plus the result must be pushed.
-				require.Equal(t, uint64(1), compiler.locationStack.sp)
-
-				// To verify the behavior, we push the flag value
-				// to the stack.
-				flag := compiler.locationStack.peek()
-				require.True(t, flag.onConditionalRegister() && !flag.onRegister())
-				err = compiler.moveConditionalToGeneralPurposeRegister(flag)
-				require.NoError(t, err)
-				require.True(t, !flag.onConditionalRegister() && flag.onRegister())
-				compiler.releaseRegisterToStack(flag)
-				compiler.returnFunction()
+			t.Run("int64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 int64
+					signed bool
+				}{
+					{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint64
+					{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
+					{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint64
+					{x1: 100, x2: 200, signed: true},
+					{x1: 200, x2: 100, signed: true},
+					{x1: 1 << 56, x2: 100, signed: true},
+					{x1: 1 << 56, x2: 1 << 61, signed: true},
+					{x1: math.MaxInt64, x2: 100, signed: true},
+					{x1: math.MinInt64, x2: 100, signed: true},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the target values.
+						err := compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						var targetType wazeroir.SignedType
+						if tc.signed {
+							targetType = wazeroir.SignedTypeInt64
+						} else {
+							targetType = wazeroir.SignedTypeUint64
+						}
+						if instruction.inclusive {
+							err = compiler.compileLe(&wazeroir.OperationLe{Type: targetType})
+						} else {
+							err = compiler.compileLt(&wazeroir.OperationLt{Type: targetType})
+						}
+						require.NoError(t, err)
+
+						// At this point, all the registesr must be consumed by cmp
+						// so they should be marked as unused.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						var exp bool
+						if tc.signed {
+							exp = tc.x1 < tc.x2
+						} else {
+							exp = uint64(tc.x1) < uint64(tc.x2)
+						}
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+			t.Run("float32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float32
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: float32(math.Inf(1)), x2: 100},
+					{x1: float32(math.Inf(-1)), x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						// Prepare operands.
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+						err := compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions
+						if instruction.inclusive {
+							err = compiler.compileLe(&wazeroir.OperationLe{Type: wazeroir.SignedTypeFloat32})
+						} else {
+							err = compiler.compileLt(&wazeroir.OperationLt{Type: wazeroir.SignedTypeFloat32})
+						}
+						require.NoError(t, err)
+
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						exp := tc.x1 < tc.x2
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+			t.Run("float64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float64
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 1.37438953472e+11 /* = 1 << 37*/},
+					{x1: math.Inf(1), x2: 100},
+					{x1: math.Inf(-1), x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						// Prepare operands.
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+						err := compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions,
+						if instruction.inclusive {
+							err = compiler.compileLe(&wazeroir.OperationLe{Type: wazeroir.SignedTypeFloat64})
+						} else {
+							err = compiler.compileLt(&wazeroir.OperationLt{Type: wazeroir.SignedTypeFloat64})
+						}
+						require.NoError(t, err)
+
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						exp := tc.x1 < tc.x2
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+		})
+	}
+}
 
-				// Generate the code under test.
-				// and the verification code (moving the result to the stack so we can assert against it)
-				code, _, err := compiler.generate()
-				require.NoError(t, err)
-				// Run code.
-				eng := newEngine()
-				mem := newMemoryInst()
-				jitcall(
-					uintptr(unsafe.Pointer(&code[0])),
-					uintptr(unsafe.Pointer(eng)),
-					uintptr(unsafe.Pointer(&mem.Buffer[0])),
-				)
-				// Check the stack.
-				require.Equal(t, uint64(1), eng.stackPointer)
-				require.Equal(t, tc.x1 >= tc.x2, eng.stack[eng.stackPointer-1] == 1)
+func TestAmd64Compiler_compileGe_or_Gt(t *testing.T) {
+	for _, instruction := range []struct {
+		name      string
+		inclusive bool
+	}{
+		{name: "greater_than_or_equal", inclusive: true},
+		{name: "greater_than", inclusive: false},
+	} {
+		instruction := instruction
+		t.Run(instruction.name, func(t *testing.T) {
+			t.Run("int32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 int32
+					signed bool
+				}{
+					{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint32
+					{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
+					{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint32
+					{x1: 100, x2: 200, signed: true},
+					{x1: 100, x2: 100, signed: true},
+					{x1: 200, x2: 100, signed: true},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the target values.
+						err := compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						var targetType wazeroir.SignedType
+						if tc.signed {
+							targetType = wazeroir.SignedTypeInt32
+						} else {
+							targetType = wazeroir.SignedTypeUint32
+						}
+						if instruction.inclusive {
+							err = compiler.compileGe(&wazeroir.OperationGe{Type: targetType})
+						} else {
+							err = compiler.compileGt(&wazeroir.OperationGt{Type: targetType})
+						}
+						require.NoError(t, err)
+
+						// At this point, all the registesr must be consumed by cmp
+						// so they should be marked as unused.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						var exp bool
+						if tc.signed {
+							exp = tc.x1 > tc.x2
+						} else {
+							exp = uint32(tc.x1) > uint32(tc.x2)
+						}
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
 			})
-		}
-	})
+			t.Run("int64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 int64
+					signed bool
+				}{
+					{x1: 100, x2: -1, signed: false}, // interpret x2 as max uint64
+					{x1: -1, x2: -1, signed: false},  // interpret x1 and x2 as max uint32
+					{x1: -1, x2: 100, signed: false}, // interpret x1 as max uint64
+					{x1: 100, x2: 200, signed: true},
+					{x1: 200, x2: 100, signed: true},
+					{x1: 1 << 56, x2: 100, signed: true},
+					{x1: 1 << 56, x2: 1 << 61, signed: true},
+					{x1: math.MaxInt64, x2: 100, signed: true},
+					{x1: math.MinInt64, x2: 100, signed: true},
+				} {
+
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+
+						// Push the target values.
+						err := compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x1)})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: uint64(tc.x2)})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions.
+						var targetType wazeroir.SignedType
+						if tc.signed {
+							targetType = wazeroir.SignedTypeInt64
+						} else {
+							targetType = wazeroir.SignedTypeUint64
+						}
+						if instruction.inclusive {
+							err = compiler.compileGe(&wazeroir.OperationGe{Type: targetType})
+						} else {
+							err = compiler.compileGt(&wazeroir.OperationGt{Type: targetType})
+						}
+						require.NoError(t, err)
+
+						// At this point, all the registesr must be consumed by cmp
+						// so they should be marked as unused.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						top := compiler.locationStack.peek()
+						require.True(t, top.onConditionalRegister() && !top.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(top)
+						require.NoError(t, err)
+						require.True(t, !top.onConditionalRegister() && top.onRegister())
+						compiler.releaseRegisterToStack(top)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						var exp bool
+						if tc.signed {
+							exp = tc.x1 > tc.x2
+						} else {
+							exp = uint64(tc.x1) > uint64(tc.x2)
+						}
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+			t.Run("float32", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float32
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: float32(math.Inf(1)), x2: 100},
+					{x1: float32(math.Inf(-1)), x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						// Prepare operands.
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+						err := compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF32(&wazeroir.OperationConstF32{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions,
+						if instruction.inclusive {
+							err = compiler.compileGe(&wazeroir.OperationGe{Type: wazeroir.SignedTypeFloat32})
+						} else {
+							err = compiler.compileGt(&wazeroir.OperationGt{Type: wazeroir.SignedTypeFloat32})
+						}
+						require.NoError(t, err)
+
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						exp := tc.x1 > tc.x2
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+			t.Run("float64", func(t *testing.T) {
+				for i, tc := range []struct {
+					x1, x2 float64
+				}{
+					{x1: 100, x2: -1.1},
+					{x1: -1, x2: 100},
+					{x1: 100, x2: 200},
+					{x1: 100.01234124, x2: 100.01234124},
+					{x1: 100.01234124, x2: -100.01234124},
+					{x1: 200.12315, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 100},
+					{x1: 6.8719476736e+10 /* = 1 << 36 */, x2: 1.37438953472e+11 /* = 1 << 37*/},
+					{x1: math.Inf(1), x2: 100},
+					{x1: math.Inf(-1), x2: 100},
+				} {
+					t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+						// Prepare operands.
+						compiler := requireNewCompiler(t)
+						compiler.initializeReservedRegisters()
+						err := compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x1})
+						require.NoError(t, err)
+						x1 := compiler.locationStack.peek()
+						err = compiler.compileConstF64(&wazeroir.OperationConstF64{Value: tc.x2})
+						require.NoError(t, err)
+						x2 := compiler.locationStack.peek()
+
+						// Emit the cmp instructions,
+						if instruction.inclusive {
+							err = compiler.compileGe(&wazeroir.OperationGe{Type: wazeroir.SignedTypeFloat64})
+						} else {
+							err = compiler.compileGt(&wazeroir.OperationGt{Type: wazeroir.SignedTypeFloat64})
+						}
+						require.NoError(t, err)
+
+						// At this point, these registers must be consumed.
+						require.NotContains(t, compiler.locationStack.usedRegisters, x1.register)
+						require.NotContains(t, compiler.locationStack.usedRegisters, x2.register)
+						// Plus the result must be pushed.
+						require.Equal(t, uint64(1), compiler.locationStack.sp)
+
+						// To verify the behavior, we push the flag value
+						// to the stack.
+						flag := compiler.locationStack.peek()
+						require.True(t, flag.onConditionalRegister() && !flag.onRegister())
+						err = compiler.moveConditionalToGeneralPurposeRegister(flag)
+						require.NoError(t, err)
+						require.True(t, !flag.onConditionalRegister() && flag.onRegister())
+						compiler.releaseRegisterToStack(flag)
+						compiler.returnFunction()
+
+						// Generate the code under test.
+						// and the verification code (moving the result to the stack so we can assert against it)
+						code, _, err := compiler.generate()
+						require.NoError(t, err)
+						// Run code.
+						eng := newEngine()
+						mem := newMemoryInst()
+						jitcall(
+							uintptr(unsafe.Pointer(&code[0])),
+							uintptr(unsafe.Pointer(eng)),
+							uintptr(unsafe.Pointer(&mem.Buffer[0])),
+						)
+
+						// Check the stack.
+						require.Equal(t, uint64(1), eng.stackPointer)
+						exp := tc.x1 > tc.x2
+						if instruction.inclusive {
+							exp = exp || tc.x1 == tc.x2
+						}
+						require.Equal(t, exp, eng.stack[eng.stackPointer-1] == 1)
+					})
+				}
+			})
+		})
+	}
 }
 
 func TestAmd64Compiler_compileSub(t *testing.T) {