mirror of
https://github.com/wazero/wazero
synced 2026-06-21 14:12:37 +00:00
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:
co-authored by
Takeshi Yoneda
parent
09da2e94b2
commit
ed85669880
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user