wazevo: passes all many params/results tests (#1727)

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
Takeshi Yoneda
2023-09-20 16:24:30 +09:00
committed by GitHub
parent 13cbdc4821
commit 103e223d1d
11 changed files with 473 additions and 1360 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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()))
})
}
}

View File

@@ -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]

View File

@@ -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]

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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)
}