wazevo: fixes extended register operands for arm64, imported memory size type (#1694)

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
Takeshi Yoneda
2023-09-11 14:02:08 +09:00
committed by GitHub
parent 557f271238
commit d776d8c025
6 changed files with 226 additions and 22 deletions

View File

@@ -144,6 +144,16 @@ func (i *instruction) encode(c backend.Compiler) {
i.u3 == 1,
rn == sp,
))
case aluRRRExtend:
rm, exo, to := i.rm.er()
c.Emit4Bytes(encodeAluRRRExtend(
aluOp(i.u1),
regNumberInEncoding[i.rd.realReg()],
regNumberInEncoding[i.rn.realReg()],
regNumberInEncoding[rm.RealReg()],
exo,
to,
))
case aluRRRShift:
r, amt, sop := i.rm.sr()
c.Emit4Bytes(encodeAluRRRShift(
@@ -1062,6 +1072,48 @@ func encodeAluRRRShift(op aluOp, rd, rn, rm, amount uint32, shiftOp shiftOp, _64
return opc<<29 | n<<21 | _31to24<<24 | shift<<22 | rm<<16 | (amount << 10) | (rn << 5) | rd
}
// "Add/subtract (extended register)" in
// https://developer.arm.com/documentation/ddi0596/2020-12/Index-by-Encoding/Data-Processing----Register?lang=en#addsub_ext
func encodeAluRRRExtend(ao aluOp, rd, rn, rm uint32, extOp extendOp, to byte) uint32 {
var s, op uint32
switch ao {
case aluOpAdd:
op = 0b0
case aluOpAddS:
op, s = 0b0, 0b1
case aluOpSub:
op = 0b1
case aluOpSubS:
op, s = 0b1, 0b1
default:
panic("BUG: extended register operand can be used only for add/sub")
}
var sf uint32
if to == 64 {
sf = 0b1
}
var option uint32
switch extOp {
case extendOpUXTB:
option = 0b000
case extendOpUXTH:
option = 0b001
case extendOpUXTW:
option = 0b010
case extendOpSXTB:
option = 0b100
case extendOpSXTH:
option = 0b101
case extendOpSXTW:
option = 0b110
case extendOpSXTX, extendOpUXTX:
panic(fmt.Sprintf("%s is essentially noop, and should be handled much earlier than encoding", extOp.String()))
}
return sf<<31 | op<<30 | s<<29 | 0b1011001<<21 | rm<<16 | option<<13 | rn<<5 | rd
}
// encodeAluRRR encodes as Data Processing (register), depending on aluOp.
// https://developer.arm.com/documentation/ddi0596/2020-12/Index-by-Encoding/Data-Processing----Register?lang=en
func encodeAluRRR(op aluOp, rd, rn, rm uint32, _64bit, isRnSp bool) uint32 {

View File

@@ -302,6 +302,48 @@ func TestInstruction_encode(t *testing.T) {
{want: "f20300b2", setup: func(i *instruction) { i.asALUBitmaskImm(aluOpOrr, xzrVReg, x18VReg, 0x100000001, true) }},
{want: "f21fbf0e", setup: func(i *instruction) { i.asFpuMov64(v18VReg, v31VReg) }},
{want: "f21fbf4e", setup: func(i *instruction) { i.asFpuMov128(v18VReg, v31VReg) }},
{want: "40a034ab", setup: func(i *instruction) {
i.asALU(aluOpAddS, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTH, 64), false)
}},
{want: "4080348b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTB, 64), false)
}},
{want: "40a0348b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTH, 64), false)
}},
{want: "40c0348b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTW, 64), false)
}},
{want: "4080340b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTB, 32), false)
}},
{want: "40a0340b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTH, 32), false)
}},
{want: "40c0340b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpSXTW, 32), false)
}},
{want: "400034eb", setup: func(i *instruction) {
i.asALU(aluOpSubS, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTB, 64), false)
}},
{want: "400034cb", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTB, 64), false)
}},
{want: "402034cb", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTH, 64), false)
}},
{want: "404034cb", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTW, 64), false)
}},
{want: "4000344b", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTB, 32), false)
}},
{want: "4020344b", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTH, 32), false)
}},
{want: "4040344b", setup: func(i *instruction) {
i.asALU(aluOpSub, operandNR(x0VReg), operandNR(x2VReg), operandER(x20VReg, extendOpUXTW, 32), false)
}},
{want: "4000140b", setup: func(i *instruction) {
i.asALU(aluOpAdd, operandNR(x0VReg), operandNR(x2VReg), operandNR(x20VReg), false)
}},

