wazevo: passes simd f32/f64 cmp, rounding, pmax+pmin spec tests (#1735)

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
Co-authored-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
Edoardo Vacchi
2023-09-26 08:19:03 +09:00
committed by GitHub
co-authored by Takeshi Yoneda
parent 09da2e94b2
commit ed85669880
7 changed files with 549 additions and 5 deletions
@@ -1602,6 +1602,12 @@ func (b vecOp) String() string {
return "cmge"
case vecOpCmhs:
return "cmhs"
case vecOpFcmeq:
return "fcmeq"
case vecOpFcmgt:
return "fcmgt"
case vecOpFcmge:
return "fcmge"
case vecOpCmeq0:
return "cmeq0"
case vecOpUaddlv:
@@ -1658,6 +1664,14 @@ func (b vecOp) String() string {
return "neg"
case vecOpFneg:
return "fneg"
case vecOpFrintp:
return "frintp"
case vecOpFrintm:
return "frintm"
case vecOpFrintn:
return "frintn"
case vecOpFrintz:
return "frintz"
case vecOpFsqrt:
return "fsqrt"
case vecOpRev64:
@@ -1688,6 +1702,9 @@ const (
vecOpCmhi
vecOpCmge
vecOpCmhs
vecOpFcmeq
vecOpFcmgt
vecOpFcmge
vecOpUaddlv
vecOpBit
vecOpBic
@@ -1724,6 +1741,10 @@ const (
vecOpFabs
vecOpNeg
vecOpFneg
vecOpFrintm
vecOpFrintn
vecOpFrintp
vecOpFrintz
vecOpRev64
vecOpXtn
vecOpShll
@@ -414,6 +414,38 @@ func encodeVecRRR(op vecOp, rd, rn, rm uint32, arr vecArrangement) uint32 {
case vecOpCmhs:
size, q := arrToSizeQEncoded(arr)
return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b00111, size, 0b1, q)
case vecOpFcmeq:
var size, q uint32
switch arr {
case vecArrangement4S:
size, q = 0b00, 0b1
case vecArrangement2S:
size, q = 0b00, 0b0
case vecArrangement2D:
size, q = 0b01, 0b1
default:
panic("unsupported arrangement: " + arr.String())
}
return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b11100, size, 0b0, q)
case vecOpFcmgt:
if arr < vecArrangement2S || arr == vecArrangement1D {
panic("unsupported arrangement: " + arr.String())
}
size, q := arrToSizeQEncoded(arr)
return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b11100, size, 0b1, q)
case vecOpFcmge:
var size, q uint32
switch arr {
case vecArrangement4S:
size, q = 0b00, 0b1
case vecArrangement2S:
size, q = 0b00, 0b0
case vecArrangement2D:
size, q = 0b01, 0b1
default:
panic("unsupported arrangement: " + arr.String())
}
return encodeAdvancedSIMDThreeSame(rd, rn, rm, 0b11100, size, 0b1, q)
case vecOpAdd:
if arr == vecArrangement1D {
panic("unsupported arrangement: " + arr.String())
@@ -1730,6 +1762,46 @@ func encodeAdvancedSIMDTwoMisc(op vecOp, rd, rn uint32, arr vecArrangement) uint
opcode = 0b01111
u = 0b1
size, q = arrToSizeQEncoded(arr)
case vecOpFrintm:
u = 0b0
opcode = 0b11001
switch arr {
case vecArrangement2S:
q, size = 0b0, 0b00
case vecArrangement4S:
q, size = 0b1, 0b00
case vecArrangement2D:
q, size = 0b1, 0b01
default:
panic("unsupported arrangement: " + arr.String())
}
case vecOpFrintn:
u = 0b0
opcode = 0b11000
switch arr {
case vecArrangement2S:
q, size = 0b0, 0b00
case vecArrangement4S:
q, size = 0b1, 0b00
case vecArrangement2D:
q, size = 0b1, 0b01
default:
panic("unsupported arrangement: " + arr.String())
}
case vecOpFrintp:
u = 0b0
opcode = 0b11000
if arr < vecArrangement2S || arr == vecArrangement1D {
panic("unsupported arrangement: " + arr.String())
}
size, q = arrToSizeQEncoded(arr)
case vecOpFrintz:
u = 0b0
opcode = 0b11001
if arr < vecArrangement2S || arr == vecArrangement1D {
panic("unsupported arrangement: " + arr.String())
}
size, q = arrToSizeQEncoded(arr)
case vecOpFsqrt:
if arr < vecArrangement2S || arr == vecArrangement1D {
panic("unsupported arrangement: " + arr.String())
@@ -604,6 +604,69 @@ func TestInstruction_encode(t *testing.T) {
{want: "41fc636e", setup: func(i *instruction) {
i.asVecRRR(vecOpFdiv, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2D)
}},
{want: "41e4230e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmeq, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2S)
}},
{want: "41e4234e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmeq, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement4S)
}},
{want: "41e4634e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmeq, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2D)
}},
{want: "41e4a32e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmgt, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2S)
}},
{want: "41e4a36e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmgt, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement4S)
}},
{want: "41e4e36e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmgt, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2D)
}},
{want: "41e4232e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmge, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2S)
}},
{want: "41e4236e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmge, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement4S)
}},
{want: "41e4636e", setup: func(i *instruction) {
i.asVecRRR(vecOpFcmge, operandNR(v1VReg), operandNR(v2VReg), operandNR(v3VReg), vecArrangement2D)
}},
{want: "4198210e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintm, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2S)
}},
{want: "4198214e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintm, operandNR(v1VReg), operandNR(v2VReg), vecArrangement4S)
}},
{want: "4198614e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintm, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2D)
}},
{want: "4188210e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintn, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2S)
}},
{want: "4188214e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintn, operandNR(v1VReg), operandNR(v2VReg), vecArrangement4S)
}},
{want: "4188614e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintn, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2D)
}},
{want: "4188a10e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintp, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2S)
}},
{want: "4188a14e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintp, operandNR(v1VReg), operandNR(v2VReg), vecArrangement4S)
}},
{want: "4188e14e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintp, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2D)
}},
{want: "4198a10e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintz, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2S)
}},
{want: "4198a14e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintz, operandNR(v1VReg), operandNR(v2VReg), vecArrangement4S)
}},
{want: "4198e14e", setup: func(i *instruction) {
i.asVecMisc(vecOpFrintz, operandNR(v1VReg), operandNR(v2VReg), vecArrangement2D)
}},
{want: "41b8200e", setup: func(i *instruction) {
i.asVecMisc(vecOpAbs, operandNR(v1VReg), operandNR(v2VReg), vecArrangement8B)
}},
@@ -161,6 +161,20 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) {
m.lowerIcmp(instr)
case ssa.OpcodeVIcmp:
m.lowerVIcmp(instr)
case ssa.OpcodeVFcmp:
m.lowerVFcmp(instr)
case ssa.OpcodeVCeil:
m.lowerVecMisc(vecOpFrintp, instr)
case ssa.OpcodeVFloor:
m.lowerVecMisc(vecOpFrintm, instr)
case ssa.OpcodeVTrunc:
m.lowerVecMisc(vecOpFrintz, instr)
case ssa.OpcodeVNearest:
m.lowerVecMisc(vecOpFrintn, instr)
case ssa.OpcodeVMaxPseudo:
m.lowerVMinMaxPseudo(instr, true)
case ssa.OpcodeVMinPseudo:
m.lowerVMinMaxPseudo(instr, false)
case ssa.OpcodeBand:
m.lowerBitwiseAluOp(instr, aluOpAnd)
case ssa.OpcodeBor:
@@ -763,6 +777,28 @@ func (m *machine) lowerVIMul(rd, rn, rm operand, arr vecArrangement) {
}
}
func (m *machine) lowerVMinMaxPseudo(instr *ssa.Instruction, max bool) {
x, y, lane := instr.Arg2WithLane()
arr := ssaLaneToArrangement(lane)
rn := m.getOperand_NR(m.compiler.ValueDefinition(x), extModeNone)
rm := m.getOperand_NR(m.compiler.ValueDefinition(y), extModeNone)
rd := operandNR(m.compiler.VRegOf(instr.Return()))
fcmgt := m.allocateInstr()
if max {
fcmgt.asVecRRR(vecOpFcmgt, rd, rm, rn, arr)
} else {
// if min, swap the args
fcmgt.asVecRRR(vecOpFcmgt, rd, rn, rm, arr)
}
m.insert(fcmgt)
bsl := m.allocateInstr()
bsl.asVecRRR(vecOpBsl, rd, rm, rn, vecArrangement16B)
m.insert(bsl)
}
func (m *machine) lowerIRem(execCtxVReg regalloc.VReg, rd, rn, rm operand, _64bit, signed bool) {
div := m.allocateInstr()
@@ -1109,6 +1145,50 @@ func (m *machine) lowerVIcmp(si *ssa.Instruction) {
m.insert(cset)
}
func (m *machine) lowerVFcmp(si *ssa.Instruction) {
x, y, c, lane := si.VFcmpData()
flag := condFlagFromSSAFloatCmpCond(c)
arr := ssaLaneToArrangement(lane)
rn := m.getOperand_NR(m.compiler.ValueDefinition(x), extModeNone)
rm := m.getOperand_NR(m.compiler.ValueDefinition(y), extModeNone)
rd := operandNR(m.compiler.VRegOf(si.Return()))
switch flag {
case eq:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmeq, rd, rn, rm, arr)
m.insert(cmp)
case ne:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmeq, rd, rn, rm, arr)
m.insert(cmp)
not := m.allocateInstr()
not.asVecMisc(vecOpNot, rd, rn, vecArrangement16B)
m.insert(not)
case ge:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmge, rd, rn, rm, arr)
m.insert(cmp)
case gt:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmgt, rd, rn, rm, arr)
m.insert(cmp)
case mi:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmgt, rd, rm, rn, arr) // rm, rn are swapped
m.insert(cmp)
case ls:
cmp := m.allocateInstr()
cmp.asVecRRR(vecOpFcmge, rd, rm, rn, arr) // rm, rn are swapped
m.insert(cmp)
}
cset := m.allocateInstr()
cset.asCSet(rd.reg(), flag)
m.insert(cset)
}
func (m *machine) lowerShifts(si *ssa.Instruction, ext extMode, aluOp aluOp) {
x, amount := si.Arg2()
rn := m.getOperand_NR(m.compiler.ValueDefinition(x), ext)
+6
View File
@@ -162,6 +162,12 @@ func TestSpectestV2(t *testing.T) {
{"simd_f64x2"},
{"simd_f32x4_arith"},
{"simd_f64x2_arith"},
{"simd_f32x4_cmp"},
{"simd_f64x2_cmp"},
{"simd_f32x4_rounding"},
{"simd_f64x2_rounding"},
{"simd_f32x4_pmin_pmax"},
{"simd_f64x2_pmin_pmax"},
} {
t.Run(tc.name, func(t *testing.T) {
t.Run("normal", func(t *testing.T) {
+182 -1
View File
@@ -2032,7 +2032,188 @@ func (c *Compiler) lowerCurrentOpcode() {
v1 := state.pop()
ret := builder.AllocateInstruction().AsVFdiv(v1, v2, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Eq, wasm.OpcodeVecF64x2Eq:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Eq:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Eq:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondEqual, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Ne, wasm.OpcodeVecF64x2Ne:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Ne:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Ne:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondNotEqual, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Lt, wasm.OpcodeVecF64x2Lt:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Lt:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Lt:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondLessThan, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Le, wasm.OpcodeVecF64x2Le:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Le:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Le:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondLessThanOrEqual, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Gt, wasm.OpcodeVecF64x2Gt:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Gt:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Gt:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondGreaterThan, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Ge, wasm.OpcodeVecF64x2Ge:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Ge:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Ge:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().
AsVFcmp(v1, v2, ssa.FloatCmpCondGreaterThanOrEqual, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Ceil, wasm.OpcodeVecF64x2Ceil:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Ceil:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Ceil:
lane = ssa.VecLaneF64x2
}
v1 := state.pop()
ret := builder.AllocateInstruction().AsVCeil(v1, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Floor, wasm.OpcodeVecF64x2Floor:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Floor:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Floor:
lane = ssa.VecLaneF64x2
}
v1 := state.pop()
ret := builder.AllocateInstruction().AsVFloor(v1, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Trunc, wasm.OpcodeVecF64x2Trunc:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Trunc:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Trunc:
lane = ssa.VecLaneF64x2
}
v1 := state.pop()
ret := builder.AllocateInstruction().AsVTrunc(v1, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Nearest, wasm.OpcodeVecF64x2Nearest:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Nearest:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Nearest:
lane = ssa.VecLaneF64x2
}
v1 := state.pop()
ret := builder.AllocateInstruction().AsVNearest(v1, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Pmin, wasm.OpcodeVecF64x2Pmin:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Pmin:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Pmin:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().AsVMinPseudo(v1, v2, lane).Insert(builder).Return()
state.push(ret)
case wasm.OpcodeVecF32x4Pmax, wasm.OpcodeVecF64x2Pmax:
if state.unreachable {
break
}
var lane ssa.VecLane
switch vecOp {
case wasm.OpcodeVecF32x4Pmax:
lane = ssa.VecLaneF32x4
case wasm.OpcodeVecF64x2Pmax:
lane = ssa.VecLaneF64x2
}
v2 := state.pop()
v1 := state.pop()
ret := builder.AllocateInstruction().AsVMaxPseudo(v1, v2, lane).Insert(builder).Return()
state.push(ret)
default:
panic("TODO: unsupported vector instruction: " + wasm.VectorInstructionName(vecOp))
}
+125 -4
View File
@@ -449,7 +449,28 @@ const (
// OpcodeVFdiv performs a floating point division: `v = VFdiv.lane x, y` on vector.
OpcodeVFdiv
// OpcodeVSqrt takes the minimum of two floating point values: `v = VFmin.lane x, y on vector.
// OpcodeVFcmp compares two float values with the given condition: `v = VFcmp.lane Cond, x, y` on float.
OpcodeVFcmp
// OpcodeVCeil takes the ceiling of the given floating point value: `v = ceil.lane x` on vector.
OpcodeVCeil
// OpcodeVFloor takes the floor of the given floating point value: `v = floor.lane x` on vector.
OpcodeVFloor
// OpcodeVTrunc takes the truncation of the given floating point value: `v = trunc.lane x` on vector.
OpcodeVTrunc
// OpcodeVNearest takes the nearest integer of the given floating point value: `v = nearest.lane x` on vector.
OpcodeVNearest
// OpcodeVMaxPseudo computes the lane-wise maximum value `v = VMaxPseudo.lane x, y` on vector defined as `x < y ? x : y`.
OpcodeVMaxPseudo
// OpcodeVMinPseudo computes the lane-wise minimum value `v = VMinPseudo.lane x, y` on vector defined as `y < x ? x : y`.
OpcodeVMinPseudo
// OpcodeVSqrt takes the minimum of two floating point values: `v = VFmin.lane x, y` on vector.
OpcodeVSqrt
// OpcodeImul performs an integer multiplication: `v = Imul x, y`.
@@ -955,6 +976,13 @@ var instructionSideEffects = [opcodeEnd]sideEffect{
OpcodeVFsub: sideEffectNone,
OpcodeVFmul: sideEffectNone,
OpcodeVFdiv: sideEffectNone,
OpcodeVFcmp: sideEffectNone,
OpcodeVCeil: sideEffectNone,
OpcodeVFloor: sideEffectNone,
OpcodeVTrunc: sideEffectNone,
OpcodeVNearest: sideEffectNone,
OpcodeVMaxPseudo: sideEffectNone,
OpcodeVMinPseudo: sideEffectNone,
}
// sideEffect returns true if this instruction has side effects.
@@ -1104,6 +1132,13 @@ var instructionReturnTypes = [opcodeEnd]returnTypesFn{
OpcodeVFsub: returnTypesFnV128,
OpcodeVFmul: returnTypesFnV128,
OpcodeVFdiv: returnTypesFnV128,
OpcodeVFcmp: returnTypesFnI32,
OpcodeVCeil: returnTypesFnV128,
OpcodeVFloor: returnTypesFnV128,
OpcodeVTrunc: returnTypesFnV128,
OpcodeVNearest: returnTypesFnV128,
OpcodeVMaxPseudo: returnTypesFnV128,
OpcodeVMinPseudo: returnTypesFnV128,
}
// AsLoad initializes this instruction as a store instruction with OpcodeLoad.
@@ -1482,6 +1517,73 @@ func (i *Instruction) AsVIcmp(x, y Value, c IntegerCmpCond, lane VecLane) *Instr
return i
}
// AsVFcmp initializes this instruction as a float comparison instruction with OpcodeVFcmp on Vector.
func (i *Instruction) AsVFcmp(x, y Value, c FloatCmpCond, lane VecLane) *Instruction {
i.opcode = OpcodeVFcmp
i.v = x
i.v2 = y
i.u1 = uint64(c)
i.typ = TypeI32
i.u2 = uint64(lane)
return i
}
// AsVCeil initializes this instruction as an instruction with OpcodeCeil.
func (i *Instruction) AsVCeil(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVCeil
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVFloor initializes this instruction as an instruction with OpcodeFloor.
func (i *Instruction) AsVFloor(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFloor
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVTrunc initializes this instruction as an instruction with OpcodeTrunc.
func (i *Instruction) AsVTrunc(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVTrunc
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVNearest initializes this instruction as an instruction with OpcodeNearest.
func (i *Instruction) AsVNearest(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVNearest
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVMaxPseudo initializes this instruction as an instruction with OpcodeVMaxPseudo.
func (i *Instruction) AsVMaxPseudo(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVMaxPseudo
i.typ = x.Type()
i.v = x
i.v2 = y
i.u1 = uint64(lane)
return i
}
// AsVMinPseudo initializes this instruction as an instruction with OpcodeVMinPseudo.
func (i *Instruction) AsVMinPseudo(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVMinPseudo
i.typ = x.Type()
i.v = x
i.v2 = y
i.u1 = uint64(lane)
return i
}
// AsSDiv initializes this instruction as an integer bitwise and instruction with OpcodeSdiv.
func (i *Instruction) AsSDiv(x, y, ctx Value) *Instruction {
i.opcode = OpcodeSdiv
@@ -1603,6 +1705,11 @@ func (i *Instruction) VIcmpData() (x, y Value, c IntegerCmpCond, l VecLane) {
return i.v, i.v2, IntegerCmpCond(i.u1), VecLane(i.u2)
}
// VFcmpData returns the operands and comparison condition of this float comparison instruction on vector.
func (i *Instruction) VFcmpData() (x, y Value, c FloatCmpCond, l VecLane) {
return i.v, i.v2, FloatCmpCond(i.u1), VecLane(i.u2)
}
// AsFadd initializes this instruction as a floating-point addition instruction with OpcodeFadd.
func (i *Instruction) AsFadd(x, y Value) {
i.opcode = OpcodeFadd
@@ -2233,7 +2340,7 @@ func (i *Instruction) Format(b Builder) string {
instSuffix += "]"
case OpcodeBand, OpcodeBor, OpcodeBxor, OpcodeRotr, OpcodeRotl, OpcodeIshl, OpcodeSshr, OpcodeUshr,
OpcodeSdiv, OpcodeUdiv, OpcodeFcopysign, OpcodeSrem, OpcodeUrem,
OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp:
OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp, OpcodeVFcmp:
instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
case OpcodeUndefined:
case OpcodeClz, OpcodeCtz, OpcodePopcnt, OpcodeFneg, OpcodeFcvtToSint, OpcodeFcvtToUint, OpcodeFcvtFromSint,
@@ -2243,10 +2350,10 @@ func (i *Instruction) Format(b Builder) string {
case OpcodeVIadd, OpcodeVSaddSat, OpcodeVUaddSat, OpcodeVIsub, OpcodeVSsubSat, OpcodeVUsubSat,
OpcodeVImin, OpcodeVUmin, OpcodeVImax, OpcodeVUmax, OpcodeVImul, OpcodeVAvgRound,
OpcodeVFadd, OpcodeVFsub, OpcodeVFmul, OpcodeVFdiv,
OpcodeVFmin, OpcodeVFmax:
OpcodeVFmin, OpcodeVFmax, OpcodeVMinPseudo, OpcodeVMaxPseudo:
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:
OpcodeVFabs, OpcodeVFneg, OpcodeVSqrt, OpcodeVCeil, OpcodeVFloor, OpcodeVTrunc, OpcodeVNearest:
instSuffix = fmt.Sprintf(".%s %s", VecLane(i.u1), i.v.Format(b))
default:
panic(fmt.Sprintf("TODO: format for %s", i.opcode))
@@ -2678,6 +2785,20 @@ func (o Opcode) String() (ret string) {
return "VFmul"
case OpcodeVFdiv:
return "VFdiv"
case OpcodeVFcmp:
return "VFcmp"
case OpcodeVCeil:
return "VCeil"
case OpcodeVFloor:
return "VFloor"
case OpcodeVTrunc:
return "VTrunc"
case OpcodeVNearest:
return "VNearest"
case OpcodeVMaxPseudo:
return "VMaxPseudo"
case OpcodeVMinPseudo:
return "VMinPseudo"
case OpcodeVSqrt:
return "VSqrt"