Repository: tetratelabs/wazero
Pull request #2021 (2024-02-07 00:03:27)

wazevo(backend): do not have *abi in instruction struct


Patch:
diff --git a/internal/engine/wazevo/backend/abi.go b/internal/engine/wazevo/backend/abi.go
index bae83848..cf91c6b7 100644
--- a/internal/engine/wazevo/backend/abi.go
+++ b/internal/engine/wazevo/backend/abi.go
@@ -15,8 +15,10 @@ type (
 		Args, Rets                 []ABIArg
 		ArgStackSize, RetStackSize int64
 
-		ArgRealRegs []regalloc.VReg
-		RetRealRegs []regalloc.VReg
+		ArgIntRealRegs   byte
+		ArgFloatRealRegs byte
+		RetIntRealRegs   byte
+		RetFloatRealRegs byte
 	}
 
 	// ABIArg represents either argument or return value's location.
@@ -77,19 +79,26 @@ func (a *FunctionABI) Init(sig *ssa.Signature, argResultInts, argResultFloats []
 	a.ArgStackSize = a.setABIArgs(a.Args, sig.Params, argResultInts, argResultFloats)
 
 	// Gather the real registers usages in arg/return.
-	a.RetRealRegs = a.RetRealRegs[:0]
+	a.ArgIntRealRegs, a.ArgFloatRealRegs = 0, 0
+	a.RetIntRealRegs, a.RetFloatRealRegs = 0, 0
 	for i := range a.Rets {
 		r := &a.Rets[i]
 		if r.Kind == ABIArgKindReg {
-			a.RetRealRegs = append(a.RetRealRegs, r.Reg)
+			if r.Type.IsInt() {
+				a.RetIntRealRegs++
+			} else {
+				a.RetFloatRealRegs++
+			}
 		}
 	}
-	a.ArgRealRegs = a.ArgRealRegs[:0]
 	for i := range a.Args {
 		arg := &a.Args[i]
 		if arg.Kind == ABIArgKindReg {
-			reg := arg.Reg
-			a.ArgRealRegs = append(a.ArgRealRegs, reg)
+			if arg.Type.IsInt() {
+				a.ArgIntRealRegs++
+			} else {
+				a.ArgFloatRealRegs++
+			}
 		}
 	}
 
@@ -137,9 +146,25 @@ func (a *FunctionABI) setABIArgs(s []ABIArg, types []ssa.Type, ints, floats []re
 	return stackOffset
 }
 
-func (a *FunctionABI) AlignedArgResultStackSlotSize() int64 {
+func (a *FunctionABI) AlignedArgResultStackSlotSize() uint32 {
 	stackSlotSize := a.RetStackSize + a.ArgStackSize
 	// Align stackSlotSize to 16 bytes.
 	stackSlotSize = (stackSlotSize + 15) &^ 15
-	return stackSlotSize
+	// Check overflow 32-bit.
+	if stackSlotSize > 0xFFFFFFFF {
+		panic("ABI stack slot size overflow")
+	}
+	return uint32(stackSlotSize)
+}
+
+func (a *FunctionABI) ABIInfoAsUint64() uint64 {
+	return uint64(a.ArgIntRealRegs)<<56 |
+		uint64(a.ArgFloatRealRegs)<<48 |
+		uint64(a.RetIntRealRegs)<<40 |
+		uint64(a.RetFloatRealRegs)<<32 |
+		uint64(a.AlignedArgResultStackSlotSize())
+}
+
+func ABIInfoFromUint64(info uint64) (argIntRealRegs, argFloatRealRegs, retIntRealRegs, retFloatRealRegs byte, stackSlotSize uint32) {
+	return byte(info >> 56), byte(info >> 48), byte(info >> 40), byte(info >> 32), uint32(info)
 }
diff --git a/internal/engine/wazevo/backend/isa/amd64/abi_entry_preamble.go b/internal/engine/wazevo/backend/isa/amd64/abi_entry_preamble.go
index 18116b15..474c5bd8 100644
--- a/internal/engine/wazevo/backend/isa/amd64/abi_entry_preamble.go
+++ b/internal/engine/wazevo/backend/isa/amd64/abi_entry_preamble.go
@@ -96,7 +96,7 @@ func (m *machine) compileEntryPreamble(sig *ssa.Signature) *instruction {
 	// Finally, restore the original RBP and RSP.
 	cur = m.restoreOriginalRSPRBP(cur)
 
-	ret := m.allocateInstr().asRet(&abi)
+	ret := m.allocateInstr().asRet()
 	linkInstr(cur, ret)
 	return root
 }
diff --git a/internal/engine/wazevo/backend/isa/amd64/abi_go_call.go b/internal/engine/wazevo/backend/isa/amd64/abi_go_call.go
index b8786658..751050af 100644
--- a/internal/engine/wazevo/backend/isa/amd64/abi_go_call.go
+++ b/internal/engine/wazevo/backend/isa/amd64/abi_go_call.go
@@ -270,7 +270,7 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 
 	// Finally ready to return.
 	cur = m.revertRBPRSP(cur)
-	linkInstr(cur, m.allocateInstr().asRet(nil))
+	linkInstr(cur, m.allocateInstr().asRet())
 
 	m.encodeWithoutSSA(ectx.RootInstr)
 	return m.c.Buf()
@@ -377,7 +377,7 @@ func (m *machine) CompileStackGrowCallSequence() []byte {
 
 	// Finally ready to return.
 	cur = m.revertRBPRSP(cur)
-	linkInstr(cur, m.allocateInstr().asRet(nil))
+	linkInstr(cur, m.allocateInstr().asRet())
 
 	m.encodeWithoutSSA(ectx.RootInstr)
 	return m.c.Buf()
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr.go b/internal/engine/wazevo/backend/isa/amd64/instr.go
index a10dd81c..23973b97 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr.go
@@ -10,7 +10,6 @@ import (
 
 type instruction struct {
 	prev, next          *instruction
-	abi                 *backend.FunctionABI
 	op1, op2            operand
 	u1, u2              uint64
 	b1                  bool
@@ -220,11 +219,7 @@ func (i *instruction) String() string {
 	case ud2:
 		return "ud2"
 	case call:
-		if i.u2 > 0 {
-			return fmt.Sprintf("call $%d", int32(i.u2))
-		} else {
-			return fmt.Sprintf("call %s", ssa.FuncRef(i.u1))
-		}
+		return fmt.Sprintf("call %s", ssa.FuncRef(i.u1))
 	case callIndirect:
 		return fmt.Sprintf("callq *%s", i.op1.format(true))
 	case v128ConstIsland:
@@ -273,7 +268,13 @@ func (i *instruction) Defs(regs *[]regalloc.VReg) []regalloc.VReg {
 	case defKindOp2:
 		*regs = append(*regs, i.op2.reg())
 	case defKindCall:
-		*regs = append(*regs, i.abi.RetRealRegs...)
+		_, _, retIntRealRegs, retFloatRealRegs, _ := backend.ABIInfoFromUint64(i.u2)
+		for i := byte(0); i < retIntRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[intArgResultRegs[i]])
+		}
+		for i := byte(0); i < retFloatRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[floatArgResultRegs[i]])
+		}
 	case defKindDivRem:
 		_, _, _, isDiv, _, _ := i.idivRemSequenceData()
 		if isDiv {
@@ -333,9 +334,15 @@ func (i *instruction) Uses(regs *[]regalloc.VReg) []regalloc.VReg {
 		default:
 			panic(fmt.Sprintf("BUG: invalid operand: %s", i))
 		}
-		*regs = append(*regs, i.abi.ArgRealRegs...)
+		fallthrough
 	case useKindCall:
-		*regs = append(*regs, i.abi.ArgRealRegs...)
+		argIntRealRegs, argFloatRealRegs, _, _, _ := backend.ABIInfoFromUint64(i.u2)
+		for i := byte(0); i < argIntRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[intArgResultRegs[i]])
+		}
+		for i := byte(0); i < argFloatRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[floatArgResultRegs[i]])
+		}
 	case useKindFcvtToSintSequence:
 		execCtx, src, tmpGp, tmpGp2, tmpXmm, _, _, _ := i.fcvtToSintSequenceData()
 		*regs = append(*regs, execCtx, src, tmpGp, tmpGp2, tmpXmm)