View File

@@ -74,12 +74,15 @@ func (o operand) nr() regalloc.VReg {
// operandER encodes the given VReg as an operand of operandKindER.
func operandER(r regalloc.VReg, eop extendOp, to byte) operand {
if to < 32 {
panic("TODO?BUG?: when we need to extend to less than 32 bits?")
}
return operand{kind: operandKindER, data: uint64(r), data2: uint64(eop)<<32 | uint64(to)}
}
// er decodes the underlying VReg, extend operation, and the target size assuming the operand is of operandKindER.
func (o operand) er() (r regalloc.VReg, eop extendOp, to byte) {
return regalloc.VReg(o.data), extendOp(o.data2>>32) & 0xff, byte(o.data) & 0xff
return regalloc.VReg(o.data), extendOp(o.data2>>32) & 0xff, byte(o.data2 & 0xff)
}
// operandSR encodes the given VReg as an operand of operandKindSR.
@@ -215,15 +218,16 @@ func (m *machine) getOperand_ER_SR_NR(def *backend.SSAValueDefinition, mode extM
signed := extInstr.Opcode() == ssa.OpcodeSExtend
innerExtFromBits, innerExtToBits := extInstr.ExtendFromToBits()
if mode == extModeNone {
modeBits, modeSigned := mode.bits(), mode.signed()
if mode == extModeNone || innerExtToBits == modeBits {
eop := extendOpFrom(signed, innerExtFromBits)
op = operandER(m.compiler.VRegOf(extInstr.Arg()), eop, innerExtToBits)
extArg := m.getOperand_NR(m.compiler.ValueDefinition(extInstr.Arg()), extModeNone)
op = operandER(extArg.nr(), eop, innerExtToBits)
m.compiler.MarkLowered(extInstr) // We merged the instruction in the operand.
return
}
modeBits, modeSigned := mode.bits(), mode.signed()
if innerExtToBits >= modeBits {
if innerExtToBits > modeBits {
panic("BUG?TODO?: need the results of inner extension to be larger than the mode")
}

View File

@@ -232,6 +232,7 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
}
func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
const nextVReg = 100
type testCase struct {
setup func(*mockCompiler, ssa.Builder, *machine) (def *backend.SSAValueDefinition, mode extMode, verify func(t *testing.T))
exp operand
@@ -239,6 +240,7 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
}
runner := func(tc testCase) {
ctx, b, m := newSetupWithMockContext()
ctx.vRegCounter = nextVReg - 1
def, mode, verify := tc.setup(ctx, b, m)
actual := m.getOperand_ER_SR_NR(def, mode)
require.Equal(t, tc.exp, actual)
@@ -286,7 +288,9 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
ext.AsUExtend(v, c.from, c.to)
}
builder.InsertInstruction(ext)
extArg := ext.Arg()
ctx.vRegMap[ext.Arg()] = regalloc.VReg(10)
ctx.definitions[v] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(10), BlockParamValue: extArg}
def = &backend.SSAValueDefinition{Instr: ext, N: 0}
return def, extModeNone, func(t *testing.T) {
_, ok := ctx.lowered[ext]
@@ -301,12 +305,14 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
t.Run("valid mode", func(t *testing.T) {
const argVReg, resultVReg = regalloc.VReg(10), regalloc.VReg(11)
for _, c := range []struct {
name string
from, to byte
signed bool
mode extMode
exp operand
lowered bool
name string
from, to byte
signed bool
mode extMode
exp operand
lowered bool
extArgConst bool
instructions []string
}{
{
name: "8->16->32: signed",
@@ -356,6 +362,93 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
exp: operandER(argVReg, extendOpUXTB, 64),
lowered: true,
},
{
name: "8(VReg)->64->64: unsigned",
from: 8, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpUXTB, 64),
lowered: true,
},
{
name: "8(VReg,Const)->64->64: unsigned",
from: 8, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpUXTB, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
{
name: "16(VReg)->64->64: unsigned",
from: 16, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpUXTH, 64),
lowered: true,
},
{
name: "16(VReg,Const)->64->64: unsigned",
from: 16, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpUXTH, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
{
name: "32(VReg)->64->64: unsigned",
from: 32, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpUXTW, 64),
lowered: true,
},
{
name: "32(VReg,Const)->64->64: unsigned",
from: 32, to: 64, signed: false, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpUXTW, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
///////////
{
name: "8(VReg)->64->64: signed",
from: 8, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpSXTB, 64),
lowered: true,
},
{
name: "8(VReg,Const)->64->64: signed",
from: 8, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpSXTB, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
{
name: "16(VReg)->64->64: signed",
from: 16, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpSXTH, 64),
lowered: true,
},
{
name: "16(VReg,Const)->64->64: signed",
from: 16, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpSXTH, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
{
name: "32(VReg)->64->64: signed",
from: 32, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(argVReg, extendOpSXTW, 64),
lowered: true,
},
{
name: "32(VReg,Const)->64->64: signed",
from: 32, to: 64, signed: true, mode: extModeZeroExtend64,
exp: operandER(regalloc.VReg(nextVReg).SetRegType(regalloc.RegTypeInt), extendOpSXTW, 64),
lowered: true,
extArgConst: true,
instructions: []string{"movz w100?, #0xffff, lsl 0"},
},
// Not lowered cases.
{
name: "8-signed->16-zero->64",
@@ -406,15 +499,28 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
ext.AsUExtend(v, c.from, c.to)
}
builder.InsertInstruction(ext)
ctx.vRegMap[ext.Arg()] = argVReg
extArg := ext.Arg()
ctx.vRegMap[extArg] = argVReg
ctx.vRegMap[ext.Return()] = resultVReg
if c.extArgConst {
iconst := builder.AllocateInstruction().AsIconst32(0xffff).Insert(builder)
m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{
Instr: iconst,
}
} else {
m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{
BlkParamVReg: argVReg,
BlockParamValue: extArg,
}
}
def = &backend.SSAValueDefinition{Instr: ext, N: 0}
return def, c.mode, func(t *testing.T) {
_, ok := ctx.lowered[ext]
require.Equal(t, c.lowered, ok)
}
},
exp: c.exp,
exp: c.exp,
instructions: c.instructions,
})
})
}

