Repository: tetratelabs/wazero
Pull request #632 (2022-06-17 04:29:38)

arm64: implement vector comparisons 
This implements vector comparison instructions for 
arm64 backend.

part of #484 


Patch:
diff --git a/internal/asm/arm64/consts.go b/internal/asm/arm64/consts.go
index 4538baef..76cc3fbd 100644
--- a/internal/asm/arm64/consts.go
+++ b/internal/asm/arm64/consts.go
@@ -772,6 +772,20 @@ const (
 	SSHR
 	// EXT is the EXT instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/EXT--Extract-vector-from-pair-of-vectors-?lang=en
 	EXT
+	// CMGT is the CMGT(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMGT--register---Compare-signed-Greater-than--vector--?lang=en
+	CMGT
+	// CMHI is the CMHI(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMHI--register---Compare-unsigned-Higher--vector--?lang=en
+	CMHI
+	// CMGE is the CMGE(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMGE--register---Compare-signed-Greater-than-or-Equal--vector--?lang=en
+	CMGE
+	// CMHS is the CMHS(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMHS--register---Compare-unsigned-Higher-or-Same--vector--?lang=en
+	CMHS
+	// FCMEQ is the FCMEQ(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMEQ--register---Floating-point-Compare-Equal--vector--?lang=en
+	FCMEQ
+	// FCMGT is the FCMGT(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMGT--register---Floating-point-Compare-Greater-than--vector--?lang=en
+	FCMGT
+	// FCMGE is the FCMGE(register) instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMGE--register---Floating-point-Compare-Greater-than-or-Equal--vector--?lang=en
+	FCMGE
 
 	// instructionEnd is always placed at the bottom of this iota definition to be used in the test.
 	instructionEnd
@@ -1176,6 +1190,20 @@ func InstructionName(i asm.Instruction) string {
 		return "SSHR"
 	case EXT:
 		return "EXT"
+	case CMGT:
+		return "CMGT"
+	case CMHI:
+		return "CMHI"
+	case CMGE:
+		return "CMGE"
+	case CMHS:
+		return "CMHS"
+	case FCMEQ:
+		return "FCMEQ"
+	case FCMGT:
+		return "FCMGT"
+	case FCMGE:
+		return "FCMGE"
 	}
 	panic(fmt.Errorf("unknown instruction %d", i))
 }
diff --git a/internal/asm/arm64/impl.go b/internal/asm/arm64/impl.go
index dea74b46..8cd8c359 100644
--- a/internal/asm/arm64/impl.go
+++ b/internal/asm/arm64/impl.go
@@ -3049,41 +3049,77 @@ var advancedSIMDThreeSame = map[asm.Instruction]struct {
 		return
 	}},
 	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/UMAXP--Unsigned-Maximum-Pairwise-?lang=en