@@ -522,7 +529,7 @@ func (i *instruction) nop0Label() backend.Label {
 	return backend.Label(i.u1)
 }
 
-type instructionKind int
+type instructionKind byte
 
 const (
 	nop0 instructionKind = iota + 1
@@ -1001,8 +1008,10 @@ func (i *instruction) asLEA(target operand, rd regalloc.VReg) *instruction {
 
 func (i *instruction) asCall(ref ssa.FuncRef, abi *backend.FunctionABI) *instruction {
 	i.kind = call
-	i.abi = abi
 	i.u1 = uint64(ref)
+	if abi != nil {
+		i.u2 = abi.ABIInfoAsUint64()
+	}
 	return i
 }
 
@@ -1011,14 +1020,15 @@ func (i *instruction) asCallIndirect(ptr operand, abi *backend.FunctionABI) *ins
 		panic("BUG")
 	}
 	i.kind = callIndirect
-	i.abi = abi
 	i.op1 = ptr
+	if abi != nil {
+		i.u2 = abi.ABIInfoAsUint64()
+	}
 	return i
 }
 
-func (i *instruction) asRet(abi *backend.FunctionABI) *instruction {
+func (i *instruction) asRet() *instruction {
 	i.kind = ret
-	i.abi = abi
 	return i
 }
 
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go b/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
index b3a24243..8d46e477 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
@@ -1118,9 +1118,8 @@ func (i *instruction) encode(c backend.Compiler) (needsLabelResolution bool) {
 
 	case call:
 		c.EmitByte(0xe8)
-		if i.u2 == 0 { // Meaning that the call target is a function value, and requires relocation.
-			c.AddRelocationInfo(ssa.FuncRef(i.u1))
-		}
+		// Meaning that the call target is a function value, and requires relocation.
+		c.AddRelocationInfo(ssa.FuncRef(i.u1))
 		// Note that this is zero as a placeholder for the call target if it's a function value.
 		c.Emit4Bytes(uint32(i.u2))
 
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index 91aedc9e..72585857 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -123,7 +123,7 @@ func (m *machine) RegAlloc() {
 
 // InsertReturn implements backend.Machine.
 func (m *machine) InsertReturn() {
-	i := m.allocateInstr().asRet(m.currentABI)
+	i := m.allocateInstr().asRet()
 	m.insert(i)
 }
 
@@ -139,7 +139,7 @@ func (m *machine) LowerSingleBranch(b *ssa.Instruction) {
 		jmp := m.allocateInstr()
 		target := ectx.GetOrAllocateSSABlockLabel(targetBlk)
 		if target == backend.LabelReturn {
-			jmp.asRet(m.currentABI)
+			jmp.asRet()
 		} else {
 			jmp.asJmp(newOperandLabel(target))
 		}
@@ -1105,7 +1105,7 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
 	}
 	calleeABI := m.c.GetFunctionABI(m.c.SSABuilder().ResolveSignature(sigID))
 
-	stackSlotSize := calleeABI.AlignedArgResultStackSlotSize()
+	stackSlotSize := int64(calleeABI.AlignedArgResultStackSlotSize())
 	if m.maxRequiredStackSizeForCalls < stackSlotSize+16 {
 		m.maxRequiredStackSizeForCalls = stackSlotSize + 16 // 16 == return address + RBP.
 	}
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue.go b/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue.go
index 9c78d7bb..8fa974c6 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue.go
@@ -1,6 +1,7 @@
 package amd64
 
 import (
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
 )
 
@@ -171,15 +172,15 @@ func (m *machine) postRegAlloc() {
 				cur = linkInstr(cur, instr)
 			}
 			linkInstr(cur, next)
-		}
-
-		if abi := cur.abi; abi != nil {
+			continue
+		case call, callIndirect:
 			// At this point, reg alloc is done, therefore we can safely insert dec/inc RPS instruction
 			// right before/after the call instruction. If this is done before reg alloc, the stack slot
 			// can point to the wrong location and therefore results in a wrong value.
 			call := cur
 			next := call.next
-			if size := uint32(abi.AlignedArgResultStackSlotSize()); size > 0 {
+			_, _, _, _, size := backend.ABIInfoFromUint64(call.u2)
+			if size > 0 {
 				dec := m.allocateInstr().asAluRmiR(aluRmiROpcodeSub, newOperandImm32(size), rspVReg, true)
 				linkInstr(call.prev, dec)
 				linkInstr(dec, call)
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi.go b/internal/engine/wazevo/backend/isa/arm64/abi.go
index 54accac7..f7aeb573 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi.go
@@ -265,7 +265,7 @@ func (m *machine) lowerCall(si *ssa.Instruction) {
 	}
 	calleeABI := m.compiler.GetFunctionABI(m.compiler.SSABuilder().ResolveSignature(sigID))
 
-	stackSlotSize := calleeABI.AlignedArgResultStackSlotSize()
+	stackSlotSize := int64(calleeABI.AlignedArgResultStackSlotSize())
 	if m.maxRequiredStackSizeForCalls < stackSlotSize+16 {
 		m.maxRequiredStackSizeForCalls = stackSlotSize + 16 // return address frame.
 	}
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 b6b9f273..7a9cceb3 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_entry_preamble.go
@@ -168,7 +168,7 @@ func (m *machine) constructEntryPreamble(sig *ssa.Signature) (root *instruction)
 		prReg = paramResultSliceCopied
 	}
 
-	stackSlotSize := abi.AlignedArgResultStackSlotSize()
+	stackSlotSize := int64(abi.AlignedArgResultStackSlotSize())
 	for i := range abi.Args {
 		if i < 2 {
 			// module context ptr and execution context ptr are passed in x0 and x1 by the Go assembly function.
@@ -201,7 +201,7 @@ func (m *machine) constructEntryPreamble(sig *ssa.Signature) (root *instruction)
 	cur = m.move64(spVReg, tmpRegVReg, cur)
 	cur = m.loadOrStoreAtExecutionContext(lrVReg, wazevoapi.ExecutionContextOffsetGoReturnAddress, false, cur)
 	retInst := m.allocateInstr()
-	retInst.asRet(nil)
+	retInst.asRet()
 	linkInstr(cur, retInst)
 	return
 }
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 5cf9e1b9..466b1f96 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_go_call.go
@@ -175,7 +175,7 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 	}
 
 	// Make the SP point to the original address (above the result slot).
-	if s := m.currentABI.AlignedArgResultStackSlotSize(); s > 0 {
+	if s := int64(m.currentABI.AlignedArgResultStackSlotSize()); s > 0 {
 		cur = m.addsAddOrSubStackPointer(cur, spVReg, s, true)
 	}
 
@@ -240,7 +240,7 @@ func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *
 	}
 
 	ret := m.allocateInstr()
-	ret.asRet(nil)
+	ret.asRet()
 	linkInstr(cur, ret)
 
 	m.encode(m.executableContext.RootInstr)
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr.go b/internal/engine/wazevo/backend/isa/arm64/instr.go
index 2eb74fa7..208c343d 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr.go
@@ -22,19 +22,18 @@ type (
 	//
 	// TODO: optimize the layout later once the impl settles.
 	instruction struct {
-		kind                instructionKind
 		prev, next          *instruction
 		u1, u2, u3          uint64
 		rd, rm, rn, ra      operand
 		amode               addressMode
-		abi                 *backend.FunctionABI
 		targets             []uint32
+		kind                instructionKind
 		addedBeforeRegAlloc bool
 	}
 
 	// instructionKind represents the kind of instruction.
 	// This controls how the instruction struct is interpreted.
-	instructionKind int
+	instructionKind byte
 )
 
 func asNop0(i *instruction) {
@@ -174,7 +173,13 @@ func (i *instruction) Defs(regs *[]regalloc.VReg) []regalloc.VReg {
 	case defKindRD:
 		*regs = append(*regs, i.rd.nr())
 	case defKindCall:
-		*regs = append(*regs, i.abi.RetRealRegs...)
+		_, _, retIntRealRegs, retFloatRealRegs, _ := backend.ABIInfoFromUint64(i.u2)
+		for i := byte(0); i < retIntRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[intParamResultRegs[i]])
+		}
+		for i := byte(0); i < retFloatRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[floatParamResultRegs[i]])
+		}
 	default:
 		panic(fmt.Sprintf("defKind for %v not defined", i))
 	}
@@ -202,7 +207,6 @@ const (
 	useKindRNRM
 	useKindRNRMRA
 	useKindRNRN1RM
-	useKindRet
 	useKindCall
 	useKindCallInd
 	useKindAMode
@@ -233,7 +237,7 @@ var useKinds = [numInstructionKinds]useKind{
 	nop0:                 useKindNone,
 	call:                 useKindCall,
 	callInd:              useKindCallInd,
-	ret:                  useKindRet,
+	ret:                  useKindNone,
 	store8:               useKindRNAMode,
 	store16:              useKindRNAMode,
 	store32:              useKindRNAMode,
@@ -324,8 +328,6 @@ func (i *instruction) Uses(regs *[]regalloc.VReg) []regalloc.VReg {
 		if rm := i.rm.reg(); rm.Valid() {
 			*regs = append(*regs, rm)
 		}
-	case useKindRet:
-		*regs = append(*regs, i.abi.RetRealRegs...)
 	case useKindAMode:
 		if amodeRN := i.amode.rn; amodeRN.Valid() {
 			*regs = append(*regs, amodeRN)
@@ -346,11 +348,17 @@ func (i *instruction) Uses(regs *[]regalloc.VReg) []regalloc.VReg {
 		if cnd.kind() != condKindCondFlagSet {
 			*regs = append(*regs, cnd.register())
 		}
-	case useKindCall:
-		*regs = append(*regs, i.abi.ArgRealRegs...)
 	case useKindCallInd:
 		*regs = append(*regs, i.rn.nr())
-		*regs = append(*regs, i.abi.ArgRealRegs...)
+		fallthrough
+	case useKindCall:
+		argIntRealRegs, argFloatRealRegs, _, _, _ := backend.ABIInfoFromUint64(i.u2)
+		for i := byte(0); i < argIntRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[intParamResultRegs[i]])
+		}
+		for i := byte(0); i < argFloatRealRegs; i++ {
+			*regs = append(*regs, regInfo.RealRegToVReg[floatParamResultRegs[i]])
+		}
 	case useKindVecRRRRewrite:
 		*regs = append(*regs, i.rn.reg())
 		*regs = append(*regs, i.rm.reg())
@@ -419,8 +427,6 @@ func (i *instruction) AssignUse(index int, reg regalloc.VReg) {
 				i.ra = i.ra.assignReg(reg)
 			}
 		}
-	case useKindRet:
-		panic("BUG: ret instructions shouldn't be assigned")
 	case useKindAMode:
 		if index == 0 {
 			if amodeRN := i.amode.rn; amodeRN.Valid() {
@@ -467,13 +473,17 @@ func (i *instruction) AssignUse(index int, reg regalloc.VReg) {
 func (i *instruction) asCall(ref ssa.FuncRef, abi *backend.FunctionABI) {
 	i.kind = call
 	i.u1 = uint64(ref)
-	i.abi = abi
+	if abi != nil {
+		i.u2 = abi.ABIInfoAsUint64()
+	}
 }
 
 func (i *instruction) asCallIndirect(ptr regalloc.VReg, abi *backend.FunctionABI) {
 	i.kind = callInd
 	i.rn = operandNR(ptr)
-	i.abi = abi
+	if abi != nil {
+		i.u2 = abi.ABIInfoAsUint64()
+	}
 }
 
 func (i *instruction) callFuncRef() ssa.FuncRef {
@@ -527,9 +537,8 @@ func (i *instruction) nop0Label() label {
 	return label(i.u1)
 }
 
-func (i *instruction) asRet(abi *backend.FunctionABI) {
+func (i *instruction) asRet() {
 	i.kind = ret
-	i.abi = abi
 }
 
 func (i *instruction) asStorePair64(src1, src2 regalloc.VReg, amode addressMode) {
@@ -1391,11 +1400,7 @@ func (i *instruction) String() (str string) {
 	case movFromFPSR:
 		str = fmt.Sprintf("mrs %s fpsr", formatVRegSized(i.rd.nr(), 64))
 	case call:
-		if i.u2 > 0 {
-			str = fmt.Sprintf("bl #%#x", i.u2)
-		} else {
-			str = fmt.Sprintf("bl %s", ssa.FuncRef(i.u1))
-		}
+		str = fmt.Sprintf("bl %s", ssa.FuncRef(i.u1))
 	case callInd:
 		str = fmt.Sprintf("bl %s", formatVRegSized(i.rn.nr(), 64))
 	case ret:
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go b/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
index db35e035..24c8407e 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr_encoding.go
@@ -33,15 +33,9 @@ func (i *instruction) encode(c backend.Compiler) {
 		imm := i.brOffset()
 		c.Emit4Bytes(encodeUnconditionalBranch(false, imm))
 	case call:
-		if i.u2 > 0 {
-			// This is a special case for EmitGoEntryPreamble which doesn't need reloc info,
-			// but instead the imm is already resolved.
-			c.Emit4Bytes(encodeUnconditionalBranch(true, int64(i.u2)))
-		} else {
-			// We still don't know the exact address of the function to call, so we emit a placeholder.
-			c.AddRelocationInfo(i.callFuncRef())
-			c.Emit4Bytes(encodeUnconditionalBranch(true, 0)) // 0 = placeholder
-		}
+		// We still don't know the exact address of the function to call, so we emit a placeholder.
+		c.AddRelocationInfo(i.callFuncRef())
+		c.Emit4Bytes(encodeUnconditionalBranch(true, 0)) // 0 = placeholder
 	case callInd:
 		c.Emit4Bytes(encodeUnconditionalBranchReg(regNumberInEncoding[i.rn.realReg()], true))
 	case store8, store16, store32, store64, fpuStore32, fpuStore64, fpuStore128:
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
index 8ee83225..bcb04d70 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go
@@ -27,7 +27,7 @@ func (m *machine) LowerSingleBranch(br *ssa.Instruction) {
 		b := m.allocateInstr()
 		target := ectx.GetOrAllocateSSABlockLabel(targetBlk)
 		if target == labelReturn {
-			b.asRet(m.currentABI)
+			b.asRet()
 		} else {
 			b.asBr(target)
 		}
diff --git a/internal/engine/wazevo/backend/isa/arm64/machine.go b/internal/engine/wazevo/backend/isa/arm64/machine.go
index 971df393..55fc47dd 100644
--- a/internal/engine/wazevo/backend/isa/arm64/machine.go
+++ b/internal/engine/wazevo/backend/isa/arm64/machine.go
@@ -451,7 +451,7 @@ func (m *machine) Format() string {
 // InsertReturn implements backend.Machine.
 func (m *machine) InsertReturn() {
 	i := m.allocateInstr()
-	i.asRet(m.currentABI)
+	i.asRet()
 	m.insert(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 90c17d86..df1ce7d6 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
@@ -153,7 +153,7 @@ func (m *machine) setupPrologue() {
 func (m *machine) createReturnAddrAndSizeOfArgRetSlot(cur *instruction) *instruction {
 	// First we decrement the stack pointer to point the arg0 slot.
 	var sizeOfArgRetReg regalloc.VReg
-	s := m.currentABI.AlignedArgResultStackSlotSize()
+	s := int64(m.currentABI.AlignedArgResultStackSlotSize())
 	if s > 0 {
 		cur = m.lowerConstantI64AndInsert(cur, tmpRegVReg, s)
 		sizeOfArgRetReg = tmpRegVReg
@@ -311,7 +311,7 @@ func (m *machine) setupEpilogueAfter(cur *instruction) {
 		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 {
+	if s := int64(m.currentABI.AlignedArgResultStackSlotSize()); s > 0 {
 		cur = m.addsAddOrSubStackPointer(cur, spVReg, s, true)
 	}
 
@@ -440,7 +440,7 @@ func (m *machine) CompileStackGrowCallSequence() []byte {
 
 	// Then goes back the original address of this stack grow call.
 	ret := m.allocateInstr()
-	ret.asRet(nil)
+	ret.asRet()
 	linkInstr(cur, ret)
 
 	m.encode(ectx.RootInstr)


Test patch:
diff --git a/internal/engine/wazevo/backend/abi_test.go b/internal/engine/wazevo/backend/abi_test.go
new file mode 100644
index 00000000..4331d205
--- /dev/null
+++ b/internal/engine/wazevo/backend/abi_test.go
@@ -0,0 +1,282 @@
+package backend
+
+import (
+	"testing"
+
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
+	"github.com/tetratelabs/wazero/internal/testing/require"
+)
+
+const (
+	x0 = regalloc.RealRegInvalid + 1 + iota
+	x1
+	x2
+	x3
+	x4
+	x5
+	x6
+	x7
+	x8
+	x9
+	v0
+	v1
+	v2
+	v3
+	v4
+	v5
+	v6
+	v7
+	v8
+	v9
+)
+
+var (
+	x0VReg = regalloc.FromRealReg(x0, regalloc.RegTypeInt)
+	x1VReg = regalloc.FromRealReg(x1, regalloc.RegTypeInt)
+	x2VReg = regalloc.FromRealReg(x2, regalloc.RegTypeInt)
+	x3VReg = regalloc.FromRealReg(x3, regalloc.RegTypeInt)
+	x4VReg = regalloc.FromRealReg(x4, regalloc.RegTypeInt)
+	x5VReg = regalloc.FromRealReg(x5, regalloc.RegTypeInt)
+	x6VReg = regalloc.FromRealReg(x6, regalloc.RegTypeInt)
+	x7VReg = regalloc.FromRealReg(x7, regalloc.RegTypeInt)
+
+	v0VReg = regalloc.FromRealReg(v0, regalloc.RegTypeFloat)
+	v1VReg = regalloc.FromRealReg(v1, regalloc.RegTypeFloat)
+	v2VReg = regalloc.FromRealReg(v2, regalloc.RegTypeFloat)
+	v3VReg = regalloc.FromRealReg(v3, regalloc.RegTypeFloat)
+	v4VReg = regalloc.FromRealReg(v4, regalloc.RegTypeFloat)
+	v5VReg = regalloc.FromRealReg(v5, regalloc.RegTypeFloat)
+	v6VReg = regalloc.FromRealReg(v6, regalloc.RegTypeFloat)
+	v7VReg = regalloc.FromRealReg(v7, regalloc.RegTypeFloat)
+
+	intParamResultRegs   = []regalloc.RealReg{x0, x1, x2, x3, x4, x5, x6, x7}
+	floatParamResultRegs = []regalloc.RealReg{v0, v1, v2, v3, v4, v5, v6, v7}
+)
+
+func TestAbiImpl_init(t *testing.T) {
+	for _, tc := range []struct {
+		name string
+		sig  *ssa.Signature
+		exp  FunctionABI
+	}{
+		{
+			name: "empty sig",
+			sig:  &ssa.Signature{},
+			exp:  FunctionABI{},
+		},
+		{
+			name: "small sig",
+			sig: &ssa.Signature{
+				Params:  []ssa.Type{ssa.TypeI32, ssa.TypeF32, ssa.TypeI32},
+				Results: []ssa.Type{ssa.TypeI64, ssa.TypeF64},
+			},
+			exp: FunctionABI{
+				Args: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
+					{Index: 2, Kind: ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI32},
+				},
+				Rets: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI64},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF64},
+				},
+				ArgIntRealRegs: 2, ArgFloatRealRegs: 1,
+				RetIntRealRegs: 1, RetFloatRealRegs: 1,
+			},
+		},
+		{
+			name: "regs stack mix and match",
+			sig: &ssa.Signature{
+				Params: []ssa.Type{
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+				},
+				Results: []ssa.Type{
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+				},
+			},
+			exp: FunctionABI{
+				ArgStackSize: 128, RetStackSize: 128,
+				Args: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
+					{Index: 2, Kind: ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
+					{Index: 3, Kind: ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
+					{Index: 4, Kind: ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
+					{Index: 5, Kind: ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
+					{Index: 6, Kind: ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
+					{Index: 7, Kind: ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
+					{Index: 8, Kind: ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
+					{Index: 9, Kind: ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
+					{Index: 10, Kind: ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
+					{Index: 11, Kind: ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
+					{Index: 12, Kind: ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
+					{Index: 13, Kind: ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
+					{Index: 14, Kind: ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
+					{Index: 15, Kind: ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
+					{Index: 16, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
+					{Index: 17, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
+					{Index: 18, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
+					{Index: 19, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
+					{Index: 20, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
+					{Index: 21, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
+					{Index: 22, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
+					{Index: 23, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
+					{Index: 24, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
+					{Index: 25, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
+					{Index: 26, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
+					{Index: 27, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
+					{Index: 28, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
+					{Index: 29, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
+					{Index: 30, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
+					{Index: 31, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
+				},
+				Rets: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
+					{Index: 2, Kind: ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
+					{Index: 3, Kind: ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
+					{Index: 4, Kind: ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
+					{Index: 5, Kind: ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
+					{Index: 6, Kind: ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
+					{Index: 7, Kind: ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
+					{Index: 8, Kind: ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
+					{Index: 9, Kind: ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
+					{Index: 10, Kind: ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
+					{Index: 11, Kind: ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
+					{Index: 12, Kind: ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
+					{Index: 13, Kind: ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
+					{Index: 14, Kind: ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
+					{Index: 15, Kind: ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
+					{Index: 16, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
+					{Index: 17, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
+					{Index: 18, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
+					{Index: 19, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
+					{Index: 20, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
+					{Index: 21, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
+					{Index: 22, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
+					{Index: 23, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
+					{Index: 24, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
+					{Index: 25, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
+					{Index: 26, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
+					{Index: 27, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
+					{Index: 28, Kind: ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
+					{Index: 29, Kind: ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
+					{Index: 30, Kind: ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
+					{Index: 31, Kind: ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
+				},
+				ArgIntRealRegs: 8, ArgFloatRealRegs: 8,
+				RetIntRealRegs: 8, RetFloatRealRegs: 8,
+			},
+		},
+		{
+			name: "all regs",
+			sig: &ssa.Signature{
+				Params: []ssa.Type{
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+				},
+				Results: []ssa.Type{
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+					ssa.TypeI32, ssa.TypeF32,
+					ssa.TypeI64, ssa.TypeF64,
+				},
+			},
+			exp: FunctionABI{
+				Args: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
+					{Index: 2, Kind: ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
+					{Index: 3, Kind: ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
+					{Index: 4, Kind: ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
+					{Index: 5, Kind: ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
+					{Index: 6, Kind: ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
+					{Index: 7, Kind: ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
+					{Index: 8, Kind: ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
+					{Index: 9, Kind: ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
+					{Index: 10, Kind: ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
+					{Index: 11, Kind: ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
+					{Index: 12, Kind: ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
+					{Index: 13, Kind: ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
+					{Index: 14, Kind: ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
+					{Index: 15, Kind: ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
+				},
+				Rets: []ABIArg{
+					{Index: 0, Kind: ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
+					{Index: 1, Kind: ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
+					{Index: 2, Kind: ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
+					{Index: 3, Kind: ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
+					{Index: 4, Kind: ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
+					{Index: 5, Kind: ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
+					{Index: 6, Kind: ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
+					{Index: 7, Kind: ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
+					{Index: 8, Kind: ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
+					{Index: 9, Kind: ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
+					{Index: 10, Kind: ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
+					{Index: 11, Kind: ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
+					{Index: 12, Kind: ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
+					{Index: 13, Kind: ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
+					{Index: 14, Kind: ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
+					{Index: 15, Kind: ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
+				},
+				ArgIntRealRegs: 8, ArgFloatRealRegs: 8,
+				RetIntRealRegs: 8, RetFloatRealRegs: 8,
+			},
+		},
+	} {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			abi := FunctionABI{}
+			abi.Init(tc.sig, intParamResultRegs, floatParamResultRegs)
+			require.Equal(t, tc.exp.Args, abi.Args)
+			require.Equal(t, tc.exp.Rets, abi.Rets)
+			require.Equal(t, tc.exp.ArgStackSize, abi.ArgStackSize)
+			require.Equal(t, tc.exp.RetStackSize, abi.RetStackSize)
+			require.Equal(t, tc.exp.RetIntRealRegs, abi.RetIntRealRegs)
+			require.Equal(t, tc.exp.RetFloatRealRegs, abi.RetFloatRealRegs)
+			require.Equal(t, tc.exp.ArgIntRealRegs, abi.ArgIntRealRegs)
+			require.Equal(t, tc.exp.ArgFloatRealRegs, abi.ArgFloatRealRegs)
+		})
+	}
+}
diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go
index e51a564f..2e5c7727 100644
--- a/internal/engine/wazevo/backend/backend_test.go
+++ b/internal/engine/wazevo/backend/backend_test.go
@@ -8,17 +8,19 @@ import (
 	"testing"
 
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
+	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/isa/amd64"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/isa/arm64"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/frontend"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/testcases"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
+	"github.com/tetratelabs/wazero/internal/platform"
 	"github.com/tetratelabs/wazero/internal/testing/require"
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
 func TestMain(m *testing.M) {
-	if runtime.GOARCH != "arm64" {
+	if !platform.CompilerSupported() {
 		os.Exit(0)
 	}
 	os.Exit(m.Run())
@@ -28,6 +30,8 @@ func newMachine() backend.Machine {
 	switch runtime.GOARCH {
 	case "arm64":
 		return arm64.NewBackend()
+	case "amd64":
+		return amd64.NewBackend()
 	default:
 		panic("unsupported architecture")
 	}
@@ -2155,6 +2159,16 @@ L1 (SSA Block: blk0):
 		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
+			var exp string
+			switch runtime.GOARCH {
+			case "arm64":
+				exp = tc.afterFinalizeARM64
+			case "amd64":
+				t.Skip()
+			default:
+				t.Fail()
+			}
+
 			ssab := ssa.NewBuilder()
 			offset := wazevoapi.NewModuleContextOffsetData(tc.m, false)
 			fc := frontend.NewFrontendCompiler(tc.m, ssab, &offset, false, false, false)
@@ -2213,12 +2227,7 @@ L1 (SSA Block: blk0):
 				fmt.Println(be.Format())
 			}
 
-			switch runtime.GOARCH {
-			case "arm64":
-				require.Equal(t, tc.afterFinalizeARM64, be.Format())
-			default:
-				t.Fail()
-			}
+			require.Equal(t, exp, be.Format())
 		})
 	}
 }
diff --git a/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go b/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
index 7140b82c..9fa6e1ad 100644
--- a/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
@@ -22,7 +22,7 @@ func TestInstruction_format_encode(t *testing.T) {
 		wantFormat string
 	}{
 		{
-			setup:      func(i *instruction) { i.asRet(nil) },
+			setup:      func(i *instruction) { i.asRet() },
 			wantFormat: "ret",
 			want:       "c3",
 		},
@@ -1876,7 +1876,7 @@ func TestInstruction_format_encode(t *testing.T) {
 				i.u2 = 0xff
 			},
 			want:       "e8ff000000",
-			wantFormat: "call $255",
+			wantFormat: "call f0",
 		},
 		{
 			setup: func(i *instruction) {
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue_test.go b/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue_test.go
index d59589ac..9fdcdace 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine_pro_epi_logue_test.go
@@ -145,7 +145,7 @@ func TestMachine_postRegAlloc(t *testing.T) {
 			root := m.allocateNop()
 			m.ectx.RootInstr = root
 			ret := m.allocateInstr()
-			ret.asRet(nil)
+			ret.asRet()
 			root.next = ret
 			ret.prev = root
 			m.postRegAlloc()
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine_regalloc_test.go b/internal/engine/wazevo/backend/isa/amd64/machine_regalloc_test.go
index f89abb2b..3eeb99e1 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine_regalloc_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine_regalloc_test.go
@@ -47,7 +47,7 @@ func TestMachine_InsertStoreRegisterAt(t *testing.T) {
 					ctx.typeOf = map[regalloc.VRegID]ssa.Type{
 						raxVReg.ID(): ssa.TypeI64, xmm1VReg.ID(): ssa.TypeF64,
 					}
-					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet(nil)
+					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
 					i1.next = i2
 					i2.prev = i1
 
@@ -105,7 +105,7 @@ func TestMachine_InsertReloadRegisterAt(t *testing.T) {
 					ctx.typeOf = map[regalloc.VRegID]ssa.Type{
 						raxVReg.ID(): ssa.TypeI64, xmm1VReg.ID(): ssa.TypeV128,
 					}
-					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet(nil)
+					i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
 					i1.next = i2
 					i2.prev = i1
 
@@ -150,7 +150,7 @@ func TestMachine_InsertMoveBefore(t *testing.T) {
 	} {
 		t.Run(tc.expected, func(t *testing.T) {
 			_, _, m := newSetupWithMockContext()
-			i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet(nil)
+			i1, i2 := m.allocateInstr().asUD2(), m.allocateInstr().asRet()
 			i1.next = i2
 			i2.prev = i1
 
diff --git a/internal/engine/wazevo/backend/isa/arm64/abi_test.go b/internal/engine/wazevo/backend/isa/arm64/abi_test.go
index f320f175..6f36a60e 100644
--- a/internal/engine/wazevo/backend/isa/arm64/abi_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/abi_test.go
@@ -9,231 +9,6 @@ import (
 	"github.com/tetratelabs/wazero/internal/testing/require"
 )
 
-func TestAbiImpl_init(t *testing.T) {
-	for _, tc := range []struct {
-		name string
-		sig  *ssa.Signature
-		exp  backend.FunctionABI
-	}{
-		{
-			name: "empty sig",
-			sig:  &ssa.Signature{},
-			exp:  backend.FunctionABI{},
-		},
-		{
-			name: "small sig",
-			sig: &ssa.Signature{
-				Params:  []ssa.Type{ssa.TypeI32, ssa.TypeF32, ssa.TypeI32},
-				Results: []ssa.Type{ssa.TypeI64, ssa.TypeF64},
-			},
-			exp: backend.FunctionABI{
-				Args: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
-					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI32},
-				},
-				Rets: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI64},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF64},
-				},
-				ArgRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg},
-				RetRealRegs: []regalloc.VReg{x0VReg, v0VReg},
-			},
-		},
-		{
-			name: "regs stack mix and match",
-			sig: &ssa.Signature{
-				Params: []ssa.Type{
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-				},
-				Results: []ssa.Type{
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-				},
-			},
-			exp: backend.FunctionABI{
-				ArgStackSize: 128, RetStackSize: 128,
-				Args: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
-					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
-					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
-					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
-					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
-					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
-					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
-					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
-					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
-					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
-					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
-					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
-					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
-					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
-					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
-					{Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
-					{Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
-					{Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
-					{Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
-					{Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
-					{Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
-					{Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
-					{Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
-					{Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
-					{Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
-					{Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
-					{Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
-					{Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
-					{Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
-					{Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
-					{Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
-				},
-				Rets: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
-					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
-					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
-					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
-					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
-					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
-					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
-					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
-					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
-					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
-					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
-					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
-					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
-					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
-					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
-					{Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
-					{Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
-					{Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
-					{Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
-					{Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
-					{Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
-					{Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
-					{Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
-					{Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
-					{Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
-					{Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
-					{Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
-					{Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
-					{Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
-					{Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
-					{Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
-				},
-				RetRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
-				ArgRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
-			},
-		},
-		{
-			name: "all regs",
-			sig: &ssa.Signature{
-				Params: []ssa.Type{
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-				},
-				Results: []ssa.Type{
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-					ssa.TypeI32, ssa.TypeF32,
-					ssa.TypeI64, ssa.TypeF64,
-				},
-			},
-			exp: backend.FunctionABI{
-				Args: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
-					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
-					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
-					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
-					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
-					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
-					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
-					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
-					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
-					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
-					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
-					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
-					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
-					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
-					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
-				},
-				Rets: []backend.ABIArg{
-					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
-					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
-					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
-					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
-					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
-					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
-					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
-					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
-					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
-					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
-					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
-					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
-					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
-					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
-					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
-					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
-				},
-				RetRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
-				ArgRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
-			},
-		},
-	} {
-		tc := tc
-		t.Run(tc.name, func(t *testing.T) {
-			abi := backend.FunctionABI{}
-			abi.Init(tc.sig, intParamResultRegs, floatParamResultRegs)
-			require.Equal(t, tc.exp.Args, abi.Args)
-			require.Equal(t, tc.exp.Rets, abi.Rets)
-			require.Equal(t, tc.exp.ArgStackSize, abi.ArgStackSize)
-			require.Equal(t, tc.exp.RetStackSize, abi.RetStackSize)
-			require.Equal(t, tc.exp.RetRealRegs, abi.RetRealRegs)
-			require.Equal(t, tc.exp.ArgRealRegs, abi.ArgRealRegs)
-		})
-	}
-}
-
 func TestMachine_insertAddOrSubStackPointer(t *testing.T) {
 	t.Run("add/small", func(t *testing.T) {
 		_, _, m := newSetupWithMockContext()
diff --git a/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go b/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
index 8757ce1f..f1a7f91d 100644
--- a/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/instr_encoding_test.go
@@ -1259,7 +1259,7 @@ func TestInstruction_encode(t *testing.T) {
 		{want: "40001feb", setup: func(i *instruction) {
 			i.asALU(aluOpSubS, operandNR(x0VReg), operandNR(x2VReg), operandNR(xzrVReg), true)
 		}},
-		{want: "c0035fd6", setup: func(i *instruction) { i.asRet(nil) }},
+		{want: "c0035fd6", setup: func(i *instruction) { i.asRet() }},
 		{want: "e303042a", setup: func(i *instruction) { i.asMove32(x3VReg, x4VReg) }},
 		{want: "fe03002a", setup: func(i *instruction) { i.asMove32(x30VReg, x0VReg) }},
 		{want: "e30304aa", setup: func(i *instruction) { i.asMove64(x3VReg, x4VReg) }},
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 c878084a..ad82e716 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
@@ -217,7 +217,7 @@ func TestMachine_postRegAlloc(t *testing.T) {
 			root := m.allocateNop()
 			m.executableContext.RootInstr = root
 			ret := m.allocateInstr()
-			ret.asRet(nil)
+			ret.asRet()
 			root.next = ret
 			ret.prev = root
 			m.postRegAlloc()