wazevo: passes all many params/results tests (#1727)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -259,7 +259,7 @@ func (a *abiImpl) CalleeGenVRegsToFunctionReturns(rets []ssa.Value) {
|
||||
|
||||
// callerGenVRegToFunctionArg is the opposite of GenFunctionArgToVReg, which is used to generate the
|
||||
// caller side of the function call.
|
||||
func (a *abiImpl) callerGenVRegToFunctionArg(argIndex int, reg regalloc.VReg, def *backend.SSAValueDefinition) {
|
||||
func (a *abiImpl) callerGenVRegToFunctionArg(argIndex int, reg regalloc.VReg, def *backend.SSAValueDefinition, slotBegin int64) {
|
||||
arg := &a.args[argIndex]
|
||||
if def != nil && def.IsFromInstr() {
|
||||
// Constant instructions are inlined.
|
||||
@@ -274,20 +274,20 @@ func (a *abiImpl) callerGenVRegToFunctionArg(argIndex int, reg regalloc.VReg, de
|
||||
//
|
||||
// Note that at this point, stack pointer is already adjusted.
|
||||
bits := arg.Type.Bits()
|
||||
amode := a.m.resolveAddressModeForOffset(arg.Offset, bits, spVReg)
|
||||
amode := a.m.resolveAddressModeForOffset(arg.Offset-slotBegin, bits, spVReg, false)
|
||||
store := a.m.allocateInstr()
|
||||
store.asStore(operandNR(reg), amode, bits)
|
||||
a.m.insert(store)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *abiImpl) callerGenFunctionReturnVReg(retIndex int, reg regalloc.VReg) {
|
||||
func (a *abiImpl) callerGenFunctionReturnVReg(retIndex int, reg regalloc.VReg, slotBegin int64) {
|
||||
r := &a.rets[retIndex]
|
||||
if r.Kind == backend.ABIArgKindReg {
|
||||
a.m.InsertMove(reg, r.Reg, r.Type)
|
||||
} else {
|
||||
// TODO: we could use pair load if there's consecutive loads for the same type.
|
||||
amode := a.m.resolveAddressModeForOffset(r.Offset, r.Type.Bits(), spVReg)
|
||||
amode := a.m.resolveAddressModeForOffset(a.argStackSize+r.Offset-slotBegin, r.Type.Bits(), spVReg, false)
|
||||
ldr := a.m.allocateInstr()
|
||||
switch r.Type {
|
||||
case ssa.TypeI32, ssa.TypeI64:
|
||||
@@ -301,16 +301,16 @@ func (a *abiImpl) callerGenFunctionReturnVReg(retIndex int, reg regalloc.VReg) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *machine) resolveAddressModeForOffsetAndInsert(cur *instruction, offset int64, dstBits byte, rn regalloc.VReg) (*instruction, addressMode) {
|
||||
func (m *machine) resolveAddressModeForOffsetAndInsert(cur *instruction, offset int64, dstBits byte, rn regalloc.VReg, allowTmpRegUse bool) (*instruction, addressMode) {
|
||||
m.pendingInstructions = m.pendingInstructions[:0]
|
||||
mode := m.resolveAddressModeForOffset(offset, dstBits, rn)
|
||||
mode := m.resolveAddressModeForOffset(offset, dstBits, rn, allowTmpRegUse)
|
||||
for _, instr := range m.pendingInstructions {
|
||||
cur = linkInstr(cur, instr)
|
||||
}
|
||||
return cur, mode
|
||||
}
|
||||
|
||||
func (m *machine) resolveAddressModeForOffset(offset int64, dstBits byte, rn regalloc.VReg) addressMode {
|
||||
func (m *machine) resolveAddressModeForOffset(offset int64, dstBits byte, rn regalloc.VReg, allowTmpRegUse bool) addressMode {
|
||||
if rn.RegType() != regalloc.RegTypeInt {
|
||||
panic("BUG: rn should be a pointer: " + formatVRegSized(rn, 64))
|
||||
}
|
||||
@@ -320,8 +320,15 @@ func (m *machine) resolveAddressModeForOffset(offset int64, dstBits byte, rn reg
|
||||
} else if offsetFitsInAddressModeKindRegSignedImm9(offset) {
|
||||
amode = addressMode{kind: addressModeKindRegSignedImm9, rn: rn, imm: offset}
|
||||
} else {
|
||||
m.lowerConstantI64(tmpRegVReg, offset)
|
||||
amode = addressMode{kind: addressModeKindRegReg, rn: rn, rm: tmpRegVReg, extOp: extendOpUXTX /* indicates index rm is 64-bit */}
|
||||
var indexReg regalloc.VReg
|
||||
if allowTmpRegUse {
|
||||
m.lowerConstantI64(tmpRegVReg, offset)
|
||||
indexReg = tmpRegVReg
|
||||
} else {
|
||||
indexReg = m.compiler.AllocateVRegWithSSAType(regalloc.RegTypeInt, ssa.TypeI64)
|
||||
m.lowerConstantI64(indexReg, offset)
|
||||
}
|
||||
amode = addressMode{kind: addressModeKindRegReg, rn: rn, rm: indexReg, extOp: extendOpUXTX /* indicates index rm is 64-bit */}
|
||||
}
|
||||
return amode
|
||||
}
|
||||
@@ -347,10 +354,6 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
|
||||
calleeABI := m.getOrCreateABIImpl(m.compiler.ResolveSignature(sigID))
|
||||
|
||||
stackSlotSize := calleeABI.alignedArgResultStackSlotSize()
|
||||
if stackSlotSize > 0 {
|
||||
m.insertAddOrSubStackPointer(spVReg, stackSlotSize, false /* == sub */)
|
||||
}
|
||||
|
||||
if m.maxRequiredStackSizeForCalls < stackSlotSize {
|
||||
m.maxRequiredStackSizeForCalls = stackSlotSize
|
||||
}
|
||||
@@ -358,7 +361,7 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
|
||||
for i, arg := range args {
|
||||
reg := m.compiler.VRegOf(arg)
|
||||
def := m.compiler.ValueDefinition(arg)
|
||||
calleeABI.callerGenVRegToFunctionArg(i, reg, def)
|
||||
calleeABI.callerGenVRegToFunctionArg(i, reg, def, stackSlotSize)
|
||||
}
|
||||
|
||||
if isDirectCall {
|
||||
@@ -375,18 +378,14 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
|
||||
var index int
|
||||
r1, rs := si.Returns()
|
||||
if r1.Valid() {
|
||||
calleeABI.callerGenFunctionReturnVReg(0, m.compiler.VRegOf(r1))
|
||||
calleeABI.callerGenFunctionReturnVReg(0, m.compiler.VRegOf(r1), stackSlotSize)
|
||||
index++
|
||||
}
|
||||
|
||||
for _, r := range rs {
|
||||
calleeABI.callerGenFunctionReturnVReg(index, m.compiler.VRegOf(r))
|
||||
calleeABI.callerGenFunctionReturnVReg(index, m.compiler.VRegOf(r), stackSlotSize)
|
||||
index++
|
||||
}
|
||||
|
||||
if stackSlotSize > 0 {
|
||||
m.insertAddOrSubStackPointer(spVReg, stackSlotSize, true /* add */)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *machine) insertAddOrSubStackPointer(rd regalloc.VReg, diff int64, add bool) {
|
||||
|
||||
@@ -37,7 +37,7 @@ var (
|
||||
functionExecutable = x24VReg
|
||||
)
|
||||
|
||||
func (m *machine) goEntryPreamblePassArg(cur *instruction, paramSlicePtr regalloc.VReg, arg *backend.ABIArg) *instruction {
|
||||
func (m *machine) goEntryPreamblePassArg(cur *instruction, paramSlicePtr regalloc.VReg, arg *backend.ABIArg, argStartOffsetFromSP int64) *instruction {
|
||||
typ := arg.Type
|
||||
bits := typ.Bits()
|
||||
isStackArg := arg.Kind == backend.ABIArgKindStack
|
||||
@@ -48,7 +48,7 @@ func (m *machine) goEntryPreamblePassArg(cur *instruction, paramSlicePtr regallo
|
||||
} else {
|
||||
switch typ {
|
||||
case ssa.TypeI32, ssa.TypeI64:
|
||||
loadTargetReg = operandNR(tmpRegVReg)
|
||||
loadTargetReg = operandNR(x15VReg)
|
||||
case ssa.TypeF32, ssa.TypeF64, ssa.TypeV128:
|
||||
loadTargetReg = operandNR(v15VReg)
|
||||
default:
|
||||
@@ -81,7 +81,7 @@ func (m *machine) goEntryPreamblePassArg(cur *instruction, paramSlicePtr regallo
|
||||
|
||||
if isStackArg {
|
||||
var storeMode addressMode
|
||||
cur, storeMode = m.resolveAddressModeForOffsetAndInsert(cur, arg.Offset, bits, spVReg)
|
||||
cur, storeMode = m.resolveAddressModeForOffsetAndInsert(cur, argStartOffsetFromSP+arg.Offset, bits, spVReg, true)
|
||||
toStack := m.allocateInstr()
|
||||
toStack.asStore(loadTargetReg, storeMode, bits)
|
||||
cur = linkInstr(cur, toStack)
|
||||
@@ -100,7 +100,7 @@ func (m *machine) goEntryPreamblePassResult(cur *instruction, resultSlicePtr reg
|
||||
} else {
|
||||
switch typ {
|
||||
case ssa.TypeI32, ssa.TypeI64:
|
||||
storeTargetReg = operandNR(tmpRegVReg)
|
||||
storeTargetReg = operandNR(x15VReg)
|
||||
case ssa.TypeF32, ssa.TypeF64, ssa.TypeV128:
|
||||
storeTargetReg = operandNR(v15VReg)
|
||||
default:
|
||||
@@ -117,7 +117,7 @@ func (m *machine) goEntryPreamblePassResult(cur *instruction, resultSlicePtr reg
|
||||
|
||||
if isStackArg {
|
||||
var loadMode addressMode
|
||||
cur, loadMode = m.resolveAddressModeForOffsetAndInsert(cur, resultStartOffsetFromSP+result.Offset, bits, spVReg)
|
||||
cur, loadMode = m.resolveAddressModeForOffsetAndInsert(cur, resultStartOffsetFromSP+result.Offset, bits, spVReg, true)
|
||||
toReg := m.allocateInstr()
|
||||
switch typ {
|
||||
case ssa.TypeI32, ssa.TypeI64:
|
||||
@@ -157,21 +157,8 @@ func (a *abiImpl) constructEntryPreamble() (root *instruction) {
|
||||
cur = a.loadOrStoreAtExecutionContext(tmpRegVReg, wazevoapi.ExecutionContextOffsetOriginalStackPointer, true, cur)
|
||||
cur = a.loadOrStoreAtExecutionContext(lrVReg, wazevoapi.ExecutionContextOffsetGoReturnAddress, true, cur)
|
||||
|
||||
// Next, adjust the Go-allocated stack pointer to reserve the arg/result spaces.
|
||||
// sub x28, x28, #stackSlotSize
|
||||
if stackSlotSize := a.alignedArgResultStackSlotSize(); stackSlotSize > 0 {
|
||||
if imm12Operand, ok := asImm12Operand(uint64(stackSlotSize)); ok {
|
||||
instr := m.allocateInstr()
|
||||
rd := operandNR(goAllocatedStackPtr)
|
||||
instr.asALU(aluOpSub, rd, rd, imm12Operand, true)
|
||||
cur = linkInstr(cur, instr)
|
||||
} else {
|
||||
panic("TODO: too large stack slot size")
|
||||
}
|
||||
}
|
||||
|
||||
// Then, move the Go-allocated stack pointer to SP:
|
||||
// mov sp, x28
|
||||
// mov sp, goAllocatedStackPtr
|
||||
cur = a.move64(spVReg, goAllocatedStackPtr, cur)
|
||||
|
||||
prReg := paramResultSlicePtr
|
||||
@@ -181,18 +168,18 @@ func (a *abiImpl) constructEntryPreamble() (root *instruction) {
|
||||
cur = a.move64(paramResultSliceCopied, paramResultSlicePtr, cur)
|
||||
prReg = paramResultSliceCopied
|
||||
}
|
||||
|
||||
stackSlotSize := a.alignedArgResultStackSlotSize()
|
||||
for i := range a.args {
|
||||
if i < 2 {
|
||||
// module context ptr and execution context ptr are passed in x0 and x1 by the Go assembly function.
|
||||
continue
|
||||
}
|
||||
arg := &a.args[i]
|
||||
cur = m.goEntryPreamblePassArg(cur, prReg, arg)
|
||||
cur = m.goEntryPreamblePassArg(cur, prReg, arg, -stackSlotSize)
|
||||
}
|
||||
|
||||
// Call the real function coming after epilogue:
|
||||
// bl #<offset of real function from this instruction>
|
||||
// But at this point, we don't know the size of epilogue, so we emit a placeholder.
|
||||
// Call the real function.
|
||||
bl := m.allocateInstr()
|
||||
bl.asCallIndirect(functionExecutable, a)
|
||||
cur = linkInstr(cur, bl)
|
||||
@@ -201,7 +188,7 @@ func (a *abiImpl) constructEntryPreamble() (root *instruction) {
|
||||
|
||||
// Store the register results into paramResultSlicePtr.
|
||||
for i := range a.rets {
|
||||
cur = m.goEntryPreamblePassResult(cur, paramResultSlicePtr, &a.rets[i], a.argStackSize)
|
||||
cur = m.goEntryPreamblePassResult(cur, paramResultSlicePtr, &a.rets[i], a.argStackSize-stackSlotSize)
|
||||
}
|
||||
|
||||
// Finally, restore the FP, SP and LR, and return to the Go code.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -178,7 +179,6 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
mov x27, sp
|
||||
str x27, [x20, #0x18]
|
||||
str x30, [x20, #0x20]
|
||||
sub x26, x26, #0x70
|
||||
mov sp, x26
|
||||
bl x24
|
||||
str s0, [x19], #0x8
|
||||
@@ -195,29 +195,29 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
str d4, [x19], #0x8
|
||||
str w7, [x19], #0x8
|
||||
str s5, [x19], #0x8
|
||||
ldr x27, [sp]
|
||||
str x27, [x19], #0x8
|
||||
ldr w27, [sp, #0x8]
|
||||
str w27, [x19], #0x8
|
||||
ldr w27, [sp, #0x10]
|
||||
str w27, [x19], #0x8
|
||||
ldr x27, [sp, #0x18]
|
||||
str x27, [x19], #0x8
|
||||
ldr w27, [sp, #0x20]
|
||||
str w27, [x19], #0x8
|
||||
ldr x27, [sp, #0x28]
|
||||
str x27, [x19], #0x8
|
||||
ldr x15, [sp, #-0x70]
|
||||
str x15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x68]
|
||||
str w15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x60]
|
||||
str w15, [x19], #0x8
|
||||
ldr x15, [sp, #-0x58]
|
||||
str x15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x50]
|
||||
str w15, [x19], #0x8
|
||||
ldr x15, [sp, #-0x48]
|
||||
str x15, [x19], #0x8
|
||||
str s6, [x19], #0x8
|
||||
str d7, [x19], #0x8
|
||||
ldr d15, [sp, #0x30]
|
||||
ldr d15, [sp, #-0x40]
|
||||
str d15, [x19], #0x8
|
||||
ldr s15, [sp, #0x38]
|
||||
ldr s15, [sp, #-0x38]
|
||||
str s15, [x19], #0x8
|
||||
ldr d15, [sp, #0x40]
|
||||
ldr d15, [sp, #-0x30]
|
||||
str d15, [x19], #0x8
|
||||
ldr q15, [sp, #0x50]
|
||||
ldr q15, [sp, #-0x20]
|
||||
str q15, [x19], #0x10
|
||||
ldr q15, [sp, #0x60]
|
||||
ldr q15, [sp, #-0x10]
|
||||
str q15, [x19], #0x10
|
||||
ldr x29, [x20, #0x10]
|
||||
ldr x27, [x20, #0x18]
|
||||
@@ -241,7 +241,6 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
mov x27, sp
|
||||
str x27, [x20, #0x18]
|
||||
str x30, [x20, #0x20]
|
||||
sub x26, x26, #0xa0
|
||||
mov sp, x26
|
||||
ldr q0, [x19], #0x10
|
||||
ldr q1, [x19], #0x10
|
||||
@@ -254,39 +253,39 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
ldr x7, [x19], #0x8
|
||||
ldr s3, [x19], #0x8
|
||||
ldr d4, [x19], #0x8
|
||||
ldr w27, [x19], #0x8
|
||||
str w27, [sp]
|
||||
ldr w15, [x19], #0x8
|
||||
str w15, [sp, #-0xa0]
|
||||
ldr s5, [x19], #0x8
|
||||
ldr x27, [x19], #0x8
|
||||
str x27, [sp, #0x8]
|
||||
ldr w27, [x19], #0x8
|
||||
str w27, [sp, #0x10]
|
||||
ldr w27, [x19], #0x8
|
||||
str w27, [sp, #0x18]
|
||||
ldr x27, [x19], #0x8
|
||||
str x27, [sp, #0x20]
|
||||
ldr w27, [x19], #0x8
|
||||
str w27, [sp, #0x28]
|
||||
ldr x27, [x19], #0x8
|
||||
str x27, [sp, #0x30]
|
||||
ldr x15, [x19], #0x8
|
||||
str x15, [sp, #-0x98]
|
||||
ldr w15, [x19], #0x8
|
||||
str w15, [sp, #-0x90]
|
||||
ldr w15, [x19], #0x8
|
||||
str w15, [sp, #-0x88]
|
||||
ldr x15, [x19], #0x8
|
||||
str x15, [sp, #-0x80]
|
||||
ldr w15, [x19], #0x8
|
||||
str w15, [sp, #-0x78]
|
||||
ldr x15, [x19], #0x8
|
||||
str x15, [sp, #-0x70]
|
||||
ldr s6, [x19], #0x8
|
||||
ldr d7, [x19], #0x8
|
||||
ldr d15, [x19], #0x8
|
||||
str d15, [sp, #0x38]
|
||||
str d15, [sp, #-0x68]
|
||||
ldr s15, [x19], #0x8
|
||||
str s15, [sp, #0x40]
|
||||
str s15, [sp, #-0x60]
|
||||
ldr d15, [x19], #0x8
|
||||
str d15, [sp, #0x48]
|
||||
str d15, [sp, #-0x58]
|
||||
ldr q15, [x19], #0x10
|
||||
str q15, [sp, #0x50]
|
||||
str q15, [sp, #-0x50]
|
||||
ldr q15, [x19], #0x10
|
||||
str q15, [sp, #0x60]
|
||||
str q15, [sp, #-0x40]
|
||||
ldr q15, [x19], #0x10
|
||||
str q15, [sp, #0x70]
|
||||
str q15, [sp, #-0x30]
|
||||
ldr q15, [x19], #0x10
|
||||
str q15, [sp, #0x80]
|
||||
str q15, [sp, #-0x20]
|
||||
ldr q15, [x19], #0x10
|
||||
str q15, [sp, #0x90]
|
||||
str q15, [sp, #-0x10]
|
||||
bl x24
|
||||
ldr x29, [x20, #0x10]
|
||||
ldr x27, [x20, #0x18]
|
||||
@@ -296,7 +295,7 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "many params/results",
|
||||
name: "many params and results",
|
||||
sig: &ssa.Signature{
|
||||
Params: []ssa.Type{
|
||||
i32, i32, v128, v128, v128, i64, i32, i32, i64, i32, i64,
|
||||
@@ -314,7 +313,6 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
mov x27, sp
|
||||
str x27, [x20, #0x18]
|
||||
str x30, [x20, #0x20]
|
||||
sub x26, x26, #0xe0
|
||||
mov sp, x26
|
||||
mov x25, x19
|
||||
ldr q0, [x25], #0x10
|
||||
@@ -328,39 +326,39 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
ldr x7, [x25], #0x8
|
||||
ldr s3, [x25], #0x8
|
||||
ldr d4, [x25], #0x8
|
||||
ldr w27, [x25], #0x8
|
||||
str w27, [sp]
|
||||
ldr w15, [x25], #0x8
|
||||
str w15, [sp, #-0xe0]
|
||||
ldr s5, [x25], #0x8
|
||||
ldr x27, [x25], #0x8
|
||||
str x27, [sp, #0x8]
|
||||
ldr w27, [x25], #0x8
|
||||
str w27, [sp, #0x10]
|
||||
ldr w27, [x25], #0x8
|
||||
str w27, [sp, #0x18]
|
||||
ldr x27, [x25], #0x8
|
||||
str x27, [sp, #0x20]
|
||||
ldr w27, [x25], #0x8
|
||||
str w27, [sp, #0x28]
|
||||
ldr x27, [x25], #0x8
|
||||
str x27, [sp, #0x30]
|
||||
ldr x15, [x25], #0x8
|
||||
str x15, [sp, #-0xd8]
|
||||
ldr w15, [x25], #0x8
|
||||
str w15, [sp, #-0xd0]
|
||||
ldr w15, [x25], #0x8
|
||||
str w15, [sp, #-0xc8]
|
||||
ldr x15, [x25], #0x8
|
||||
str x15, [sp, #-0xc0]
|
||||
ldr w15, [x25], #0x8
|
||||
str w15, [sp, #-0xb8]
|
||||
ldr x15, [x25], #0x8
|
||||
str x15, [sp, #-0xb0]
|
||||
ldr s6, [x25], #0x8
|
||||
ldr d7, [x25], #0x8
|
||||
ldr d15, [x25], #0x8
|
||||
str d15, [sp, #0x38]
|
||||
str d15, [sp, #-0xa8]
|
||||
ldr s15, [x25], #0x8
|
||||
str s15, [sp, #0x40]
|
||||
str s15, [sp, #-0xa0]
|
||||
ldr d15, [x25], #0x8
|
||||
str d15, [sp, #0x48]
|
||||
str d15, [sp, #-0x98]
|
||||
ldr q15, [x25], #0x10
|
||||
str q15, [sp, #0x50]
|
||||
str q15, [sp, #-0x90]
|
||||
ldr q15, [x25], #0x10
|
||||
str q15, [sp, #0x60]
|
||||
str q15, [sp, #-0x80]
|
||||
ldr q15, [x25], #0x10
|
||||
str q15, [sp, #0x70]
|
||||
str q15, [sp, #-0x70]
|
||||
ldr q15, [x25], #0x10
|
||||
str q15, [sp, #0x80]
|
||||
str q15, [sp, #-0x60]
|
||||
ldr q15, [x25], #0x10
|
||||
str q15, [sp, #0x90]
|
||||
str q15, [sp, #-0x50]
|
||||
bl x24
|
||||
str s0, [x19], #0x8
|
||||
str d1, [x19], #0x8
|
||||
@@ -373,23 +371,23 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
str w5, [x19], #0x8
|
||||
str x6, [x19], #0x8
|
||||
str w7, [x19], #0x8
|
||||
ldr w27, [sp, #0xa0]
|
||||
str w27, [x19], #0x8
|
||||
ldr w15, [sp, #-0x40]
|
||||
str w15, [x19], #0x8
|
||||
str q3, [x19], #0x10
|
||||
str q4, [x19], #0x10
|
||||
str q5, [x19], #0x10
|
||||
ldr x27, [sp, #0xa8]
|
||||
str x27, [x19], #0x8
|
||||
ldr w27, [sp, #0xb0]
|
||||
str w27, [x19], #0x8
|
||||
ldr w27, [sp, #0xb8]
|
||||
str w27, [x19], #0x8
|
||||
ldr x27, [sp, #0xc0]
|
||||
str x27, [x19], #0x8
|
||||
ldr w27, [sp, #0xc8]
|
||||
str w27, [x19], #0x8
|
||||
ldr x27, [sp, #0xd0]
|
||||
str x27, [x19], #0x8
|
||||
ldr x15, [sp, #-0x38]
|
||||
str x15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x30]
|
||||
str w15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x28]
|
||||
str w15, [x19], #0x8
|
||||
ldr x15, [sp, #-0x20]
|
||||
str x15, [x19], #0x8
|
||||
ldr w15, [sp, #-0x18]
|
||||
str w15, [x19], #0x8
|
||||
ldr x15, [sp, #-0x10]
|
||||
str x15, [x19], #0x8
|
||||
ldr x29, [x20, #0x10]
|
||||
ldr x27, [x20, #0x18]
|
||||
mov sp, x27
|
||||
@@ -404,6 +402,8 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
m.rootInstr = abi.constructEntryPreamble()
|
||||
fmt.Println(m.Format())
|
||||
require.Equal(t, tc.exp, m.Format())
|
||||
m.Encode()
|
||||
fmt.Println(hex.EncodeToString(m.compiler.Buf()))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -411,8 +411,9 @@ func TestAbiImpl_constructEntryPreamble(t *testing.T) {
|
||||
func TestMachine_goEntryPreamblePassArg(t *testing.T) {
|
||||
paramSlicePtr := x16VReg
|
||||
for _, tc := range []struct {
|
||||
arg backend.ABIArg
|
||||
exp string
|
||||
arg backend.ABIArg
|
||||
argSlotBeginOffsetFromSP int64
|
||||
exp string
|
||||
}{
|
||||
// Reg kinds.
|
||||
{
|
||||
@@ -455,29 +456,29 @@ func TestMachine_goEntryPreamblePassArg(t *testing.T) {
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 0, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr w27, [x16], #0x8
|
||||
str w27, [sp]
|
||||
ldr w15, [x16], #0x8
|
||||
str w15, [sp]
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 8, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr w27, [x16], #0x8
|
||||
str w27, [sp, #0x8]
|
||||
ldr w15, [x16], #0x8
|
||||
str w15, [sp, #0x8]
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI64, Offset: 0, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr x27, [x16], #0x8
|
||||
str x27, [sp]
|
||||
ldr x15, [x16], #0x8
|
||||
str x15, [sp]
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI64, Offset: 128, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr x27, [x16], #0x8
|
||||
str x27, [sp, #0x80]
|
||||
ldr x15, [x16], #0x8
|
||||
str x15, [sp, #0x80]
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -521,6 +522,15 @@ func TestMachine_goEntryPreamblePassArg(t *testing.T) {
|
||||
ldr q15, [x16], #0x10
|
||||
movz x27, #0x808, lsl 0
|
||||
str q15, [sp, x27]
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeV128, Offset: 1024, Kind: backend.ABIArgKindStack},
|
||||
argSlotBeginOffsetFromSP: -1648,
|
||||
exp: `
|
||||
ldr q15, [x16], #0x10
|
||||
movn x27, #0x26f, lsl 0
|
||||
str q15, [sp, x27]
|
||||
`,
|
||||
},
|
||||
} {
|
||||
@@ -528,9 +538,11 @@ func TestMachine_goEntryPreamblePassArg(t *testing.T) {
|
||||
_, _, m := newSetupWithMockContext()
|
||||
cur := m.allocateNop()
|
||||
m.rootInstr = cur
|
||||
m.goEntryPreamblePassArg(cur, paramSlicePtr, &tc.arg)
|
||||
m.goEntryPreamblePassArg(cur, paramSlicePtr, &tc.arg, tc.argSlotBeginOffsetFromSP)
|
||||
fmt.Println(m.Format())
|
||||
require.Equal(t, tc.exp, m.Format())
|
||||
m.Encode()
|
||||
fmt.Println(hex.EncodeToString(m.compiler.Buf()))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -583,45 +595,45 @@ func TestMachine_goEntryPreamblePassResult(t *testing.T) {
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 0, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr w27, [sp]
|
||||
str w27, [x16], #0x8
|
||||
ldr w15, [sp]
|
||||
str w15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 0, Kind: backend.ABIArgKindStack},
|
||||
retStart: 1024,
|
||||
exp: `
|
||||
ldr w27, [sp, #0x400]
|
||||
str w27, [x16], #0x8
|
||||
ldr w15, [sp, #0x400]
|
||||
str w15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 8, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr w27, [sp, #0x8]
|
||||
str w27, [x16], #0x8
|
||||
ldr w15, [sp, #0x8]
|
||||
str w15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI32, Offset: 8, Kind: backend.ABIArgKindStack},
|
||||
retStart: 1024,
|
||||
exp: `
|
||||
ldr w27, [sp, #0x408]
|
||||
str w27, [x16], #0x8
|
||||
ldr w15, [sp, #0x408]
|
||||
str w15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI64, Offset: 0, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr x27, [sp]
|
||||
str x27, [x16], #0x8
|
||||
ldr x15, [sp]
|
||||
str x15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeI64, Offset: 128, Kind: backend.ABIArgKindStack},
|
||||
exp: `
|
||||
ldr x27, [sp, #0x80]
|
||||
str x27, [x16], #0x8
|
||||
ldr x15, [sp, #0x80]
|
||||
str x15, [x16], #0x8
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -669,9 +681,9 @@ func TestMachine_goEntryPreamblePassResult(t *testing.T) {
|
||||
},
|
||||
{
|
||||
arg: backend.ABIArg{Type: ssa.TypeV128, Offset: 2056, Kind: backend.ABIArgKindStack},
|
||||
retStart: 1024,
|
||||
retStart: -1024,
|
||||
exp: `
|
||||
movz x27, #0xc08, lsl 0
|
||||
movz x27, #0x408, lsl 0
|
||||
ldr q15, [sp, x27]
|
||||
str q15, [x16], #0x10
|
||||
`,
|
||||
@@ -684,6 +696,8 @@ func TestMachine_goEntryPreamblePassResult(t *testing.T) {
|
||||
m.goEntryPreamblePassResult(cur, paramSlicePtr, &tc.arg, tc.retStart)
|
||||
fmt.Println(m.Format())
|
||||
require.Equal(t, tc.exp, m.Format())
|
||||
m.Encode()
|
||||
fmt.Println(hex.EncodeToString(m.compiler.Buf()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,15 +33,15 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
|
||||
// In the following, we create the following stack layout:
|
||||
//
|
||||
// (high address)
|
||||
// +-----------------+
|
||||
// | ....... |
|
||||
// | ret Y | <----+
|
||||
// SP ------> +-----------------+ <----+
|
||||
// | ....... | |
|
||||
// | ret Y | |
|
||||
// | ....... | |
|
||||
// | ret 0 | |
|
||||
// | arg X | | size_of_arg_ret
|
||||
// | ....... | |
|
||||
// | arg 1 | |
|
||||
// SP ------> | arg 0 | <----+ <-------- originalArg0Reg
|
||||
// | arg 0 | <----+ <-------- originalArg0Reg
|
||||
// | size_of_arg_ret |
|
||||
// | ReturnAddress |
|
||||
// +-----------------+ <----+
|
||||
@@ -59,9 +59,12 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
|
||||
// therefore will be accessed as the usual []uint64. So that's where we need to pass/receive
|
||||
// the arguments/return values.
|
||||
|
||||
// First of all, to update the SP, and create "ReturnAddress + size_of_arg_ret".
|
||||
cur = m.createReturnAddrAndSizeOfArgRetSlot(cur)
|
||||
|
||||
const callFrameSize = 32 // == frame_size + sliceSize + ReturnAddress + size_of_arg_ret.
|
||||
|
||||
// First of all, we should allocate the stack for the Go function call if necessary.
|
||||
// Next, we should allocate the stack for the Go function call if necessary.
|
||||
goCallStackSize, sliceSizeInBytes := goFunctionCallRequiredStackSize(sig, argBegin)
|
||||
cur = m.insertStackBoundsCheck(goCallStackSize+callFrameSize, cur)
|
||||
|
||||
@@ -72,9 +75,6 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
|
||||
cur = linkInstr(cur, copySp)
|
||||
}
|
||||
|
||||
// Next is to create "ReturnAddress + size_of_arg_ret".
|
||||
cur = m.createReturnAddrAndSizeOfArgRetSlot(cur)
|
||||
|
||||
// Save the callee saved registers.
|
||||
cur = m.saveRegistersInExecutionContext(cur, calleeSavedRegistersPlusLinkRegSorted)
|
||||
|
||||
@@ -162,7 +162,7 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
|
||||
}
|
||||
|
||||
// Removes the stack frame! --> Stack pointer now points to the original arg 0 slot.
|
||||
cur = m.addsAddOrSubStackPointer(cur, spVReg, goCallStackSize+callFrameSize, true)
|
||||
cur = m.addsAddOrSubStackPointer(cur, spVReg, goCallStackSize+callFrameSize+m.currentABI.alignedArgResultStackSlotSize(), true)
|
||||
|
||||
for i := range abi.rets {
|
||||
r := &abi.rets[i]
|
||||
|
||||
@@ -54,6 +54,9 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
},
|
||||
},
|
||||
exp: `
|
||||
orr x27, xzr, #0xc0
|
||||
sub sp, sp, x27
|
||||
stp x30, x27, [sp, #-0x10]!
|
||||
sub x27, sp, #0x140
|
||||
ldr x11, [x0, #0x28]
|
||||
subs xzr, x27, x11
|
||||
@@ -63,8 +66,6 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
ldr x27, [x0, #0x50]
|
||||
bl x27
|
||||
mov x17, sp
|
||||
orr x27, xzr, #0xc0
|
||||
stp x30, x27, [sp, #-0x10]!
|
||||
str x19, [x0, #0x60]
|
||||
str x20, [x0, #0x70]
|
||||
str x21, [x0, #0x80]
|
||||
@@ -153,7 +154,7 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
ldr q30, [x0, #0x1c0]
|
||||
ldr q31, [x0, #0x1d0]
|
||||
add x15, sp, #0x10
|
||||
add sp, sp, #0x140
|
||||
add sp, sp, #0x200
|
||||
ldr q0, [x15], #0x10
|
||||
ldr w0, [x15], #0x8
|
||||
ldr x1, [x15], #0x8
|
||||
@@ -209,6 +210,7 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
},
|
||||
needModuleContextPtr: true,
|
||||
exp: `
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
sub x27, sp, #0x40
|
||||
ldr x11, [x0, #0x28]
|
||||
subs xzr, x27, x11
|
||||
@@ -217,7 +219,6 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
str x27, [x0, #0x40]
|
||||
ldr x27, [x0, #0x50]
|
||||
bl x27
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
str x19, [x0, #0x60]
|
||||
str x20, [x0, #0x70]
|
||||
str x21, [x0, #0x80]
|
||||
@@ -298,6 +299,7 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
},
|
||||
needModuleContextPtr: true,
|
||||
exp: `
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
sub x27, sp, #0x40
|
||||
ldr x11, [x0, #0x28]
|
||||
subs xzr, x27, x11
|
||||
@@ -306,7 +308,6 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
str x27, [x0, #0x40]
|
||||
ldr x27, [x0, #0x50]
|
||||
bl x27
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
str x19, [x0, #0x60]
|
||||
str x20, [x0, #0x70]
|
||||
str x21, [x0, #0x80]
|
||||
@@ -384,6 +385,7 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
Results: []ssa.Type{ssa.TypeI32},
|
||||
},
|
||||
exp: `
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
sub x27, sp, #0x30
|
||||
ldr x11, [x0, #0x28]
|
||||
subs xzr, x27, x11
|
||||
@@ -392,7 +394,6 @@ func TestMachine_CompileGoFunctionTrampoline(t *testing.T) {
|
||||
str x27, [x0, #0x40]
|
||||
ldr x27, [x0, #0x50]
|
||||
bl x27
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
str x19, [x0, #0x60]
|
||||
str x20, [x0, #0x70]
|
||||
str x21, [x0, #0x80]
|
||||
|
||||
@@ -266,8 +266,8 @@ func TestAbiImpl_callerGenVRegToFunctionArg_constant_inlining(t *testing.T) {
|
||||
i64 := builder.AllocateInstruction().AsIconst64(10).Insert(builder)
|
||||
f64 := builder.AllocateInstruction().AsF64const(3.14).Insert(builder)
|
||||
abi := m.getOrCreateABIImpl(&ssa.Signature{Params: []ssa.Type{ssa.TypeI64, ssa.TypeF64}})
|
||||
abi.callerGenVRegToFunctionArg(0, regalloc.VReg(100).SetRegType(regalloc.RegTypeInt), &backend.SSAValueDefinition{Instr: i64, RefCount: 1})
|
||||
abi.callerGenVRegToFunctionArg(1, regalloc.VReg(50).SetRegType(regalloc.RegTypeFloat), &backend.SSAValueDefinition{Instr: f64, RefCount: 1})
|
||||
abi.callerGenVRegToFunctionArg(0, regalloc.VReg(100).SetRegType(regalloc.RegTypeInt), &backend.SSAValueDefinition{Instr: i64, RefCount: 1}, 0)
|
||||
abi.callerGenVRegToFunctionArg(1, regalloc.VReg(50).SetRegType(regalloc.RegTypeFloat), &backend.SSAValueDefinition{Instr: f64, RefCount: 1}, 0)
|
||||
require.Equal(t, `movz x100?, #0xa, lsl 0
|
||||
mov x0, x100?
|
||||
ldr d50?, #8; b 16; data.f64 3.140000
|
||||
|
||||
@@ -14,16 +14,16 @@ func (m *machine) SetupPrologue() {
|
||||
|
||||
//
|
||||
// (high address) (high address)
|
||||
// +-----------------+ +------------------+
|
||||
// | ....... | | ....... |
|
||||
// | ret Y | | ret Y | <----+
|
||||
// SP----> +-----------------+ +------------------+ <----+
|
||||
// | ....... | | ....... | |
|
||||
// | ret Y | | ret Y | |
|
||||
// | ....... | | ....... | |
|
||||
// | ret 0 | | ret 0 | |
|
||||
// | arg X | | arg X | | size_of_arg_ret.
|
||||
// | ....... | ====> | ....... | |
|
||||
// | arg 1 | | arg 1 | |
|
||||
// | arg 0 | | arg 0 | <----+
|
||||
// SP----> |-----------------| | size_of_arg_ret |
|
||||
// |-----------------| | size_of_arg_ret |
|
||||
// | return address |
|
||||
// +------------------+ <---- SP
|
||||
// (low address) (low address)
|
||||
@@ -96,7 +96,7 @@ func (m *machine) SetupPrologue() {
|
||||
// (low address) | clobbered N |
|
||||
// | ............ |
|
||||
// | clobbered 0 |
|
||||
// +-----------------+
|
||||
// +-----------------+ <----- SP
|
||||
// (low address)
|
||||
//
|
||||
_amode := addressModePreOrPostIndex(spVReg,
|
||||
@@ -147,15 +147,22 @@ func (m *machine) SetupPrologue() {
|
||||
}
|
||||
|
||||
func (m *machine) createReturnAddrAndSizeOfArgRetSlot(cur *instruction) *instruction {
|
||||
// Saves the return address (lr) and the size_of_arg_ret below the SP.
|
||||
// size_of_arg_ret is used for stack unwinding.
|
||||
// First we decrement the stack pointer to point the arg0 slot.
|
||||
var sizeOfArgRetReg regalloc.VReg
|
||||
if s := m.currentABI.alignedArgResultStackSlotSize(); s > 0 {
|
||||
s := m.currentABI.alignedArgResultStackSlotSize()
|
||||
if s > 0 {
|
||||
cur = m.lowerConstantI64AndInsert(cur, tmpRegVReg, s)
|
||||
sizeOfArgRetReg = tmpRegVReg
|
||||
|
||||
subSp := m.allocateInstr()
|
||||
subSp.asALU(aluOpSub, operandNR(spVReg), operandNR(spVReg), operandNR(sizeOfArgRetReg), true)
|
||||
cur = linkInstr(cur, subSp)
|
||||
} else {
|
||||
sizeOfArgRetReg = xzrVReg
|
||||
}
|
||||
|
||||
// Saves the return address (lr) and the size_of_arg_ret below the SP.
|
||||
// size_of_arg_ret is used for stack unwinding.
|
||||
pstr := m.allocateInstr()
|
||||
amode := addressModePreOrPostIndex(spVReg, -16, true /* decrement before store */)
|
||||
pstr.asStorePair64(lrVReg, sizeOfArgRetReg, amode)
|
||||
@@ -266,6 +273,7 @@ func (m *machine) setupEpilogueAfter(cur *instruction) {
|
||||
// | ....... | | ....... |
|
||||
// | arg 1 | | arg 1 |
|
||||
// | arg 0 | | arg 0 |
|
||||
// | xxxxx | | xxxxx |
|
||||
// | ReturnAddress | | ReturnAddress |
|
||||
// +-----------------+ ====> +-----------------+ <---- SP
|
||||
// | ........... | (low address)
|
||||
@@ -295,10 +303,14 @@ func (m *machine) setupEpilogueAfter(cur *instruction) {
|
||||
// SP----> +-----------------+
|
||||
|
||||
ldr := m.allocateInstr()
|
||||
amode := addressModePreOrPostIndex(spVReg, 16 /* stack pointer must be 16-byte aligned. */, false /* increment after loads */)
|
||||
ldr.asULoad(operandNR(lrVReg), amode, 64)
|
||||
ldr.asULoad(operandNR(lrVReg),
|
||||
addressModePreOrPostIndex(spVReg, 16 /* stack pointer must be 16-byte aligned. */, false /* increment after loads */), 64)
|
||||
cur = linkInstr(cur, ldr)
|
||||
|
||||
if s := m.currentABI.alignedArgResultStackSlotSize(); s > 0 {
|
||||
cur = m.addsAddOrSubStackPointer(cur, spVReg, s, true)
|
||||
}
|
||||
|
||||
linkInstr(cur, prevNext)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,17 @@ func TestMachine_SetupPrologue(t *testing.T) {
|
||||
stp x30, xzr, [sp, #-0x10]!
|
||||
str xzr, [sp, #-0x10]!
|
||||
udf
|
||||
`,
|
||||
},
|
||||
{
|
||||
spillSlotSize: 0,
|
||||
abi: abiImpl{argStackSize: 16, retStackSize: 16},
|
||||
exp: `
|
||||
orr x27, xzr, #0x20
|
||||
sub sp, sp, x27
|
||||
stp x30, x27, [sp, #-0x10]!
|
||||
str xzr, [sp, #-0x10]!
|
||||
udf
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -61,6 +72,24 @@ func TestMachine_SetupPrologue(t *testing.T) {
|
||||
orr x27, xzr, #0x180
|
||||
str x27, [sp, #-0x10]!
|
||||
udf
|
||||
`,
|
||||
},
|
||||
{
|
||||
spillSlotSize: 320,
|
||||
abi: abiImpl{argStackSize: 320, retStackSize: 160},
|
||||
clobberedRegs: []regalloc.VReg{v18VReg, v19VReg, x18VReg, x25VReg},
|
||||
exp: `
|
||||
orr x27, xzr, #0x1e0
|
||||
sub sp, sp, x27
|
||||
stp x30, x27, [sp, #-0x10]!
|
||||
sub sp, sp, #0x140
|
||||
str q18, [sp, #-0x10]!
|
||||
str q19, [sp, #-0x10]!
|
||||
str x18, [sp, #-0x10]!
|
||||
str x25, [sp, #-0x10]!
|
||||
orr x27, xzr, #0x180
|
||||
str x27, [sp, #-0x10]!
|
||||
udf
|
||||
`,
|
||||
},
|
||||
} {
|
||||
@@ -92,6 +121,7 @@ func TestMachine_SetupPrologue(t *testing.T) {
|
||||
func TestMachine_SetupEpilogue(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
exp string
|
||||
abi abiImpl
|
||||
clobberedRegs []regalloc.VReg
|
||||
spillSlotSize int64
|
||||
}{
|
||||
@@ -117,6 +147,18 @@ func TestMachine_SetupEpilogue(t *testing.T) {
|
||||
{
|
||||
exp: `
|
||||
add sp, sp, #0x10
|
||||
add sp, sp, #0x50
|
||||
ldr x30, [sp], #0x10
|
||||
add sp, sp, #0x20
|
||||
ret
|
||||
`,
|
||||
abi: abiImpl{argStackSize: 16, retStackSize: 16},
|
||||
spillSlotSize: 16 * 5,
|
||||
clobberedRegs: nil,
|
||||
},
|
||||
{
|
||||
exp: `
|
||||
add sp, sp, #0x10
|
||||
ldr q27, [sp], #0x10
|
||||
ldr q18, [sp], #0x10
|
||||
ldr x30, [sp], #0x10
|
||||
@@ -150,12 +192,29 @@ func TestMachine_SetupEpilogue(t *testing.T) {
|
||||
spillSlotSize: 16 * 10,
|
||||
clobberedRegs: []regalloc.VReg{v18VReg, v27VReg, x18VReg, x25VReg},
|
||||
},
|
||||
{
|
||||
exp: `
|
||||
add sp, sp, #0x10
|
||||
ldr x25, [sp], #0x10
|
||||
ldr x18, [sp], #0x10
|
||||
ldr q27, [sp], #0x10
|
||||
ldr q18, [sp], #0x10
|
||||
add sp, sp, #0xa0
|
||||
ldr x30, [sp], #0x10
|
||||
add sp, sp, #0x150
|
||||
ret
|
||||
`,
|
||||
spillSlotSize: 16 * 10,
|
||||
abi: abiImpl{argStackSize: 16, retStackSize: 320},
|
||||
clobberedRegs: []regalloc.VReg{v18VReg, v27VReg, x18VReg, x25VReg},
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.exp, func(t *testing.T) {
|
||||
ctx, _, m := newSetupWithMockContext()
|
||||
m.spillSlotSize = tc.spillSlotSize
|
||||
m.clobberedRegs = tc.clobberedRegs
|
||||
m.currentABI = &tc.abi
|
||||
|
||||
root := m.allocateNop()
|
||||
m.rootInstr = root
|
||||
|
||||
@@ -288,7 +288,7 @@ func (m *machine) insertStoreRegisterAt(v regalloc.VReg, instr *instruction, aft
|
||||
|
||||
offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size())
|
||||
var amode addressMode
|
||||
cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg)
|
||||
cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true)
|
||||
store := m.allocateInstr()
|
||||
store.asStore(operandNR(v), amode, typ.Bits())
|
||||
|
||||
@@ -312,7 +312,7 @@ func (m *machine) insertReloadRegisterAt(v regalloc.VReg, instr *instruction, af
|
||||
|
||||
offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size())
|
||||
var amode addressMode
|
||||
cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg)
|
||||
cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true)
|
||||
load := m.allocateInstr()
|
||||
switch typ {
|
||||
case ssa.TypeI32, ssa.TypeI64:
|
||||
|
||||
@@ -37,33 +37,35 @@ type testCase struct {
|
||||
}
|
||||
|
||||
var tests = map[string]testCase{
|
||||
"huge stack": {f: testHugeStack},
|
||||
"unreachable": {f: testUnreachable},
|
||||
"recursive entry": {f: testRecursiveEntry},
|
||||
"host func memory": {f: testHostFuncMemory},
|
||||
"host function with context parameter": {f: testHostFunctionContextParameter},
|
||||
"host function with nested context": {f: testNestedGoContext},
|
||||
"host function with numeric parameter": {f: testHostFunctionNumericParameter},
|
||||
"close module with in-flight calls": {f: testCloseInFlight},
|
||||
"multiple instantiation from same source": {f: testMultipleInstantiation},
|
||||
"exported function that grows memory": {f: testMemOps},
|
||||
"import functions with reference type in signature": {f: testReftypeImports, wazevoSkip: true},
|
||||
"overflow integer addition": {f: testOverflow},
|
||||
"un-signed extend global": {f: testGlobalExtend},
|
||||
"user-defined primitive in host func": {f: testUserDefinedPrimitiveHostFunc},
|
||||
"ensures invocations terminate on module close": {f: testEnsureTerminationOnClose},
|
||||
"call host function indirectly": {f: callHostFunctionIndirect},
|
||||
"lookup function": {f: testLookupFunction},
|
||||
"memory grow in recursive call": {f: testMemoryGrowInRecursiveCall},
|
||||
"call": {f: testCall},
|
||||
"module memory": {f: testModuleMemory, wazevoSkip: true},
|
||||
"two indirection to host": {f: testTwoIndirection},
|
||||
"before listener globals": {f: testBeforeListenerGlobals},
|
||||
"before listener stack iterator": {f: testBeforeListenerStackIterator},
|
||||
"before listener stack iterator offsets": {f: testListenerStackIteratorOffset, wazevoSkip: true},
|
||||
"many params many results / doubler": {f: testManyParamsResultsDoubler},
|
||||
"many params many results / swapper": {f: testManyParamsResultsSwapper},
|
||||
"many params many results / main": {f: testManyParamsResultsMain, wazevoSkip: true},
|
||||
"huge stack": {f: testHugeStack},
|
||||
"unreachable": {f: testUnreachable},
|
||||
"recursive entry": {f: testRecursiveEntry},
|
||||
"host func memory": {f: testHostFuncMemory},
|
||||
"host function with context parameter": {f: testHostFunctionContextParameter},
|
||||
"host function with nested context": {f: testNestedGoContext},
|
||||
"host function with numeric parameter": {f: testHostFunctionNumericParameter},
|
||||
"close module with in-flight calls": {f: testCloseInFlight},
|
||||
"multiple instantiation from same source": {f: testMultipleInstantiation},
|
||||
"exported function that grows memory": {f: testMemOps},
|
||||
"import functions with reference type in signature": {f: testReftypeImports, wazevoSkip: true},
|
||||
"overflow integer addition": {f: testOverflow},
|
||||
"un-signed extend global": {f: testGlobalExtend},
|
||||
"user-defined primitive in host func": {f: testUserDefinedPrimitiveHostFunc},
|
||||
"ensures invocations terminate on module close": {f: testEnsureTerminationOnClose},
|
||||
"call host function indirectly": {f: callHostFunctionIndirect},
|
||||
"lookup function": {f: testLookupFunction},
|
||||
"memory grow in recursive call": {f: testMemoryGrowInRecursiveCall},
|
||||
"call": {f: testCall},
|
||||
"module memory": {f: testModuleMemory, wazevoSkip: true},
|
||||
"two indirection to host": {f: testTwoIndirection},
|
||||
"before listener globals": {f: testBeforeListenerGlobals},
|
||||
"before listener stack iterator": {f: testBeforeListenerStackIterator},
|
||||
"before listener stack iterator offsets": {f: testListenerStackIteratorOffset, wazevoSkip: true},
|
||||
"many params many results / doubler": {f: testManyParamsResultsDoubler},
|
||||
"many params many results / call_many_consts": {f: testManyParamsResultsCallManyConsts},
|
||||
"many params many results / swapper": {f: testManyParamsResultsSwapper},
|
||||
"many params many results / main": {f: testManyParamsResultsMain},
|
||||
"many params many results / call_many_consts_and_pick_last_vector": {f: testManyParamsResultsCallManyConstsAndPickLastVector},
|
||||
}
|
||||
|
||||
func TestEngineCompiler(t *testing.T) {
|
||||
@@ -1624,6 +1626,10 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
|
||||
mainType := wasm.FunctionType{}
|
||||
swapperType := wasm.FunctionType{}
|
||||
doublerType := wasm.FunctionType{}
|
||||
manyConstsType := wasm.FunctionType{}
|
||||
callManyConstsType := wasm.FunctionType{}
|
||||
pickLastVectorType := wasm.FunctionType{Results: []wasm.ValueType{v128}}
|
||||
callManyConstsAndPickLastVectorType := wasm.FunctionType{Results: []wasm.ValueType{v128}}
|
||||
for i := 0; i < 20; i++ {
|
||||
swapperType.Params = append(swapperType.Params, i32, i64, f32, f64, v128)
|
||||
swapperType.Results = append(swapperType.Results, v128, f64, f32, i64, i32)
|
||||
@@ -1631,6 +1637,9 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
|
||||
mainType.Results = append(mainType.Results, v128, f64, f32, i64, i32)
|
||||
doublerType.Params = append(doublerType.Results, v128, f64, f32, i64, i32)
|
||||
doublerType.Results = append(doublerType.Results, v128, f64, f32, i64, i32)
|
||||
manyConstsType.Results = append(manyConstsType.Results, i32, i64, f32, f64, v128)
|
||||
callManyConstsType.Results = append(callManyConstsType.Results, i32, i64, f32, f64, v128)
|
||||
pickLastVectorType.Params = append(pickLastVectorType.Params, i32, i64, f32, f64, v128)
|
||||
}
|
||||
|
||||
var mainBody []byte
|
||||
@@ -1681,15 +1690,50 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
|
||||
}
|
||||
doublerBody = append(doublerBody, wasm.OpcodeEnd)
|
||||
|
||||
var manyConstsBody []byte
|
||||
for i := 0; i < 100; i += 5 {
|
||||
ib := byte(i)
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeI32Const)
|
||||
manyConstsBody = append(manyConstsBody, leb128.EncodeInt32(int32(i))...)
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeI64Const)
|
||||
manyConstsBody = append(manyConstsBody, leb128.EncodeInt64(int64(i))...)
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeF32Const)
|
||||
manyConstsBody = append(manyConstsBody, ib, ib, ib, ib)
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeF64Const)
|
||||
manyConstsBody = append(manyConstsBody, ib, ib, ib, ib, ib, ib, ib, ib)
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const)
|
||||
manyConstsBody = append(manyConstsBody, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib)
|
||||
}
|
||||
manyConstsBody = append(manyConstsBody, wasm.OpcodeEnd)
|
||||
|
||||
var callManyConstsBody []byte
|
||||
callManyConstsBody = append(callManyConstsBody, wasm.OpcodeCall, 5, wasm.OpcodeEnd)
|
||||
|
||||
var pickLastVector []byte
|
||||
pickLastVector = append(pickLastVector, wasm.OpcodeLocalGet, 99, wasm.OpcodeEnd)
|
||||
|
||||
var callManyConstsAndPickLastVector []byte
|
||||
callManyConstsAndPickLastVector = append(callManyConstsAndPickLastVector, wasm.OpcodeCall, 5, wasm.OpcodeCall, 6, wasm.OpcodeEnd)
|
||||
|
||||
bin = binaryencoding.EncodeModule(&wasm.Module{
|
||||
TypeSection: []wasm.FunctionType{mainType, swapperType, doublerType},
|
||||
TypeSection: []wasm.FunctionType{mainType, swapperType, doublerType, callManyConstsType, callManyConstsAndPickLastVectorType, manyConstsType, pickLastVectorType},
|
||||
ExportSection: []wasm.Export{
|
||||
{Name: "main", Type: wasm.ExternTypeFunc, Index: 0},
|
||||
{Name: "swapper", Type: wasm.ExternTypeFunc, Index: 1},
|
||||
{Name: "doubler", Type: wasm.ExternTypeFunc, Index: 2},
|
||||
{Name: "call_many_consts", Type: wasm.ExternTypeFunc, Index: 3},
|
||||
{Name: "call_many_consts_and_pick_last_vector", Type: wasm.ExternTypeFunc, Index: 4},
|
||||
},
|
||||
FunctionSection: []wasm.Index{0, 1, 2, 3, 4, 5, 6},
|
||||
CodeSection: []wasm.Code{
|
||||
{Body: mainBody},
|
||||
{Body: swapperBody},
|
||||
{Body: doublerBody},
|
||||
{Body: callManyConstsBody},
|
||||
{Body: callManyConstsAndPickLastVector},
|
||||
{Body: manyConstsBody},
|
||||
{Body: pickLastVector},
|
||||
},
|
||||
FunctionSection: []wasm.Index{0, 1, 2},
|
||||
CodeSection: []wasm.Code{{Body: mainBody}, {Body: swapperBody}, {Body: doublerBody}},
|
||||
})
|
||||
|
||||
for i := 0; i < 100; i += 5 {
|
||||
@@ -1704,6 +1748,38 @@ func manyParamsResultsMod() (bin []byte, params []uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
func testManyParamsResultsCallManyConsts(t *testing.T, r wazero.Runtime) {
|
||||
bin, _ := manyParamsResultsMod()
|
||||
mod, err := r.Instantiate(testCtx, bin)
|
||||
require.NoError(t, err)
|
||||
|
||||
main := mod.ExportedFunction("call_many_consts")
|
||||
require.NotNil(t, main)
|
||||
|
||||
results, err := main.Call(testCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
exp := []uint64{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5050505, 0x505050505050505, 0x505050505050505,
|
||||
0x505050505050505, 0xa, 0xa, 0xa0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a,
|
||||
0xf, 0xf, 0xf0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0x14, 0x14, 0x14141414,
|
||||
0x1414141414141414, 0x1414141414141414, 0x1414141414141414, 0x19, 0x19, 0x19191919, 0x1919191919191919,
|
||||
0x1919191919191919, 0x1919191919191919, 0x1e, 0x1e, 0x1e1e1e1e, 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e,
|
||||
0x1e1e1e1e1e1e1e1e, 0x23, 0x23, 0x23232323, 0x2323232323232323, 0x2323232323232323, 0x2323232323232323,
|
||||
0x28, 0x28, 0x28282828, 0x2828282828282828, 0x2828282828282828, 0x2828282828282828, 0x2d, 0x2d, 0x2d2d2d2d,
|
||||
0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x32, 0x32, 0x32323232, 0x3232323232323232,
|
||||
0x3232323232323232, 0x3232323232323232, 0x37, 0x37, 0x37373737, 0x3737373737373737, 0x3737373737373737,
|
||||
0x3737373737373737, 0x3c, 0x3c, 0x3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c,
|
||||
0x41, 0x41, 0x41414141, 0x4141414141414141, 0x4141414141414141, 0x4141414141414141, 0x46, 0x46, 0x46464646,
|
||||
0x4646464646464646, 0x4646464646464646, 0x4646464646464646, 0x4b, 0x4b, 0x4b4b4b4b, 0x4b4b4b4b4b4b4b4b,
|
||||
0x4b4b4b4b4b4b4b4b, 0x4b4b4b4b4b4b4b4b, 0x50, 0x50, 0x50505050, 0x5050505050505050, 0x5050505050505050,
|
||||
0x5050505050505050, 0x55, 0x55, 0x55555555, 0x5555555555555555, 0x5555555555555555, 0x5555555555555555,
|
||||
0x5a, 0x5a, 0x5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5f, 0x5f, 0x5f5f5f5f,
|
||||
0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f,
|
||||
}
|
||||
require.Equal(t, exp, results)
|
||||
}
|
||||
|
||||
func testManyParamsResultsDoubler(t *testing.T, r wazero.Runtime) {
|
||||
bin, params := manyParamsResultsMod()
|
||||
mod, err := r.Instantiate(testCtx, bin)
|
||||
@@ -1771,3 +1847,17 @@ func testManyParamsResultsMain(t *testing.T, r wazero.Runtime) {
|
||||
}
|
||||
require.Equal(t, exp, results)
|
||||
}
|
||||
|
||||
func testManyParamsResultsCallManyConstsAndPickLastVector(t *testing.T, r wazero.Runtime) {
|
||||
bin, _ := manyParamsResultsMod()
|
||||
mod, err := r.Instantiate(testCtx, bin)
|
||||
require.NoError(t, err)
|
||||
|
||||
main := mod.ExportedFunction("call_many_consts_and_pick_last_vector")
|
||||
require.NotNil(t, main)
|
||||
|
||||
results, err := main.Call(testCtx)
|
||||
require.NoError(t, err)
|
||||
exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f}
|
||||
require.Equal(t, exp, results)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user