-	UMAXP: {U: 0b1, Opcode: 0b10100, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
-		return
-	}},
+	UMAXP: {U: 0b1, Opcode: 0b10100, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
 	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMEQ--register---Compare-bitwise-Equal--vector--?lang=en
-	CMEQ: {U: 0b1, Opcode: 0b10001, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
-		return
-	}},
+	CMEQ: {U: 0b1, Opcode: 0b10001, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
 	// https://developer.arm.com/documentation/dui0801/g/A64-SIMD-Vector-Instructions/ADDP--vector-
-	VADDP: {U: 0b0, Opcode: 0b10111, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
-		return
-	}},
+	VADDP: {U: 0b0, Opcode: 0b10111, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
 	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/ADD--vector---Add--vector--?lang=en
-	VADD: {U: 0, Opcode: 0b10000, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
-		return
-	}},
+	VADD: {U: 0, Opcode: 0b10000, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
 	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/SUB--vector---Subtract--vector--?lang=en
-	VSUB: {U: 1, Opcode: 0b10000, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
+	VSUB: {U: 1, Opcode: 0b10000, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/SSHL--Signed-Shift-Left--register--?lang=en
+	SSHL: {U: 0, Opcode: 0b01000, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/SSHL--Signed-Shift-Left--register--?lang=en
+	USHL: {U: 0b1, Opcode: 0b01000, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMGT--register---Compare-signed-Greater-than--vector--?lang=en
+	CMGT: {U: 0b0, Opcode: 0b00110, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMHI--register---Compare-unsigned-Higher--vector--?lang=en
+	CMHI: {U: 0b1, Opcode: 0b00110, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMGE--register---Compare-signed-Greater-than-or-Equal--vector--?lang=en
+	CMGE: {U: 0b0, Opcode: 0b00111, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/CMHS--register---Compare-unsigned-Higher-or-Same--vector--?lang=en
+	CMHS: {U: 0b1, Opcode: 0b00111, qAndSizeResolver: advancedSIMDThreeSameDefaultResolver},
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMEQ--register---Floating-point-Compare-Equal--vector--?lang=en
+	FCMEQ: {U: 0b0, Opcode: 0b11100, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
+		switch arrangement {
+		case VectorArrangement4S:
+			size, Q = 0b00, 1
+		case VectorArrangement2S:
+			size, Q = 0b00, 0
+		case VectorArrangement2D:
+			size, Q = 0b01, 1
+		default:
+			err = fmt.Errorf("unsupported arrangement %s for %s", arrangement.String(), InstructionName(FCMEQ))
+		}
 		return
 	}},
-	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/SSHL--Signed-Shift-Left--register--?lang=en
-	SSHL: {U: 0, Opcode: 0b01000, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMGT--register---Floating-point-Compare-Greater-than--vector--?lang=en
+	FCMGT: {U: 0b1, Opcode: 0b11100, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
+		switch arrangement {
+		case VectorArrangement4S:
+			size, Q = 0b10, 1
+		case VectorArrangement2S:
+			size, Q = 0b10, 0
+		case VectorArrangement2D:
+			size, Q = 0b11, 1
+		default:
+			err = fmt.Errorf("unsupported arrangement %s for %s", arrangement.String(), InstructionName(FCMGT))
+		}
 		return
 	}},
-	USHL: {U: 0b1, Opcode: 0b01000, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
-		size, Q = arrangementSizeQ(arrangement)
+	// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/FCMGE--register---Floating-point-Compare-Greater-than-or-Equal--vector--?lang=en
+	FCMGE: {U: 0b1, Opcode: 0b11100, qAndSizeResolver: func(arrangement VectorArrangement) (Q, size byte, err error) {
+		switch arrangement {
+		case VectorArrangement4S:
+			size, Q = 0b00, 1
+		case VectorArrangement2S:
+			size, Q = 0b00, 0
+		case VectorArrangement2D:
+			size, Q = 0b01, 1
+		default:
+			err = fmt.Errorf("unsupported arrangement %s for %s", arrangement.String(), InstructionName(FCMGE))
+		}
 		return
 	}},
 }
 
+func advancedSIMDThreeSameDefaultResolver(arrangement VectorArrangement) (Q, size byte, err error) {
+	// TODO: simply use arrangementSizeQ as the resolver after refactoring other call-site of arrangementSizeQ.
+	size, Q = arrangementSizeQ(arrangement)
+	return
+}
+
 // advancedSIMDAcrossLanes holds information to encode instructions as "Advanced SIMD across lanes" in
 // https://developer.arm.com/documentation/ddi0596/2021-12/Index-by-Encoding/Data-Processing----Scalar-Floating-Point-and-Advanced-SIMD?lang=en
 var advancedSIMDAcrossLanes = map[asm.Instruction]struct {
diff --git a/internal/engine/compiler/impl_vec_arm64.go b/internal/engine/compiler/impl_vec_arm64.go
index 44def486..f7a9a97a 100644
--- a/internal/engine/compiler/impl_vec_arm64.go
+++ b/internal/engine/compiler/impl_vec_arm64.go
@@ -939,7 +939,76 @@ func (c *arm64Compiler) compileV128ShiftImpl(shape wazeroir.Shape, ins asm.Instr
 
 // compileV128Cmp implements compiler.compileV128Cmp for arm64.
 func (c *arm64Compiler) compileV128Cmp(o *wazeroir.OperationV128Cmp) error {
-	return fmt.Errorf("TODO: %s is not implemented yet on arm64 compiler", o.Kind())
+	x2 := c.locationStack.popV128()
+	if err := c.compileEnsureOnGeneralPurposeRegister(x2); err != nil {
+		return err
+	}
+
+	x1 := c.locationStack.popV128()
+	if err := c.compileEnsureOnGeneralPurposeRegister(x1); err != nil {
+		return err
+	}
+
+	var arr arm64.VectorArrangement
+	if o.Type <= wazeroir.V128CmpTypeI8x16GeU {
+		arr = arm64.VectorArrangement16B
+	} else if o.Type <= wazeroir.V128CmpTypeI16x8GeU {
+		arr = arm64.VectorArrangement8H
+	} else if o.Type <= wazeroir.V128CmpTypeI32x4GeU {
+		arr = arm64.VectorArrangement4S
+	} else if o.Type <= wazeroir.V128CmpTypeI64x2GeS {
+		arr = arm64.VectorArrangement2D
+	} else if o.Type <= wazeroir.V128CmpTypeF32x4Ge {
+		arr = arm64.VectorArrangement4S
+	} else { // f64x2
+		arr = arm64.VectorArrangement2D
+	}
+
+	var result = x1.register
+	switch o.Type {
+	case wazeroir.V128CmpTypeI8x16Eq, wazeroir.V128CmpTypeI16x8Eq, wazeroir.V128CmpTypeI32x4Eq, wazeroir.V128CmpTypeI64x2Eq:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMEQ, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16Ne, wazeroir.V128CmpTypeI16x8Ne, wazeroir.V128CmpTypeI32x4Ne, wazeroir.V128CmpTypeI64x2Ne:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMEQ, x1.register, x2.register, result, arr)
+		// Reverse the condition by flipping all bits.
+		c.assembler.CompileVectorRegisterToVectorRegister(arm64.NOT, result, result,
+			arm64.VectorArrangement16B, arm64.VectorIndexNone, arm64.VectorIndexNone)
+	case wazeroir.V128CmpTypeI8x16LtS, wazeroir.V128CmpTypeI16x8LtS, wazeroir.V128CmpTypeI32x4LtS, wazeroir.V128CmpTypeI64x2LtS:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMGT, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16LtU, wazeroir.V128CmpTypeI16x8LtU, wazeroir.V128CmpTypeI32x4LtU:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMHI, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16GtS, wazeroir.V128CmpTypeI16x8GtS, wazeroir.V128CmpTypeI32x4GtS, wazeroir.V128CmpTypeI64x2GtS:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMGT, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16GtU, wazeroir.V128CmpTypeI16x8GtU, wazeroir.V128CmpTypeI32x4GtU:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMHI, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16LeS, wazeroir.V128CmpTypeI16x8LeS, wazeroir.V128CmpTypeI32x4LeS, wazeroir.V128CmpTypeI64x2LeS:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMGE, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16LeU, wazeroir.V128CmpTypeI16x8LeU, wazeroir.V128CmpTypeI32x4LeU:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMHS, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16GeS, wazeroir.V128CmpTypeI16x8GeS, wazeroir.V128CmpTypeI32x4GeS, wazeroir.V128CmpTypeI64x2GeS:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMGE, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeI8x16GeU, wazeroir.V128CmpTypeI16x8GeU, wazeroir.V128CmpTypeI32x4GeU:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.CMHS, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeF32x4Eq, wazeroir.V128CmpTypeF64x2Eq:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMEQ, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeF32x4Ne, wazeroir.V128CmpTypeF64x2Ne:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMEQ, x2.register, x1.register, result, arr)
+		// Reverse the condition by flipping all bits.
+		c.assembler.CompileVectorRegisterToVectorRegister(arm64.NOT, result, result,
+			arm64.VectorArrangement16B, arm64.VectorIndexNone, arm64.VectorIndexNone)
+	case wazeroir.V128CmpTypeF32x4Lt, wazeroir.V128CmpTypeF64x2Lt:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMGT, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeF32x4Le, wazeroir.V128CmpTypeF64x2Le:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMGE, x1.register, x2.register, result, arr)
+	case wazeroir.V128CmpTypeF32x4Gt, wazeroir.V128CmpTypeF64x2Gt:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMGT, x2.register, x1.register, result, arr)
+	case wazeroir.V128CmpTypeF32x4Ge, wazeroir.V128CmpTypeF64x2Ge:
+		c.assembler.CompileTwoVectorRegistersToVectorRegister(arm64.FCMGE, x2.register, x1.register, result, arr)
+	}
+
+	c.markRegisterUnused(x2.register)
+	c.pushVectorRuntimeValueLocationOnRegister(result)
+	return nil
 }
 
 // compileV128AddSat implements compiler.compileV128AddSat for arm64.


Test patch:
diff --git a/internal/asm/arm64/impl_test.go b/internal/asm/arm64/impl_test.go
index 3d36195e..690e2319 100644
--- a/internal/asm/arm64/impl_test.go
+++ b/internal/asm/arm64/impl_test.go
@@ -1741,6 +1741,182 @@ func TestAssemblerImpl_encodeTwoVectorRegistersToVectorRegister(t *testing.T) {
 			},
 			exp: []byte{0xe0, 0x39, 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
 		},
+		{
+			name: "cmeq v0.8b, v15.8b, v1.8b",
+			n: &NodeImpl{
+				Instruction:       CMEQ,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement8B,
+			},
+			exp: []byte{0xe0, 0x8d, 0x21, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmgt v0.16b, v15.16b, v1.16b",
+			n: &NodeImpl{
+				Instruction:       CMGT,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement16B,
+			},
+			exp: []byte{0xe0, 0x35, 0x21, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmhi v0.8h, v15.8h, v1.8h",
+			n: &NodeImpl{
+				Instruction:       CMHI,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement8H,
+			},
+			exp: []byte{0xe0, 0x35, 0x61, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmhi v0.4h, v15.4h, v1.4h",
+			n: &NodeImpl{
+				Instruction:       CMHI,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement4H,
+			},
+			exp: []byte{0xe0, 0x35, 0x61, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmge v0.4s, v15.4s, v1.4s",
+			n: &NodeImpl{
+				Instruction:       CMGE,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement4S,
+			},
+			exp: []byte{0xe0, 0x3d, 0xa1, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmge v0.2s, v15.2s, v1.2s",
+			n: &NodeImpl{
+				Instruction:       CMGE,
+				DstReg:            RegV0,
+				SrcReg:            RegV1,
+				SrcReg2:           RegV15,
+				VectorArrangement: VectorArrangement2S,
+			},
+			exp: []byte{0xe0, 0x3d, 0xa1, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "cmhs v30.2d, v4.2d, v11.2d",
+			n: &NodeImpl{
+				Instruction:       CMHS,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2D,
+			},
+			exp: []byte{0x9e, 0x3c, 0xeb, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmeq v30.2d, v4.2d, v11.2d",
+			n: &NodeImpl{
+				Instruction:       FCMEQ,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2D,
+			},
+			exp: []byte{0x9e, 0xe4, 0x6b, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmeq v30.4s, v4.4s, v11.4s",
+			n: &NodeImpl{
+				Instruction:       FCMEQ,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement4S,
+			},
+			exp: []byte{0x9e, 0xe4, 0x2b, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmeq v30.2s, v4.2s, v11.2s",
+			n: &NodeImpl{
+				Instruction:       FCMEQ,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2S,
+			},
+			exp: []byte{0x9e, 0xe4, 0x2b, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmgt v30.2d, v4.2d, v11.2d",
+			n: &NodeImpl{
+				Instruction:       FCMGT,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2D,
+			},
+			exp: []byte{0x9e, 0xe4, 0xeb, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmgt v30.4s, v4.4s, v11.4s",
+			n: &NodeImpl{
+				Instruction:       FCMGT,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement4S,
+			},
+			exp: []byte{0x9e, 0xe4, 0xab, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmgt v30.2s, v4.2s, v11.2s",
+			n: &NodeImpl{
+				Instruction:       FCMGT,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2S,
+			},
+			exp: []byte{0x9e, 0xe4, 0xab, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmge v30.2d, v4.2d, v11.2d",
+			n: &NodeImpl{
+				Instruction:       FCMGE,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2D,
+			},
+			exp: []byte{0x9e, 0xe4, 0x6b, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmge v30.4s, v4.4s, v11.4s",
+			n: &NodeImpl{
+				Instruction:       FCMGE,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement4S,
+			},
+			exp: []byte{0x9e, 0xe4, 0x2b, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
+		{
+			name: "fcmge v30.2s, v4.2s, v11.2s",
+			n: &NodeImpl{
+				Instruction:       FCMGE,
+				DstReg:            RegV30,
+				SrcReg:            RegV11,
+				SrcReg2:           RegV4,
+				VectorArrangement: VectorArrangement2S,
+			},
+			exp: []byte{0x9e, 0xe4, 0x2b, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/internal/engine/compiler/compiler_vec_test.go b/internal/engine/compiler/compiler_vec_test.go
index 6df5be5f..2aaa90ad 100644
--- a/internal/engine/compiler/compiler_vec_test.go
+++ b/internal/engine/compiler/compiler_vec_test.go
@@ -2994,11 +2994,6 @@ func f64x2(f1, f2 float64) (ret [16]byte) {
 }
 
 func TestCompiler_compileV128Cmp(t *testing.T) {
-	if runtime.GOARCH != "amd64" {
-		// TODO: implement on amd64.
-		t.Skip()
-	}
-
 	tests := []struct {
 		name        string
 		cmpType     wazeroir.V128CmpType
diff --git a/internal/integration_test/spectest/v2/spec_test.go b/internal/integration_test/spectest/v2/spec_test.go
index f928f4b0..68a8ae75 100644
--- a/internal/integration_test/spectest/v2/spec_test.go
+++ b/internal/integration_test/spectest/v2/spec_test.go
@@ -26,8 +26,7 @@ func TestCompiler(t *testing.T) {
 
 	spectest.Run(t, testcases, compiler.NewEngine, enabledFeatures, func(jsonname string) bool {
 		switch path.Base(jsonname) {
-		case "simd_i8x16_cmp.json", "simd_i16x8_cmp.json", "simd_i32x4_cmp.json", "simd_i64x2_cmp.json",
-			"simd_f32x4_cmp.json", "simd_f64x2_cmp.json", "simd_f32x4_arith.json", "simd_f64x2_arith.json",
+		case "simd_f32x4_arith.json", "simd_f64x2_arith.json",
 			"simd_i16x8_arith.json", "simd_i64x2_arith.json", "simd_i32x4_arith.json", "simd_i8x16_arith.json",
 			"simd_i16x8_sat_arith.json", "simd_i8x16_sat_arith.json",
 			"simd_i16x8_arith2.json", "simd_i8x16_arith2.json", "simd_i32x4_arith2.json", "simd_i64x2_arith2.json",