Repository: tetratelabs/wazero
Pull request #1772 (2023-10-11 15:03:48)

wazevo: passes simd_i16x8_q15mulr_sat_s spec test
#1496 

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>



Patch:
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr.go b/internal/engine/wazevo/backend/isa/arm64/instr.go
index c3d3f82d..c4624da7 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr.go
@@ -1769,6 +1769,8 @@ func (b vecOp) String() string {
 		return "urhadd"
 	case vecOpFmul:
 		return "fmul"
+	case vecOpSqrdmulh:
+		return "sqrdmulh"
 	case vecOpMul:
 		return "mul"
 	case vecOpUmlal:
@@ -1875,6 +1877,7 @@ const (
 	vecOpUrhadd
 	vecOpMul
 	vecOpFmul
+	vecOpSqrdmulh
 	vecOpUmlal
 	vecOpFdiv
 	vecOpFsqrt
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go b/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
index aa26e371..13fe4459 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
@@ -585,6 +585,12 @@ func encodeVecRRR(op vecOp, rd, rn, rm uint32, arr vecArrangement) uint32 {
 			panic("unsupported arrangement: " + arr.String())
 		}
 		return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b11011, size, 0b1, q)
+	case vecOpSqrdmulh:
+		if arr < vecArrangement4H || arr > vecArrangement4S {
+			panic("unsupported arrangement: " + arr.String())
+		}
+		size, q := arrToSizeQEncoded(arr)
+		return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b10110, size, 0b1, q)
 	case vecOpFdiv:
 		var size, q uint32
 		switch arr {
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
index 0ca69702..22609516 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
@@ -477,6 +477,10 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) {
 		x, y, lane := instr.Arg2WithLane()
 		arr := ssaLaneToArrangement(lane)
 		m.lowerVecRRR(vecOpFmul, x, y, instr.Return(), arr)
+	case ssa.OpcodeSqmulRoundSat:
+		x, y, lane := instr.Arg2WithLane()
+		arr := ssaLaneToArrangement(lane)
+		m.lowerVecRRR(vecOpSqrdmulh, x, y, instr.Return(), arr)
 	case ssa.OpcodeVFdiv:
 		x, y, lane := instr.Arg2WithLane()
 		arr := ssaLaneToArrangement(lane)
diff --git a/internal/engine/wazevo/frontend/lower.go b/internal/engine/wazevo/frontend/lower.go
index 48b83c26..a561ff61 100644
--- a/internal/engine/wazevo/frontend/lower.go
+++ b/internal/engine/wazevo/frontend/lower.go
@@ -2208,6 +2208,14 @@ func (c *Compiler) lowerCurrentOpcode() {
 			v1 := state.pop()
 			ret := builder.AllocateInstruction().AsVImul(v1, v2, lane).Insert(builder).Return()
 			state.push(ret)
+		case wasm.OpcodeVecI16x8Q15mulrSatS:
+			if state.unreachable {
+				break
+			}
+			v2 := state.pop()
+			v1 := state.pop()
+			ret := builder.AllocateInstruction().AsSqmulRoundSat(v1, v2, ssa.VecLaneI16x8).Insert(builder).Return()
+			state.push(ret)
 		case wasm.OpcodeVecI8x16Eq, wasm.OpcodeVecI16x8Eq, wasm.OpcodeVecI32x4Eq, wasm.OpcodeVecI64x2Eq:
 			if state.unreachable {
 				break
diff --git a/internal/engine/wazevo/ssa/instructions.go b/internal/engine/wazevo/ssa/instructions.go
index c81706fc..f7f97ce6 100644
--- a/internal/engine/wazevo/ssa/instructions.go
+++ b/internal/engine/wazevo/ssa/instructions.go
@@ -493,6 +493,10 @@ const (
 	// OpcodeFmul performs a floating point multiplication: `v = Fmul x, y`.
 	OpcodeFmul
 
+	// OpcodeSqmulRoundSat performs a lane-wise saturating rounding multiplication
+	// in Q15 format: `v = SqmulRoundSat.lane x,y` on vector.
+	OpcodeSqmulRoundSat
+
 	// OpcodeFdiv performs a floating point division: `v = Fdiv x, y`.
 	OpcodeFdiv
 
@@ -724,6 +728,7 @@ var instructionSideEffects = [opcodeEnd]sideEffect{
 	OpcodeFdiv:               sideEffectNone,
 	OpcodeFmul:               sideEffectNone,
 	OpcodeFmax:               sideEffectNone,
+	OpcodeSqmulRoundSat:      sideEffectNone,
 	OpcodeSelect:             sideEffectNone,
 	OpcodeFmin:               sideEffectNone,
 	OpcodeFneg:               sideEffectNone,
@@ -927,6 +932,7 @@ var instructionReturnTypes = [opcodeEnd]returnTypesFn{
 	OpcodeFmul:               returnTypesFnSingle,
 	OpcodeFmax:               returnTypesFnSingle,
 	OpcodeFmin:               returnTypesFnSingle,
+	OpcodeSqmulRoundSat:      returnTypesFnV128,
 	OpcodeF32const:           returnTypesFnF32,
 	OpcodeF64const:           returnTypesFnF64,
 	OpcodeClz:                returnTypesFnSingle,
@@ -1213,7 +1219,7 @@ func (i *Instruction) AsVAvgRound(x, y Value, lane VecLane) *Instruction {
 	return i
 }
 
-// AsVImul initializes this instruction as an integer subtraction multiplication with OpcodeVImul on a vector.
+// AsVImul initializes this instruction as an integer multiplication with OpcodeVImul on a vector.
 func (i *Instruction) AsVImul(x, y Value, lane VecLane) *Instruction {
 	i.opcode = OpcodeVImul
 	i.v = x
@@ -1223,6 +1229,17 @@ func (i *Instruction) AsVImul(x, y Value, lane VecLane) *Instruction {
 	return i
 }
 
+// AsSqmulRoundSat initializes this instruction as a lane-wise saturating rounding multiplication
+// in Q15 format with OpcodeSqmulRoundSat on a vector.
+func (i *Instruction) AsSqmulRoundSat(x, y Value, lane VecLane) *Instruction {
+	i.opcode = OpcodeSqmulRoundSat
+	i.v = x
+	i.v2 = y
+	i.u1 = uint64(lane)
+	i.typ = TypeV128
+	return i
+}
+
 // AsVIabs initializes this instruction as a vector absolute value with OpcodeVIabs.
 func (i *Instruction) AsVIabs(x Value, lane VecLane) *Instruction {
 	i.opcode = OpcodeVIabs
@@ -2420,7 +2437,7 @@ func (i *Instruction) Format(b Builder) string {
 		OpcodeVFadd, OpcodeVFsub, OpcodeVFmul, OpcodeVFdiv,
 		OpcodeVIshl, OpcodeVSshr, OpcodeVUshr,
 		OpcodeVFmin, OpcodeVFmax, OpcodeVMinPseudo, OpcodeVMaxPseudo,
-		OpcodeSnarrow, OpcodeUnarrow, OpcodeSwizzle:
+		OpcodeSnarrow, OpcodeUnarrow, OpcodeSwizzle, OpcodeSqmulRoundSat:
 		instSuffix = fmt.Sprintf(".%s %s, %s", VecLane(i.u1), i.v.Format(b), i.v2.Format(b))
 	case OpcodeVIabs, OpcodeVIneg, OpcodeVIpopcnt, OpcodeVhighBits, OpcodeVallTrue, OpcodeVanyTrue,
 		OpcodeVFabs, OpcodeVFneg, OpcodeVSqrt, OpcodeVCeil, OpcodeVFloor, OpcodeVTrunc, OpcodeVNearest,
@@ -2631,6 +2648,8 @@ func (o Opcode) String() (ret string) {
 		return "Fmul"
 	case OpcodeFdiv:
 		return "Fdiv"
+	case OpcodeSqmulRoundSat:
+		return "SqmulRoundSat"
 	case OpcodeSqrt:
 		return "Sqrt"
 	case OpcodeFneg:


Test patch:
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go b/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
index 26e18d38..d943906d 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
@@ -652,6 +652,18 @@ func TestInstruction_encode(t *testing.T) {
 		{want: "41dc636e", setup: func(i *instruction) {
 			i.asVecRRR(vecOpFmul, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2D)
 		}},
+		{want: "41b4636e", setup: func(i *instruction) {
+			i.asVecRRR(vecOpSqrdmulh, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement8H)
+		}},
+		{want: "41b4632e", setup: func(i *instruction) {
+			i.asVecRRR(vecOpSqrdmulh, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement4H)
+		}},
+		{want: "41b4a32e", setup: func(i *instruction) {
+			i.asVecRRR(vecOpSqrdmulh, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2S)
+		}},
+		{want: "41b4a36e", setup: func(i *instruction) {
+			i.asVecRRR(vecOpSqrdmulh, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement4S)
+		}},
 		{want: "41fc232e", setup: func(i *instruction) {
 			i.asVecRRR(vecOpFdiv, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2S)
 		}},
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index 6189233b..0a34db92 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -198,6 +198,7 @@ func TestSpectestV2(t *testing.T) {
 		{"simd_i32x4_extmul_i16x8"},
 		{"simd_i16x8_extadd_pairwise_i8x16"},
 		{"simd_i32x4_extadd_pairwise_i16x8"},
+		{"simd_i16x8_q15mulr_sat_s"},
 		{"simd_int_to_int_extend"},
 		{"simd_load"},
 		{"simd_load_extend"},