View File

@@ -1382,9 +1382,9 @@ blk0: (exec_ctx:i64, module_ctx:i64)
v7:i64 = Load module_ctx, 0x8
v8:i64 = Load v7, 0x8
v9:i64 = Load module_ctx, 0x8
v10:i64 = Load v9, 0x8
v10:i32 = Load v9, 0x8
v11:i32 = Iconst_32 0x10
v12:i64 = Ushr v10, v11
v12:i32 = Ushr v10, v11
v13:i32 = Iconst_32 0xa
Store module_ctx, exec_ctx, 0x8
v14:i64 = Load exec_ctx, 0x48
@@ -1402,9 +1402,9 @@ blk0: (exec_ctx:i64, module_ctx:i64)
v25:i64 = Load module_ctx, 0x8
v26:i64 = Load v25, 0x8
v27:i64 = Load module_ctx, 0x8
v28:i64 = Load v27, 0x8
v28:i32 = Load v27, 0x8
v29:i32 = Iconst_32 0x10
v30:i64 = Ushr v28, v29
v30:i32 = Ushr v28, v29
Jump blk_ret, v4, v12, v22, v30
`,
expAfterOpt: `
@@ -1418,9 +1418,9 @@ blk0: (exec_ctx:i64, module_ctx:i64)
v3:i64 = Load module_ctx, 0x20
v4:i32 = CallIndirect v2:sig0, exec_ctx, v3
v9:i64 = Load module_ctx, 0x8
v10:i64 = Load v9, 0x8
v10:i32 = Load v9, 0x8
v11:i32 = Iconst_32 0x10
v12:i64 = Ushr v10, v11
v12:i32 = Ushr v10, v11
v13:i32 = Iconst_32 0xa
Store module_ctx, exec_ctx, 0x8
v14:i64 = Load exec_ctx, 0x48
@@ -1430,9 +1430,9 @@ blk0: (exec_ctx:i64, module_ctx:i64)
v21:i64 = Load module_ctx, 0x20
v22:i32 = CallIndirect v20:sig0, exec_ctx, v21
v27:i64 = Load module_ctx, 0x8
v28:i64 = Load v27, 0x8
v28:i32 = Load v27, 0x8
v29:i32 = Iconst_32 0x10
v30:i64 = Ushr v28, v29
v30:i32 = Ushr v28, v29
Jump blk_ret, v4, v12, v22, v30
`,
},

View File

@@ -769,7 +769,7 @@ func (c *Compiler) lowerCurrentOpcode() {
Return()
memSizeInBytes = builder.AllocateInstruction().
AsLoad(memInstPtr, memoryInstanceBufSizeOffset, ssa.TypeI64).
AsLoad(memInstPtr, memoryInstanceBufSizeOffset, ssa.TypeI32).
Insert(builder).
Return()
} else {