Repository: tetratelabs/wazero
Pull request #2036 (2024-02-10 07:07:01)

wazevo(amd64): simd f32x4, f64x4 spec tests

evacchi: same unrelated issue as #2004 

```
--- FAIL: TestFileCache_compiler (77.28s)
    --- FAIL: TestFileCache_compiler/spectest (75.24s)
        require.go:331: expected no error, but was exit status 2: unexpected fault address 0x2c879000
```

https://github.com/tetratelabs/wazero/actions/runs/7853356149/job/21432882550?pr=2036

Patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go b/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
index b306df63..eddd9c0a 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
@@ -1052,6 +1052,8 @@ func (i *instruction) encode(c backend.Compiler) (needsLabelResolution bool) {
 		var opcode uint32
 		var opcodeNum uint32
 		switch op {
+		case sseOpcodeCmpps:
+			legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0FC2, 2
 		case sseOpcodeCmppd:
 			legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FC2, 2
 		default:
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index 291dfa18..9e056d06 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -685,6 +685,12 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) {
 		m.lowerVIabs(instr)
 	case ssa.OpcodeVIpopcnt:
 		m.lowerVIpopcnt(instr)
+	case ssa.OpcodeVFmin:
+		m.lowerVFmin(instr)
+	case ssa.OpcodeVFmax:
+		m.lowerVFmax(instr)
+	case ssa.OpcodeVFabs:
+		m.lowerVFabs(instr)
 	case ssa.OpcodeUndefined:
 		m.insert(m.allocateInstr().asUD2())
 	case ssa.OpcodeExitWithCode:
@@ -2891,3 +2897,188 @@ func (m *machine) lowerVbitselect(instr *ssa.Instruction) {
 
 	m.copyTo(tmpX, rd)
 }
+
+func (m *machine) lowerVFmin(instr *ssa.Instruction) {
+	x, y, lane := instr.Arg2WithLane()
+	rn := m.getOperand_Reg(m.c.ValueDefinition(x))
+	rm := m.getOperand_Reg(m.c.ValueDefinition(y))
+	rd := m.c.VRegOf(instr.Return())
+
+	var min, cmp, andn, or, srl /* shift right logical */ sseOpcode
+	var shiftNumToInverseNaN uint32
+	if lane == ssa.VecLaneF32x4 {
+		min, cmp, andn, or, srl, shiftNumToInverseNaN = sseOpcodeMinps, sseOpcodeCmpps, sseOpcodeAndnps, sseOpcodeOrps, sseOpcodePsrld, 0xa
+	} else {
+		min, cmp, andn, or, srl, shiftNumToInverseNaN = sseOpcodeMinpd, sseOpcodeCmppd, sseOpcodeAndnpd, sseOpcodeOrpd, sseOpcodePsrlq, 0xd
+	}
+
+	tmp1 := m.copyToTmp(rn.reg())
+	tmp2 := m.copyToTmp(rm.reg())
+
+	// tmp1=min(rn, rm)
+	minIns1 := m.allocateInstr()
+	minIns1.asXmmRmR(min, rn, tmp2)
+	m.insert(minIns1)
+
+	// tmp2=min(rm, rn)
+	minIns2 := m.allocateInstr()
+	minIns2.asXmmRmR(min, rm, tmp1)
+	m.insert(minIns2)
+
+	// tmp3:=tmp1=min(rn, rm)
+	tmp3 := m.copyToTmp(tmp1)
+
+	// tmp1 = -0         if (rn == -0 || rm == -0) && rn != NaN && rm !=NaN
+	//       NaN         if rn == NaN || rm == NaN
+	//       min(rm, rm) otherwise
+	orIns := m.allocateInstr()
+	orIns.asXmmRmR(or, newOperandReg(tmp2), tmp1)
+	m.insert(orIns)
+
+	// tmp3 is originally min(rn,rm).
+	// tmp3 = 0^ (set all bits) if rn == NaN || rm == NaN
+	//        0 otherwise
+	cmpIns := m.allocateInstr()
+	cmpIns.asXmmRmRImm(cmp, uint8(cmpPredUNORD_Q), newOperandReg(tmp2), tmp3)
+	m.insert(cmpIns)
+
+	// tmp1 = -0          if (rn == -0 || rm == -0) && rn != NaN && rm !=NaN
+	//        ^0          if rn == NaN || rm == NaN
+	//        min(v1, v2) otherwise
+	orIns2 := m.allocateInstr()
+	orIns2.asXmmRmR(or, newOperandReg(tmp3), tmp1)
+	m.insert(orIns2)
+
+	// tmp3 = set all bits on the mantissa bits
+	//        0 otherwise
+	shift := m.allocateInstr()
+	shift.asXmmRmiReg(srl, newOperandImm32(shiftNumToInverseNaN), tmp3)
+	m.insert(shift)
+
+	// tmp3 = tmp1 and !tmp3
+	//     = -0                                                   if (rn == -0 || rm == -0) && rn != NaN && rm !=NaN
+	//       set all bits on exponential and sign bit (== NaN)    if rn == NaN || rm == NaN
+	//       min(rn, rm)                                          otherwise
+	andnIns := m.allocateInstr()
+	andnIns.asXmmRmR(andn, newOperandReg(tmp1), tmp3)
+	m.insert(andnIns)
+
+	m.copyTo(tmp3, rd)
+}
+
+func (m *machine) lowerVFmax(instr *ssa.Instruction) {
+	x, y, lane := instr.Arg2WithLane()
+	rn := m.getOperand_Reg(m.c.ValueDefinition(x))
+	rm := m.getOperand_Reg(m.c.ValueDefinition(y))
+	rd := m.c.VRegOf(instr.Return())
+
+	var max, cmp, andn, or, xor, sub, srl /* shift right logical */ sseOpcode
+	var shiftNumToInverseNaN uint32
+	if lane == ssa.VecLaneF32x4 {
+		max, cmp, andn, or, xor, sub, srl, shiftNumToInverseNaN = sseOpcodeMaxps, sseOpcodeCmpps, sseOpcodeAndnps, sseOpcodeOrps, sseOpcodeXorps, sseOpcodeSubps, sseOpcodePsrld, 0xa
+	} else {
+		max, cmp, andn, or, xor, sub, srl, shiftNumToInverseNaN = sseOpcodeMaxpd, sseOpcodeCmppd, sseOpcodeAndnpd, sseOpcodeOrpd, sseOpcodeXorpd, sseOpcodeSubpd, sseOpcodePsrlq, 0xd
+	}
+
+	tmp0 := m.copyToTmp(rm.reg())
+	tmp1 := m.copyToTmp(rn.reg())
+
+	// tmp0=max(rn, rm)
+	maxIns1 := m.allocateInstr()
+	maxIns1.asXmmRmR(max, rn, tmp0)
+	m.insert(maxIns1)
+
+	// tmp1=max(rm, rn)
+	maxIns2 := m.allocateInstr()
+	maxIns2.asXmmRmR(max, rm, tmp1)
+	m.insert(maxIns2)
+
+	// tmp2=max(rm, rn)
+	tmp2 := m.copyToTmp(tmp1)
+
+	// tmp2 = -0       if (rn == -0 && rm == 0) || (rn == 0 && rm == -0)
+	//         0       if (rn == 0 && rm ==  0)
+	//        -0       if (rn == -0 && rm == -0)
+	//       v1^v2     if rn == NaN || rm == NaN
+	//         0       otherwise
+	xorInstr := m.allocateInstr()
+	xorInstr.asXmmRmR(xor, newOperandReg(tmp0), tmp2)
+	m.insert(xorInstr)
+	// tmp1 = -0           if (rn == -0 && rm == 0) || (rn == 0 && rm == -0)
+	//         0           if (rn == 0 && rm ==  0)
+	//        -0           if (rn == -0 && rm == -0)
+	//        NaN          if rn == NaN || rm == NaN
+	//        max(v1, v2)  otherwise
+	orInstr := m.allocateInstr()
+	orInstr.asXmmRmR(or, newOperandReg(tmp2), tmp1)
+	m.insert(orInstr)
+
+	tmp3 := m.copyToTmp(tmp1)
+
+	// tmp3 = 0           if (rn == -0 && rm == 0) || (rn == 0 && rm == -0) || (rn == 0 && rm ==  0)
+	//       -0           if (rn == -0 && rm == -0)
+	//       NaN          if rn == NaN || rm == NaN
+	//       max(v1, v2)  otherwise
+	//
+	// Note: -0 - (-0) = 0 (!= -0) in floating point operation.
+	subIns := m.allocateInstr()
+	subIns.asXmmRmR(sub, newOperandReg(tmp2), tmp3)
+	m.insert(subIns)
+
+	// tmp1 = 0^ if rn == NaN || rm == NaN
+	cmpIns := m.allocateInstr()
+	cmpIns.asXmmRmRImm(cmp, uint8(cmpPredUNORD_Q), newOperandReg(tmp1), tmp1)
+	m.insert(cmpIns)
+
+	// tmp1 = set all bits on the mantissa bits
+	//        0 otherwise
+	shift := m.allocateInstr()
+	shift.asXmmRmiReg(srl, newOperandImm32(shiftNumToInverseNaN), tmp1)
+	m.insert(shift)
+
+	andnIns := m.allocateInstr()
+	andnIns.asXmmRmR(andn, newOperandReg(tmp3), tmp1)
+	m.insert(andnIns)
+
+	m.copyTo(tmp1, rd)
+}
+
+func (m *machine) lowerVFabs(instr *ssa.Instruction) {
+	x, lane := instr.ArgWithLane()
+	rm := m.getOperand_Mem_Reg(m.c.ValueDefinition(x))
+	rd := m.c.VRegOf(instr.Return())
+
+	tmp := m.c.AllocateVReg(ssa.TypeV128)
+
+	def := m.allocateInstr()
+	def.asDefineUninitializedReg(tmp)
+	m.insert(def)
+
+	// Set all bits on tmp.
+	pcmp := m.allocateInstr()
+	pcmp.asXmmRmR(sseOpcodePcmpeqd, newOperandReg(tmp), tmp)
+	m.insert(pcmp)
+
+	switch lane {
+	case ssa.VecLaneF32x4:
+		// Shift right packed single floats by 1 to clear the sign bits.
+		shift := m.allocateInstr()
+		shift.asXmmRmiReg(sseOpcodePsrld, newOperandImm32(1), tmp)
+		m.insert(shift)
+		// Clear the sign bit of rm.
+		andp := m.allocateInstr()
+		andp.asXmmRmR(sseOpcodeAndpd, rm, tmp)
+		m.insert(andp)
+	case ssa.VecLaneF64x2:
+		// Shift right packed single floats by 1 to clear the sign bits.
+		shift := m.allocateInstr()
+		shift.asXmmRmiReg(sseOpcodePsrlq, newOperandImm32(1), tmp)
+		m.insert(shift)
+		// Clear the sign bit of rm.
+		andp := m.allocateInstr()
+		andp.asXmmRmR(sseOpcodeAndps, rm, tmp)
+		m.insert(andp)
+	}
+
+	m.copyTo(tmp, rd)
+}


Test patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go b/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
index f905f101..26ced088 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
@@ -1943,6 +1943,454 @@ func TestInstruction_format_encode(t *testing.T) {
 			want:       "660fc2407b1f",
 			wantFormat: "cmppd $31, 123(%rax), %xmm0",
 		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c100",
+			wantFormat: "cmpps $0, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLT_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c101",
+			wantFormat: "cmpps $1, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLE_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c102",
+			wantFormat: "cmpps $2, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredUNORD_Q), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c103",
+			wantFormat: "cmpps $3, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c104",
+			wantFormat: "cmpps $4, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLT_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c105",
+			wantFormat: "cmpps $5, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLE_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c106",
+			wantFormat: "cmpps $6, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredORD_Q), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c107",
+			wantFormat: "cmpps $7, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c108",
+			wantFormat: "cmpps $8, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGE_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c109",
+			wantFormat: "cmpps $9, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGT_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10a",
+			wantFormat: "cmpps $10, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredFALSE_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10b",
+			wantFormat: "cmpps $11, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10c",
+			wantFormat: "cmpps $12, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGE_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10d",
+			wantFormat: "cmpps $13, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGT_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10e",
+			wantFormat: "cmpps $14, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredTRUE_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c10f",
+			wantFormat: "cmpps $15, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c110",
+			wantFormat: "cmpps $16, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLT_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c111",
+			wantFormat: "cmpps $17, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLE_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c112",
+			wantFormat: "cmpps $18, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredUNORD_S), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c113",
+			wantFormat: "cmpps $19, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c114",
+			wantFormat: "cmpps $20, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLT_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c115",
+			wantFormat: "cmpps $21, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLE_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c116",
+			wantFormat: "cmpps $22, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredORD_S), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c117",
+			wantFormat: "cmpps $23, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c118",
+			wantFormat: "cmpps $24, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGE_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c119",
+			wantFormat: "cmpps $25, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGT_UQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11a",
+			wantFormat: "cmpps $26, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredFALSE_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11b",
+			wantFormat: "cmpps $27, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_OS), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11c",
+			wantFormat: "cmpps $28, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGE_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11d",
+			wantFormat: "cmpps $29, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGT_OQ), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11e",
+			wantFormat: "cmpps $30, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredTRUE_US), newOperandReg(xmm1VReg), xmm0VReg)
+			},
+			want:       "0fc2c11f",
+			wantFormat: "cmpps $31, %xmm1, %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b00",
+			wantFormat: "cmpps $0, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLT_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b01",
+			wantFormat: "cmpps $1, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLE_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b02",
+			wantFormat: "cmpps $2, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredUNORD_Q), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b03",
+			wantFormat: "cmpps $3, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b04",
+			wantFormat: "cmpps $4, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLT_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b05",
+			wantFormat: "cmpps $5, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLE_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b06",
+			wantFormat: "cmpps $6, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredORD_Q), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b07",
+			wantFormat: "cmpps $7, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b08",
+			wantFormat: "cmpps $8, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGE_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b09",
+			wantFormat: "cmpps $9, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGT_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0a",
+			wantFormat: "cmpps $10, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredFALSE_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0b",
+			wantFormat: "cmpps $11, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0c",
+			wantFormat: "cmpps $12, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGE_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0d",
+			wantFormat: "cmpps $13, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGT_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0e",
+			wantFormat: "cmpps $14, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredTRUE_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b0f",
+			wantFormat: "cmpps $15, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b10",
+			wantFormat: "cmpps $16, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLT_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b11",
+			wantFormat: "cmpps $17, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredLE_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b12",
+			wantFormat: "cmpps $18, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredUNORD_S), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b13",
+			wantFormat: "cmpps $19, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b14",
+			wantFormat: "cmpps $20, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLT_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b15",
+			wantFormat: "cmpps $21, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNLE_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b16",
+			wantFormat: "cmpps $22, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredORD_S), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b17",
+			wantFormat: "cmpps $23, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredEQ_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b18",
+			wantFormat: "cmpps $24, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGE_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b19",
+			wantFormat: "cmpps $25, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNGT_UQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1a",
+			wantFormat: "cmpps $26, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredFALSE_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1b",
+			wantFormat: "cmpps $27, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredNEQ_OS), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1c",
+			wantFormat: "cmpps $28, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGE_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1d",
+			wantFormat: "cmpps $29, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredGT_OQ), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1e",
+			wantFormat: "cmpps $30, 123(%rax), %xmm0",
+		},
+		{
+			setup: func(i *instruction) {
+				i.asXmmRmRImm(sseOpcodeCmpps, uint8(cmpPredTRUE_US), newOperandMem(newAmodeImmReg(123, raxVReg)), xmm0VReg)
+			},
+			want:       "0fc2407b1f",
+			wantFormat: "cmpps $31, 123(%rax), %xmm0",
+		},
 		{
 			setup:      func(i *instruction) { i.asPop64(raxVReg) },
 			want:       "58",
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index ace9eec3..488e75dd 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -1464,8 +1464,8 @@ func TestSpectestV2(t *testing.T) {
 		//{"simd_i16x8_cmp"},
 		//{"simd_i32x4_cmp"},
 		//{"simd_i64x2_cmp"},
-		//{"simd_f32x4"},
-		//{"simd_f64x2"},
+		{"simd_f32x4"},
+		{"simd_f64x2"},
 		{"simd_f32x4_arith"},
 		{"simd_f64x2_arith"},
 		//{"simd_f32x4_cmp"},