Repository: tetratelabs/wazero
Pull request #1727 (2023-09-20 05:37:10)

wazevo: passes all many params/results tests
#1496 


Patch:
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi.go b/internal/engine/wazevo/backend/isa/arm64/abi.go
index 80a96a3d..f410174a 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi.go
@@ -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) {
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go
index c41bd04e..0cec5cf5 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go
@@ -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.
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
index 6d300d50..f80fb2ee 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
@@ -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]
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
index b6c02a35..e24c48de 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue.go
@@ -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)
 }
 
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go b/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
index 76349491..5f46842a 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go
@@ -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:


Test patch:
diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go
index 1912f3ad..ce901e19 100644
--- a/internal/engine/wazevo/backend/backend_test.go
+++ b/internal/engine/wazevo/backend/backend_test.go
@@ -682,7 +682,6 @@ L1 (SSA Block: blk0):
 	mov v4?.8b, v0.8b
 	mov v5?.8b, v1.8b
 	str x1?, [x0?, #0x8]
-	sub sp, sp, #0xd0
 	mov x0, x0?
 	mov x1, x1?
 	mov x2, x2?
@@ -697,36 +696,35 @@ L1 (SSA Block: blk0):
 	mov x7, x3?
 	mov v4.8b, v4?.8b
 	mov v5.8b, v5?.8b
-	str w2?, [sp]
-	str x3?, [sp, #0x8]
+	str w2?, [sp, #-0xd0]
+	str x3?, [sp, #-0xc8]
 	mov v6.8b, v4?.8b
 	mov v7.8b, v5?.8b
-	str w2?, [sp, #0x10]
-	str x3?, [sp, #0x18]
-	str s4?, [sp, #0x20]
-	str d5?, [sp, #0x28]
-	str w2?, [sp, #0x30]
-	str x3?, [sp, #0x38]
-	str s4?, [sp, #0x40]
-	str d5?, [sp, #0x48]
-	str w2?, [sp, #0x50]
-	str x3?, [sp, #0x58]
-	str s4?, [sp, #0x60]
-	str d5?, [sp, #0x68]
-	str w2?, [sp, #0x70]
-	str x3?, [sp, #0x78]
-	str s4?, [sp, #0x80]
-	str d5?, [sp, #0x88]
-	str w2?, [sp, #0x90]
-	str x3?, [sp, #0x98]
-	str s4?, [sp, #0xa0]
-	str d5?, [sp, #0xa8]
-	str w2?, [sp, #0xb0]
-	str x3?, [sp, #0xb8]
-	str s4?, [sp, #0xc0]
-	str d5?, [sp, #0xc8]
+	str w2?, [sp, #-0xc0]
+	str x3?, [sp, #-0xb8]
+	str s4?, [sp, #-0xb0]
+	str d5?, [sp, #-0xa8]
+	str w2?, [sp, #-0xa0]
+	str x3?, [sp, #-0x98]
+	str s4?, [sp, #-0x90]
+	str d5?, [sp, #-0x88]
+	str w2?, [sp, #-0x80]
+	str x3?, [sp, #-0x78]
+	str s4?, [sp, #-0x70]
+	str d5?, [sp, #-0x68]
+	str w2?, [sp, #-0x60]
+	str x3?, [sp, #-0x58]
+	str s4?, [sp, #-0x50]
+	str d5?, [sp, #-0x48]
+	str w2?, [sp, #-0x40]
+	str x3?, [sp, #-0x38]
+	str s4?, [sp, #-0x30]
+	str d5?, [sp, #-0x28]
+	str w2?, [sp, #-0x20]
+	str x3?, [sp, #-0x18]
+	str s4?, [sp, #-0x10]
+	str d5?, [sp, #-0x8]
 	bl f1
-	add sp, sp, #0xd0
 	ret
 `,
 			afterFinalizeARM64: `
@@ -738,7 +736,6 @@ L1 (SSA Block: blk0):
 	mov v8.8b, v0.8b
 	mov v9.8b, v1.8b
 	str x1, [x0, #0x8]
-	sub sp, sp, #0xd0
 	mov x2, x8
 	mov x3, x9
 	mov v0.8b, v8.8b
@@ -751,36 +748,35 @@ L1 (SSA Block: blk0):
 	mov x7, x9
 	mov v4.8b, v8.8b
 	mov v5.8b, v9.8b
-	str w8, [sp]
-	str x9, [sp, #0x8]
+	str w8, [sp, #-0xd0]
+	str x9, [sp, #-0xc8]
 	mov v6.8b, v8.8b
 	mov v7.8b, v9.8b
-	str w8, [sp, #0x10]
-	str x9, [sp, #0x18]
-	str s8, [sp, #0x20]
-	str d9, [sp, #0x28]
-	str w8, [sp, #0x30]
-	str x9, [sp, #0x38]
-	str s8, [sp, #0x40]
-	str d9, [sp, #0x48]
-	str w8, [sp, #0x50]
-	str x9, [sp, #0x58]
-	str s8, [sp, #0x60]
-	str d9, [sp, #0x68]
-	str w8, [sp, #0x70]
-	str x9, [sp, #0x78]
-	str s8, [sp, #0x80]
-	str d9, [sp, #0x88]
-	str w8, [sp, #0x90]
-	str x9, [sp, #0x98]
-	str s8, [sp, #0xa0]
-	str d9, [sp, #0xa8]
-	str w8, [sp, #0xb0]
-	str x9, [sp, #0xb8]
-	str s8, [sp, #0xc0]
-	str d9, [sp, #0xc8]
+	str w8, [sp, #-0xc0]
+	str x9, [sp, #-0xb8]
+	str s8, [sp, #-0xb0]
+	str d9, [sp, #-0xa8]
+	str w8, [sp, #-0xa0]
+	str x9, [sp, #-0x98]
+	str s8, [sp, #-0x90]
+	str d9, [sp, #-0x88]
+	str w8, [sp, #-0x80]
+	str x9, [sp, #-0x78]
+	str s8, [sp, #-0x70]
+	str d9, [sp, #-0x68]
+	str w8, [sp, #-0x60]
+	str x9, [sp, #-0x58]
+	str s8, [sp, #-0x50]
+	str d9, [sp, #-0x48]
+	str w8, [sp, #-0x40]
+	str x9, [sp, #-0x38]
+	str s8, [sp, #-0x30]
+	str d9, [sp, #-0x28]
+	str w8, [sp, #-0x20]
+	str x9, [sp, #-0x18]
+	str s8, [sp, #-0x10]
+	str d9, [sp, #-0x8]
 	bl f1
-	add sp, sp, #0xd0
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -797,7 +793,6 @@ L1 (SSA Block: blk0):
 	mov v4?.8b, v0.8b
 	mov v5?.8b, v1.8b
 	str x1?, [x0?, #0x8]
-	sub sp, sp, #0xc0
 	mov x0, x0?
 	mov x1, x1?
 	mov x2, x2?
@@ -821,31 +816,30 @@ L1 (SSA Block: blk0):
 	mov x19?, x7
 	mov v20?.8b, v6.8b
 	mov v21?.8b, v7.8b
-	ldr w22?, [sp]
-	ldr x23?, [sp, #0x8]
-	ldr s24?, [sp, #0x10]
-	ldr d25?, [sp, #0x18]
-	ldr w26?, [sp, #0x20]
-	ldr x27?, [sp, #0x28]
-	ldr s28?, [sp, #0x30]
-	ldr d29?, [sp, #0x38]
-	ldr w30?, [sp, #0x40]
-	ldr x31?, [sp, #0x48]
-	ldr s32?, [sp, #0x50]
-	ldr d33?, [sp, #0x58]
-	ldr w34?, [sp, #0x60]
-	ldr x35?, [sp, #0x68]
-	ldr s36?, [sp, #0x70]
-	ldr d37?, [sp, #0x78]
-	ldr w38?, [sp, #0x80]
-	ldr x39?, [sp, #0x88]
-	ldr s40?, [sp, #0x90]
-	ldr d41?, [sp, #0x98]
-	ldr w42?, [sp, #0xa0]
-	ldr x43?, [sp, #0xa8]
-	ldr s44?, [sp, #0xb0]
-	ldr d45?, [sp, #0xb8]
-	add sp, sp, #0xc0
+	ldr w22?, [sp, #-0xc0]
+	ldr x23?, [sp, #-0xb8]
+	ldr s24?, [sp, #-0xb0]
+	ldr d25?, [sp, #-0xa8]
+	ldr w26?, [sp, #-0xa0]
+	ldr x27?, [sp, #-0x98]
+	ldr s28?, [sp, #-0x90]
+	ldr d29?, [sp, #-0x88]
+	ldr w30?, [sp, #-0x80]
+	ldr x31?, [sp, #-0x78]
+	ldr s32?, [sp, #-0x70]
+	ldr d33?, [sp, #-0x68]
+	ldr w34?, [sp, #-0x60]
+	ldr x35?, [sp, #-0x58]
+	ldr s36?, [sp, #-0x50]
+	ldr d37?, [sp, #-0x48]
+	ldr w38?, [sp, #-0x40]
+	ldr x39?, [sp, #-0x38]
+	ldr s40?, [sp, #-0x30]
+	ldr d41?, [sp, #-0x28]
+	ldr w42?, [sp, #-0x20]
+	ldr x43?, [sp, #-0x18]
+	ldr s44?, [sp, #-0x10]
+	ldr d45?, [sp, #-0x8]
 	str d45?, [#ret_space, #0xb8]
 	str s44?, [#ret_space, #0xb0]
 	str x43?, [#ret_space, #0xa8]
@@ -891,6 +885,7 @@ L1 (SSA Block: blk0):
 			afterFinalizeARM64: `
 L1 (SSA Block: blk0):
 	orr x27, xzr, #0xc0
+	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
 	str x19, [sp, #-0x10]!
 	str q18, [sp, #-0x10]!
@@ -898,33 +893,31 @@ L1 (SSA Block: blk0):
 	orr x27, xzr, #0x30
 	str x27, [sp, #-0x10]!
 	str x1, [x0, #0x8]
-	sub sp, sp, #0xc0
 	bl f1
-	ldr w19, [sp]
-	ldr x18, [sp, #0x8]
-	ldr s19, [sp, #0x10]
-	ldr d18, [sp, #0x18]
-	ldr w17, [sp, #0x20]
-	ldr x16, [sp, #0x28]
-	ldr s17, [sp, #0x30]
-	ldr d16, [sp, #0x38]
-	ldr w15, [sp, #0x40]
-	ldr x14, [sp, #0x48]
-	ldr s15, [sp, #0x50]
-	ldr d14, [sp, #0x58]
-	ldr w13, [sp, #0x60]
-	ldr x12, [sp, #0x68]
-	ldr s13, [sp, #0x70]
-	ldr d12, [sp, #0x78]
-	ldr w11, [sp, #0x80]
-	ldr x10, [sp, #0x88]
-	ldr s11, [sp, #0x90]
-	ldr d10, [sp, #0x98]
-	ldr w9, [sp, #0xa0]
-	ldr x8, [sp, #0xa8]
-	ldr s9, [sp, #0xb0]
-	ldr d8, [sp, #0xb8]
-	add sp, sp, #0xc0
+	ldr w19, [sp, #-0xc0]
+	ldr x18, [sp, #-0xb8]
+	ldr s19, [sp, #-0xb0]
+	ldr d18, [sp, #-0xa8]
+	ldr w17, [sp, #-0xa0]
+	ldr x16, [sp, #-0x98]
+	ldr s17, [sp, #-0x90]
+	ldr d16, [sp, #-0x88]
+	ldr w15, [sp, #-0x80]
+	ldr x14, [sp, #-0x78]
+	ldr s15, [sp, #-0x70]
+	ldr d14, [sp, #-0x68]
+	ldr w13, [sp, #-0x60]
+	ldr x12, [sp, #-0x58]
+	ldr s13, [sp, #-0x50]
+	ldr d12, [sp, #-0x48]
+	ldr w11, [sp, #-0x40]
+	ldr x10, [sp, #-0x38]
+	ldr s11, [sp, #-0x30]
+	ldr d10, [sp, #-0x28]
+	ldr w9, [sp, #-0x20]
+	ldr x8, [sp, #-0x18]
+	ldr s9, [sp, #-0x10]
+	ldr d8, [sp, #-0x8]
 	str d8, [sp, #0x108]
 	str s9, [sp, #0x100]
 	str x8, [sp, #0xf8]
@@ -954,566 +947,7 @@ L1 (SSA Block: blk0):
 	ldr q18, [sp], #0x10
 	ldr x19, [sp], #0x10
 	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "many_params_small_results", m: testcases.ManyParamsSmallResults.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x11?, x7
-	ldr s20?, [#arg_space, #0x20]
-	ldr d29?, [#arg_space, #0x68]
-	mov v1.8b, v29?.8b
-	mov v0.8b, v20?.8b
-	mov x1, x11?
-	mov x0, x2?
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	movz x27, #0xd0, lsl 0
-	stp x30, x27, [sp, #-0x10]!
-	str xzr, [sp, #-0x10]!
-	ldr s0, [sp, #0x40]
-	ldr d1, [sp, #0x88]
-	mov x1, x7
-	mov x0, x2
-	add sp, sp, #0x10
-	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "samll_params_many_results", m: testcases.SmallParamsManyResults.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x3?, x3
-	mov v4?.8b, v0.8b
-	mov v5?.8b, v1.8b
-	str d5?, [#ret_space, #0xb8]
-	str s4?, [#ret_space, #0xb0]
-	str x3?, [#ret_space, #0xa8]
-	str w2?, [#ret_space, #0xa0]
-	str d5?, [#ret_space, #0x98]
-	str s4?, [#ret_space, #0x90]
-	str x3?, [#ret_space, #0x88]
-	str w2?, [#ret_space, #0x80]
-	str d5?, [#ret_space, #0x78]
-	str s4?, [#ret_space, #0x70]
-	str x3?, [#ret_space, #0x68]
-	str w2?, [#ret_space, #0x60]
-	str d5?, [#ret_space, #0x58]
-	str s4?, [#ret_space, #0x50]
-	str x3?, [#ret_space, #0x48]
-	str w2?, [#ret_space, #0x40]
-	str d5?, [#ret_space, #0x38]
-	str s4?, [#ret_space, #0x30]
-	str x3?, [#ret_space, #0x28]
-	str w2?, [#ret_space, #0x20]
-	str d5?, [#ret_space, #0x18]
-	str s4?, [#ret_space, #0x10]
-	str x3?, [#ret_space, #0x8]
-	str w2?, [#ret_space, #0x0]
-	mov v7.8b, v5?.8b
-	mov v6.8b, v4?.8b
-	mov x7, x3?
-	mov x6, x2?
-	mov v5.8b, v5?.8b
-	mov v4.8b, v4?.8b
-	mov x5, x3?
-	mov x4, x2?
-	mov v3.8b, v5?.8b
-	mov v2.8b, v4?.8b
-	mov x3, x3?
-	mov x2, x2?
-	mov v1.8b, v5?.8b
-	mov v0.8b, v4?.8b
-	mov x1, x3?
-	mov x0, x2?
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	orr x27, xzr, #0xc0
-	stp x30, x27, [sp, #-0x10]!
-	str xzr, [sp, #-0x10]!
-	mov x0, x2
-	mov x1, x3
-	str d1, [sp, #0xd8]
-	str s0, [sp, #0xd0]
-	str x1, [sp, #0xc8]
-	str w0, [sp, #0xc0]
-	str d1, [sp, #0xb8]
-	str s0, [sp, #0xb0]
-	str x1, [sp, #0xa8]
-	str w0, [sp, #0xa0]
-	str d1, [sp, #0x98]
-	str s0, [sp, #0x90]
-	str x1, [sp, #0x88]
-	str w0, [sp, #0x80]
-	str d1, [sp, #0x78]
-	str s0, [sp, #0x70]
-	str x1, [sp, #0x68]
-	str w0, [sp, #0x60]
-	str d1, [sp, #0x58]
-	str s0, [sp, #0x50]
-	str x1, [sp, #0x48]
-	str w0, [sp, #0x40]
-	str d1, [sp, #0x38]
-	str s0, [sp, #0x30]
-	str x1, [sp, #0x28]
-	str w0, [sp, #0x20]
-	mov v7.8b, v1.8b
-	mov v6.8b, v0.8b
-	mov x7, x1
-	mov x6, x0
-	mov v5.8b, v1.8b
-	mov v4.8b, v0.8b
-	mov x5, x1
-	mov x4, x0
-	mov v3.8b, v1.8b
-	mov v2.8b, v0.8b
-	mov x3, x1
-	mov x2, x0
-	add sp, sp, #0x10
-	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "many_params_many_results", m: testcases.ManyParamsManyResults.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x3?, x3
-	mov v4?.8b, v0.8b
-	mov v5?.8b, v1.8b
-	mov x6?, x4
-	mov x7?, x5
-	mov v8?.8b, v2.8b
-	mov v9?.8b, v3.8b
-	mov x10?, x6
-	mov x11?, x7
-	mov v12?.8b, v4.8b
-	mov v13?.8b, v5.8b
-	ldr w14?, [#arg_space, #0x0]
-	ldr x15?, [#arg_space, #0x8]
-	mov v16?.8b, v6.8b
-	mov v17?.8b, v7.8b
-	ldr w18?, [#arg_space, #0x10]
-	ldr x19?, [#arg_space, #0x18]
-	ldr s20?, [#arg_space, #0x20]
-	ldr d21?, [#arg_space, #0x28]
-	ldr w22?, [#arg_space, #0x30]
-	ldr x23?, [#arg_space, #0x38]
-	ldr s24?, [#arg_space, #0x40]
-	ldr d25?, [#arg_space, #0x48]
-	ldr w26?, [#arg_space, #0x50]
-	ldr x27?, [#arg_space, #0x58]
-	ldr s28?, [#arg_space, #0x60]
-	ldr d29?, [#arg_space, #0x68]
-	ldr w30?, [#arg_space, #0x70]
-	ldr x31?, [#arg_space, #0x78]
-	ldr s32?, [#arg_space, #0x80]
-	ldr d33?, [#arg_space, #0x88]
-	ldr w34?, [#arg_space, #0x90]
-	ldr x35?, [#arg_space, #0x98]
-	ldr s36?, [#arg_space, #0xa0]
-	ldr d37?, [#arg_space, #0xa8]
-	ldr w38?, [#arg_space, #0xb0]
-	ldr x39?, [#arg_space, #0xb8]
-	ldr s40?, [#arg_space, #0xc0]
-	ldr d41?, [#arg_space, #0xc8]
-	str w2?, [#ret_space, #0xb8]
-	str x3?, [#ret_space, #0xb0]
-	str s4?, [#ret_space, #0xa8]
-	str d5?, [#ret_space, #0xa0]
-	str w6?, [#ret_space, #0x98]
-	str x7?, [#ret_space, #0x90]
-	str s8?, [#ret_space, #0x88]
-	str d9?, [#ret_space, #0x80]
-	str w10?, [#ret_space, #0x78]
-	str x11?, [#ret_space, #0x70]
-	str s12?, [#ret_space, #0x68]
-	str d13?, [#ret_space, #0x60]
-	str w14?, [#ret_space, #0x58]
-	str x15?, [#ret_space, #0x50]
-	str s16?, [#ret_space, #0x48]
-	str d17?, [#ret_space, #0x40]
-	str w18?, [#ret_space, #0x38]
-	str x19?, [#ret_space, #0x30]
-	str s20?, [#ret_space, #0x28]
-	str d21?, [#ret_space, #0x20]
-	str w22?, [#ret_space, #0x18]
-	str x23?, [#ret_space, #0x10]
-	str s24?, [#ret_space, #0x8]
-	str d25?, [#ret_space, #0x0]
-	mov x7, x26?
-	mov x6, x27?
-	mov v7.8b, v28?.8b
-	mov v6.8b, v29?.8b
-	mov x5, x30?
-	mov x4, x31?
-	mov v5.8b, v32?.8b
-	mov v4.8b, v33?.8b
-	mov x3, x34?
-	mov x2, x35?
-	mov v3.8b, v36?.8b
-	mov v2.8b, v37?.8b
-	mov x1, x38?
-	mov x0, x39?
-	mov v1.8b, v40?.8b
-	mov v0.8b, v41?.8b
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	movz x27, #0x190, lsl 0
-	stp x30, x27, [sp, #-0x10]!
-	str x19, [sp, #-0x10]!
-	str q18, [sp, #-0x10]!
-	str q19, [sp, #-0x10]!
-	orr x27, xzr, #0x30
-	str x27, [sp, #-0x10]!
-	mov x8, x2
-	mov x9, x3
-	mov v8.8b, v0.8b
-	mov v9.8b, v1.8b
-	mov x10, x4
-	mov x11, x5
-	mov v10.8b, v2.8b
-	mov v11.8b, v3.8b
-	mov x12, x6
-	mov x19, x7
-	mov v12.8b, v4.8b
-	mov v13.8b, v5.8b
-	ldr w18, [sp, #0x50]
-	ldr x17, [sp, #0x58]
-	mov v14.8b, v6.8b
-	mov v19.8b, v7.8b
-	ldr w16, [sp, #0x60]
-	ldr x15, [sp, #0x68]
-	ldr s18, [sp, #0x70]
-	ldr d17, [sp, #0x78]
-	ldr w14, [sp, #0x80]
-	ldr x13, [sp, #0x88]
-	ldr s16, [sp, #0x90]
-	ldr d15, [sp, #0x98]
-	ldr w7, [sp, #0xa0]
-	ldr x6, [sp, #0xa8]
-	ldr s7, [sp, #0xb0]
-	ldr d6, [sp, #0xb8]
-	ldr w5, [sp, #0xc0]
-	ldr x4, [sp, #0xc8]
-	ldr s5, [sp, #0xd0]
-	ldr d4, [sp, #0xd8]
-	ldr w3, [sp, #0xe0]
-	ldr x2, [sp, #0xe8]
-	ldr s3, [sp, #0xf0]
-	ldr d2, [sp, #0xf8]
-	ldr w1, [sp, #0x100]
-	ldr x0, [sp, #0x108]
-	ldr s1, [sp, #0x110]
-	ldr d0, [sp, #0x118]
-	str w8, [sp, #0x1d8]
-	str x9, [sp, #0x1d0]
-	str s8, [sp, #0x1c8]
-	str d9, [sp, #0x1c0]
-	str w10, [sp, #0x1b8]
-	str x11, [sp, #0x1b0]
-	str s10, [sp, #0x1a8]
-	str d11, [sp, #0x1a0]
-	str w12, [sp, #0x198]
-	str x19, [sp, #0x190]
-	str s12, [sp, #0x188]
-	str d13, [sp, #0x180]
-	str w18, [sp, #0x178]
-	str x17, [sp, #0x170]
-	str s14, [sp, #0x168]
-	str d19, [sp, #0x160]
-	str w16, [sp, #0x158]
-	str x15, [sp, #0x150]
-	str s18, [sp, #0x148]
-	str d17, [sp, #0x140]
-	str w14, [sp, #0x138]
-	str x13, [sp, #0x130]
-	str s16, [sp, #0x128]
-	str d15, [sp, #0x120]
-	add sp, sp, #0x10
-	ldr q19, [sp], #0x10
-	ldr q18, [sp], #0x10
-	ldr x19, [sp], #0x10
-	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "integer_comparisons",
-			m:    testcases.IntegerComparisons.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x3?, x3
-	mov x4?, x4
-	mov x5?, x5
-	subs wzr, w2?, w3?
-	cset x6?, eq
-	subs xzr, x4?, x5?
-	cset x7?, eq
-	subs wzr, w2?, w3?
-	cset x8?, ne
-	subs xzr, x4?, x5?
-	cset x9?, ne
-	subs wzr, w2?, w3?
-	cset x10?, lt
-	subs xzr, x4?, x5?
-	cset x11?, lt
-	subs wzr, w2?, w3?
-	cset x12?, lo
-	subs xzr, x4?, x5?
-	cset x13?, lo
-	subs wzr, w2?, w3?
-	cset x14?, gt
-	subs xzr, x4?, x5?
-	cset x15?, gt
-	subs wzr, w2?, w3?
-	cset x16?, hi
-	subs xzr, x4?, x5?
-	cset x17?, hi
-	subs wzr, w2?, w3?
-	cset x18?, le
-	subs xzr, x4?, x5?
-	cset x19?, le
-	subs wzr, w2?, w3?
-	cset x20?, ls
-	subs xzr, x4?, x5?
-	cset x21?, ls
-	subs wzr, w2?, w3?
-	cset x22?, ge
-	subs xzr, x4?, x5?
-	cset x23?, ge
-	subs wzr, w2?, w3?
-	cset x24?, hs
-	subs xzr, x4?, x5?
-	cset x25?, hs
-	str w25?, [#ret_space, #0x58]
-	str w24?, [#ret_space, #0x50]
-	str w23?, [#ret_space, #0x48]
-	str w22?, [#ret_space, #0x40]
-	str w21?, [#ret_space, #0x38]
-	str w20?, [#ret_space, #0x30]
-	str w19?, [#ret_space, #0x28]
-	str w18?, [#ret_space, #0x20]
-	str w17?, [#ret_space, #0x18]
-	str w16?, [#ret_space, #0x10]
-	str w15?, [#ret_space, #0x8]
-	str w14?, [#ret_space, #0x0]
-	mov x7, x13?
-	mov x6, x12?
-	mov x5, x11?
-	mov x4, x10?
-	mov x3, x9?
-	mov x2, x8?
-	mov x1, x7?
-	mov x0, x6?
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	orr x27, xzr, #0x60
-	stp x30, x27, [sp, #-0x10]!
-	str x19, [sp, #-0x10]!
-	str x20, [sp, #-0x10]!
-	str x21, [sp, #-0x10]!
-	orr x27, xzr, #0x30
-	str x27, [sp, #-0x10]!
-	mov x8, x2
-	mov x20, x3
-	mov x19, x4
-	mov x21, x5
-	subs wzr, w8, w20
-	cset x0, eq
-	subs xzr, x19, x21
-	cset x1, eq
-	subs wzr, w8, w20
-	cset x2, ne
-	subs xzr, x19, x21
-	cset x3, ne
-	subs wzr, w8, w20
-	cset x4, lt
-	subs xzr, x19, x21
-	cset x5, lt
-	subs wzr, w8, w20
-	cset x6, lo
-	subs xzr, x19, x21
-	cset x7, lo
-	subs wzr, w8, w20
-	cset x18, gt
-	subs xzr, x19, x21
-	cset x17, gt
-	subs wzr, w8, w20
-	cset x16, hi
-	subs xzr, x19, x21
-	cset x15, hi
-	subs wzr, w8, w20
-	cset x14, le
-	subs xzr, x19, x21
-	cset x13, le
-	subs wzr, w8, w20
-	cset x12, ls
-	subs xzr, x19, x21
-	cset x11, ls
-	subs wzr, w8, w20
-	cset x10, ge
-	subs xzr, x19, x21
-	cset x9, ge
-	subs wzr, w8, w20
-	cset x8, hs
-	subs xzr, x19, x21
-	cset x19, hs
-	str w19, [sp, #0xa8]
-	str w8, [sp, #0xa0]
-	str w9, [sp, #0x98]
-	str w10, [sp, #0x90]
-	str w11, [sp, #0x88]
-	str w12, [sp, #0x80]
-	str w13, [sp, #0x78]
-	str w14, [sp, #0x70]
-	str w15, [sp, #0x68]
-	str w16, [sp, #0x60]
-	str w17, [sp, #0x58]
-	str w18, [sp, #0x50]
-	add sp, sp, #0x10
-	ldr x21, [sp], #0x10
-	ldr x20, [sp], #0x10
-	ldr x19, [sp], #0x10
-	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "integer_bitwise",
-			m:    testcases.IntegerBitwise.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x3?, x3
-	mov x4?, x4
-	mov x5?, x5
-	and w6?, w2?, w3?
-	orr w7?, w2?, w3?
-	eor w8?, w2?, w3?
-	ror w9?, w2?, w3?
-	and x10?, x4?, x5?
-	orr x11?, x4?, x5?
-	eor x12?, x4?, x5?
-	eor x15?, x4?, x5?, lsl #8
-	sub x5?, xzr, x5?
-	ror x16?, x4?, x5?
-	ror x17?, x4?, x5?
-	str x17?, [#ret_space, #0x8]
-	str x16?, [#ret_space, #0x0]
-	mov x7, x15?
-	mov x6, x12?
-	mov x5, x11?
-	mov x4, x10?
-	mov x3, x9?
-	mov x2, x8?
-	mov x1, x7?
-	mov x0, x6?
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	orr x27, xzr, #0x10
-	stp x30, x27, [sp, #-0x10]!
-	str xzr, [sp, #-0x10]!
-	mov x10, x2
-	mov x8, x4
-	mov x9, x5
-	and w0, w10, w3
-	orr w1, w10, w3
-	eor w2, w10, w3
-	ror w3, w10, w3
-	and x4, x8, x9
-	orr x5, x8, x9
-	eor x6, x8, x9
-	eor x7, x8, x9, lsl #8
-	sub x9, xzr, x9
-	ror x10, x8, x9
-	ror x8, x8, x9
-	str x8, [sp, #0x28]
-	str x10, [sp, #0x20]
-	add sp, sp, #0x10
-	ldr x30, [sp], #0x10
-	ret
-`,
-		},
-		{
-			name: "integer_shift",
-			m:    testcases.IntegerShift.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov x2?, x2
-	mov x3?, x3
-	mov x4?, x4
-	mov x5?, x5
-	lsl w6?, w2?, w3?
-	lsl w8?, w2?, 0x1f
-	lsl x9?, x4?, x5?
-	lsl x11?, x4?, 0x20
-	lsr w12?, w2?, w3?
-	lsr w14?, w2?, 0x1f
-	lsr x15?, x4?, x5?
-	lsr x17?, x4?, 0x20
-	asr w18?, w2?, w3?
-	asr w20?, w2?, 0x1f
-	asr x21?, x4?, x5?
-	asr x23?, x4?, 0x20
-	str x23?, [#ret_space, #0x18]
-	str x21?, [#ret_space, #0x10]
-	str w20?, [#ret_space, #0x8]
-	str w18?, [#ret_space, #0x0]
-	mov x7, x17?
-	mov x6, x15?
-	mov x5, x14?
-	mov x4, x12?
-	mov x3, x11?
-	mov x2, x9?
-	mov x1, x8?
-	mov x0, x6?
-	ret
-`,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	orr x27, xzr, #0x20
-	stp x30, x27, [sp, #-0x10]!
-	str xzr, [sp, #-0x10]!
-	mov x9, x2
-	mov x10, x3
-	mov x8, x4
-	mov x11, x5
-	lsl w0, w9, w10
-	lsl w1, w9, 0x1f
-	lsl x2, x8, x11
-	lsl x3, x8, 0x20
-	lsr w4, w9, w10
-	lsr w5, w9, 0x1f
-	lsr x6, x8, x11
-	lsr x7, x8, 0x20
-	asr w10, w9, w10
-	asr w9, w9, 0x1f
-	asr x11, x8, x11
-	asr x8, x8, 0x20
-	str x8, [sp, #0x38]
-	str x11, [sp, #0x30]
-	str w9, [sp, #0x28]
-	str w10, [sp, #0x20]
-	add sp, sp, #0x10
-	ldr x30, [sp], #0x10
+	add sp, sp, #0xc0
 	ret
 `,
 		},
@@ -1613,53 +1047,10 @@ L1 (SSA Block: blk0):
 		{
 			name: "float_comparisons",
 			m:    testcases.FloatComparisons.Module,
-			afterLoweringARM64: `
-L1 (SSA Block: blk0):
-	mov v2?.8b, v0.8b
-	mov v3?.8b, v1.8b
-	mov v4?.8b, v2.8b
-	mov v5?.8b, v3.8b
-	fcmp s2?, s3?
-	cset x6?, eq
-	fcmp s2?, s3?
-	cset x7?, ne
-	fcmp s2?, s3?
-	cset x8?, mi
-	fcmp s2?, s3?
-	cset x9?, gt
-	fcmp s2?, s3?
-	cset x10?, ls
-	fcmp s2?, s3?
-	cset x11?, ge
-	fcmp d4?, d5?
-	cset x12?, eq
-	fcmp d4?, d5?
-	cset x13?, ne
-	fcmp d4?, d5?
-	cset x14?, mi
-	fcmp d4?, d5?
-	cset x15?, gt
-	fcmp d4?, d5?
-	cset x16?, ls
-	fcmp d4?, d5?
-	cset x17?, ge
-	str w17?, [#ret_space, #0x18]
-	str w16?, [#ret_space, #0x10]
-	str w15?, [#ret_space, #0x8]
-	str w14?, [#ret_space, #0x0]
-	mov x7, x13?
-	mov x6, x12?
-	mov x5, x11?
-	mov x4, x10?
-	mov x3, x9?
-	mov x2, x8?
-	mov x1, x7?
-	mov x0, x6?
-	ret
-`,
 			afterFinalizeARM64: `
 L1 (SSA Block: blk0):
 	orr x27, xzr, #0x20
+	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	fcmp s0, s1
@@ -1692,6 +1083,7 @@ L1 (SSA Block: blk0):
 	str w11, [sp, #0x20]
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
+	add sp, sp, #0x20
 	ret
 `,
 		},
@@ -2438,447 +1830,6 @@ L2:
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
-`,
-		},
-		{
-			name: "memory_loads", m: testcases.MemoryLoads.Module,
-			afterFinalizeARM64: `
-L1 (SSA Block: blk0):
-	orr x27, xzr, #0x80
-	stp x30, x27, [sp, #-0x10]!
-	str x19, [sp, #-0x10]!
-	str x20, [sp, #-0x10]!
-	str x21, [sp, #-0x10]!
-	str x22, [sp, #-0x10]!
-	str x23, [sp, #-0x10]!
-	str x24, [sp, #-0x10]!
-	str x25, [sp, #-0x10]!
-	str x26, [sp, #-0x10]!
-	orr x27, xzr, #0x80
-	str x27, [sp, #-0x10]!
-	mov x8, x0
-	mov x24, x2
-	uxtw x11, w24
-	ldr w9, [x1, #0x10]
-	add x10, x11, #0x4
-	subs xzr, x9, x10
-	b.hs #0x34, (L29)
-	movz x10, #0x4, lsl 0
-	str w10, [x8]
-	mov x10, sp
-	str x10, [x8, #0x38]
-	adr x10, #0x0
-	str x10, [x8, #0x30]
-	exit_sequence x8
-L29:
-	ldr x10, [x1, #0x8]
-	add x11, x10, x11
-	ldr w0, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x8
-	subs xzr, x9, x12
-	b.hs #0x34, (L28)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L28:
-	add x11, x10, x11
-	ldr x1, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x4
-	subs xzr, x9, x12
-	b.hs #0x34, (L27)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L27:
-	add x11, x10, x11
-	ldr s0, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x8
-	subs xzr, x9, x12
-	b.hs #0x34, (L26)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L26:
-	add x11, x10, x11
-	ldr d1, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x13
-	subs xzr, x9, x12
-	b.hs #0x34, (L25)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L25:
-	add x11, x10, x11
-	ldr w2, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x17
-	subs xzr, x9, x12
-	b.hs #0x34, (L24)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L24:
-	add x11, x10, x11
-	ldr x3, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x13
-	subs xzr, x9, x12
-	b.hs #0x34, (L23)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L23:
-	add x11, x10, x11
-	ldr s2, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x17
-	subs xzr, x9, x12
-	b.hs #0x34, (L22)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L22:
-	add x11, x10, x11
-	ldr d3, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x1
-	subs xzr, x9, x12
-	b.hs #0x34, (L21)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L21:
-	add x11, x10, x11
-	ldrsb w4, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x10
-	subs xzr, x9, x12
-	b.hs #0x34, (L20)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L20:
-	add x11, x10, x11
-	ldrsb w5, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x1
-	subs xzr, x9, x12
-	b.hs #0x34, (L19)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L19:
-	add x11, x10, x11
-	ldrb w6, [x11]
-	uxtw x11, w24
-	add x12, x11, #0x10
-	subs xzr, x9, x12
-	b.hs #0x34, (L18)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L18:
-	add x11, x10, x11
-	ldrb w7, [x11, #0xf]
-	uxtw x11, w24
-	add x12, x11, #0x2
-	subs xzr, x9, x12
-	b.hs #0x34, (L17)
-	movz x12, #0x4, lsl 0
-	str w12, [x8]
-	mov x12, sp
-	str x12, [x8, #0x38]
-	adr x12, #0x0
-	str x12, [x8, #0x30]
-	exit_sequence x8
-L17:
-	add x11, x10, x11
-	ldrsh w11, [x11]
-	uxtw x12, w24
-	add x13, x12, #0x11
-	subs xzr, x9, x13
-	b.hs #0x34, (L16)
-	movz x13, #0x4, lsl 0
-	str w13, [x8]
-	mov x13, sp
-	str x13, [x8, #0x38]
-	adr x13, #0x0
-	str x13, [x8, #0x30]
-	exit_sequence x8
-L16:
-	add x12, x10, x12
-	ldrsh w12, [x12, #0xf]
-	uxtw x13, w24
-	add x14, x13, #0x2
-	subs xzr, x9, x14
-	b.hs #0x34, (L15)
-	movz x14, #0x4, lsl 0
-	str w14, [x8]
-	mov x14, sp
-	str x14, [x8, #0x38]
-	adr x14, #0x0
-	str x14, [x8, #0x30]
-	exit_sequence x8
-L15:
-	add x13, x10, x13
-	ldrh w13, [x13]
-	uxtw x14, w24
-	add x15, x14, #0x11
-	subs xzr, x9, x15
-	b.hs #0x34, (L14)
-	movz x15, #0x4, lsl 0
-	str w15, [x8]
-	mov x15, sp
-	str x15, [x8, #0x38]
-	adr x15, #0x0
-	str x15, [x8, #0x30]
-	exit_sequence x8
-L14:
-	add x14, x10, x14
-	ldrh w14, [x14, #0xf]
-	uxtw x15, w24
-	add x16, x15, #0x1
-	subs xzr, x9, x16
-	b.hs #0x34, (L13)
-	movz x16, #0x4, lsl 0
-	str w16, [x8]
-	mov x16, sp
-	str x16, [x8, #0x38]
-	adr x16, #0x0
-	str x16, [x8, #0x30]
-	exit_sequence x8
-L13:
-	add x15, x10, x15
-	ldrsb w15, [x15]
-	uxtw x16, w24
-	add x17, x16, #0x10
-	subs xzr, x9, x17
-	b.hs #0x34, (L12)
-	movz x17, #0x4, lsl 0
-	str w17, [x8]
-	mov x17, sp
-	str x17, [x8, #0x38]
-	adr x17, #0x0
-	str x17, [x8, #0x30]
-	exit_sequence x8
-L12:
-	add x16, x10, x16
-	ldrsb w16, [x16, #0xf]
-	uxtw x17, w24
-	add x18, x17, #0x1
-	subs xzr, x9, x18
-	b.hs #0x34, (L11)
-	movz x18, #0x4, lsl 0
-	str w18, [x8]
-	mov x18, sp
-	str x18, [x8, #0x38]
-	adr x18, #0x0
-	str x18, [x8, #0x30]
-	exit_sequence x8
-L11:
-	add x17, x10, x17
-	ldrb w17, [x17]
-	uxtw x18, w24
-	add x19, x18, #0x10
-	subs xzr, x9, x19
-	b.hs #0x34, (L10)
-	movz x19, #0x4, lsl 0
-	str w19, [x8]
-	mov x19, sp
-	str x19, [x8, #0x38]
-	adr x19, #0x0
-	str x19, [x8, #0x30]
-	exit_sequence x8
-L10:
-	add x18, x10, x18
-	ldrb w18, [x18, #0xf]
-	uxtw x19, w24
-	add x20, x19, #0x2
-	subs xzr, x9, x20
-	b.hs #0x34, (L9)
-	movz x20, #0x4, lsl 0
-	str w20, [x8]
-	mov x20, sp
-	str x20, [x8, #0x38]
-	adr x20, #0x0
-	str x20, [x8, #0x30]
-	exit_sequence x8
-L9:
-	add x19, x10, x19
-	ldrsh w19, [x19]
-	uxtw x20, w24
-	add x21, x20, #0x11
-	subs xzr, x9, x21
-	b.hs #0x34, (L8)
-	movz x21, #0x4, lsl 0
-	str w21, [x8]
-	mov x21, sp
-	str x21, [x8, #0x38]
-	adr x21, #0x0
-	str x21, [x8, #0x30]
-	exit_sequence x8
-L8:
-	add x20, x10, x20
-	ldrsh w20, [x20, #0xf]
-	uxtw x21, w24
-	add x22, x21, #0x2
-	subs xzr, x9, x22
-	b.hs #0x34, (L7)
-	movz x22, #0x4, lsl 0
-	str w22, [x8]
-	mov x22, sp
-	str x22, [x8, #0x38]
-	adr x22, #0x0
-	str x22, [x8, #0x30]
-	exit_sequence x8
-L7:
-	add x21, x10, x21
-	ldrh w21, [x21]
-	uxtw x22, w24
-	add x23, x22, #0x11
-	subs xzr, x9, x23
-	b.hs #0x34, (L6)
-	movz x23, #0x4, lsl 0
-	str w23, [x8]
-	mov x23, sp
-	str x23, [x8, #0x38]
-	adr x23, #0x0
-	str x23, [x8, #0x30]
-	exit_sequence x8
-L6:
-	add x22, x10, x22
-	ldrh w22, [x22, #0xf]
-	uxtw x23, w24
-	add x25, x23, #0x4
-	subs xzr, x9, x25
-	b.hs #0x34, (L5)
-	movz x25, #0x4, lsl 0
-	str w25, [x8]
-	mov x25, sp
-	str x25, [x8, #0x38]
-	adr x25, #0x0
-	str x25, [x8, #0x30]
-	exit_sequence x8
-L5:
-	add x23, x10, x23
-	ldrs w23, [x23]
-	uxtw x25, w24
-	add x26, x25, #0x13
-	subs xzr, x9, x26
-	b.hs #0x34, (L4)
-	movz x26, #0x4, lsl 0
-	str w26, [x8]
-	mov x26, sp
-	str x26, [x8, #0x38]
-	adr x26, #0x0
-	str x26, [x8, #0x30]
-	exit_sequence x8
-L4:
-	add x25, x10, x25
-	ldrs w25, [x25, #0xf]
-	uxtw x26, w24
-	add x29, x26, #0x4
-	subs xzr, x9, x29
-	b.hs #0x34, (L3)
-	movz x29, #0x4, lsl 0
-	str w29, [x8]
-	mov x29, sp
-	str x29, [x8, #0x38]
-	adr x29, #0x0
-	str x29, [x8, #0x30]
-	exit_sequence x8
-L3:
-	add x26, x10, x26
-	ldr w26, [x26]
-	uxtw x24, w24
-	add x29, x24, #0x13
-	subs xzr, x9, x29
-	b.hs #0x34, (L2)
-	movz x9, #0x4, lsl 0
-	str w9, [x8]
-	mov x9, sp
-	str x9, [x8, #0x38]
-	adr x9, #0x0
-	str x9, [x8, #0x30]
-	exit_sequence x8
-L2:
-	add x8, x10, x24
-	ldr w8, [x8, #0xf]
-	str x8, [sp, #0x118]
-	str x26, [sp, #0x110]
-	str x25, [sp, #0x108]
-	str x23, [sp, #0x100]
-	str x22, [sp, #0xf8]
-	str x21, [sp, #0xf0]
-	str x20, [sp, #0xe8]
-	str x19, [sp, #0xe0]
-	str x18, [sp, #0xd8]
-	str x17, [sp, #0xd0]
-	str x16, [sp, #0xc8]
-	str x15, [sp, #0xc0]
-	str w14, [sp, #0xb8]
-	str w13, [sp, #0xb0]
-	str w12, [sp, #0xa8]
-	str w11, [sp, #0xa0]
-	add sp, sp, #0x10
-	ldr x26, [sp], #0x10
-	ldr x25, [sp], #0x10
-	ldr x24, [sp], #0x10
-	ldr x23, [sp], #0x10
-	ldr x22, [sp], #0x10
-	ldr x21, [sp], #0x10
-	ldr x20, [sp], #0x10
-	ldr x19, [sp], #0x10
-	ldr x30, [sp], #0x10
-	ret
 `,
 		},
 		{
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
index 2ba3a1c9..054dd625 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble_test.go
@@ -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()))
 		})
 	}
 }
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
index b6d922b7..7abd9f9c 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call_test.go
@@ -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]
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_test.go
index c17daabe..a917a67a 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_test.go
@@ -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
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue_test.go b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue_test.go
index f2899bac..e9f28433 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine_pro_epi_logue_test.go
@@ -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
diff --git a/internal/integration_test/engine/adhoc_test.go b/internal/integration_test/engine/adhoc_test.go
index cc4698b6..7fc6af6c 100644
--- a/internal/integration_test/engine/adhoc_test.go
+++ b/internal/integration_test/engine/adhoc_test.go
@@ -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)
+}