Repository: tetratelabs/wazero
Pull request #2099 (2024-02-27 08:42:08)

wazevo(regalloc): introduces "desired" registers in allocation
supersedes #2094 

mathetake: This reduces 500kb out of 17mb executable of sqlite bench, which seems really promising, but I think there's a small bug in here, so still being marked draft
mathetake: original executable size:
main: 12824127 bytes
https://github.com/tetratelabs/wazero/pull/2099/commits/5ca5cda7069cafac867931c38e40e41fc6b42122: 12165727 bytes

mathetake: last two commits seems buggy 
mathetake: I think I am done with this direction for now, and will merge this tomorrow. After that I will take a look at the trap stuff (thanks to @ncruces) and then will go back to regalloc again next week. 

Patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index 09ccbe00..26985995 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -1995,9 +1995,8 @@ func (m *machine) getVRegSpillSlotOffsetFromSP(id regalloc.VRegID, size byte) in
 }
 
 func (m *machine) copyTo(src regalloc.VReg, dst regalloc.VReg) {
-	typ := m.c.TypeOf(src)
 	mov := m.allocateInstr()
-	if typ.IsInt() {
+	if src.RegType() == regalloc.RegTypeInt {
 		mov.asMovRR(src, dst, true)
 	} else {
 		mov.asXmmUnaryRmR(sseOpcodeMovdqu, newOperandReg(src), dst)
diff --git a/internal/engine/wazevo/backend/regalloc.go b/internal/engine/wazevo/backend/regalloc.go
index 27a194a0..3f36c84e 100644
--- a/internal/engine/wazevo/backend/regalloc.go
+++ b/internal/engine/wazevo/backend/regalloc.go
@@ -112,10 +112,9 @@ func (f *RegAllocFunction[I, M]) ClobberedRegisters(regs []regalloc.VReg) {
 	f.m.ClobberedRegisters(regs)
 }
 
-// SwapAtEndOfBlock implements regalloc.Function SwapAtEndOfBlock.
-func (f *RegAllocFunction[I, M]) SwapAtEndOfBlock(x1, x2, tmp regalloc.VReg, blk regalloc.Block) {
-	cur := blk.LastInstrForInsertion()
-	f.m.Swap(cur.Prev().(I), x1, x2, tmp)
+// SwapBefore implements regalloc.Function SwapBefore.
+func (f *RegAllocFunction[I, M]) SwapBefore(x1, x2, tmp regalloc.VReg, instr regalloc.Instr) {
+	f.m.Swap(instr.Prev().(I), x1, x2, tmp)
 }
 
 // PostOrderBlockIteratorBegin implements regalloc.Function PostOrderBlockIteratorBegin.
diff --git a/internal/engine/wazevo/backend/regalloc/api.go b/internal/engine/wazevo/backend/regalloc/api.go
index 642e7507..23157b47 100644
--- a/internal/engine/wazevo/backend/regalloc/api.go
+++ b/internal/engine/wazevo/backend/regalloc/api.go
@@ -37,7 +37,7 @@ type (
 		// Followings are for rewriting the function.
 
 		// SwapAtEndOfBlock swaps the two virtual registers at the end of the given block.
-		SwapAtEndOfBlock(x1, x2, tmp VReg, block Block)
+		SwapBefore(x1, x2, tmp VReg, instr Instr)
 		// StoreRegisterBefore inserts store instruction(s) before the given instruction for the given virtual register.
 		StoreRegisterBefore(v VReg, instr Instr)
 		// StoreRegisterAfter inserts store instruction(s) after the given instruction for the given virtual register.
diff --git a/internal/engine/wazevo/backend/regalloc/regalloc.go b/internal/engine/wazevo/backend/regalloc/regalloc.go
index 544b714f..05c78746 100644
--- a/internal/engine/wazevo/backend/regalloc/regalloc.go
+++ b/internal/engine/wazevo/backend/regalloc/regalloc.go
@@ -117,7 +117,8 @@ type (
 		// value is live-in or not.
 		spilled bool
 		// isPhi is true if this is a phi value.
-		isPhi bool
+		isPhi      bool
+		desiredLoc desiredLoc
 		// phiDefInstList is a list of instructions that defines this phi value.
 		// This is used to determine the spill location, and only valid if isPhi=true.
 		*phiDefInstList
@@ -126,13 +127,43 @@ type (
 	// phiDefInstList is a linked list of instructions that defines a phi value.
 	phiDefInstList struct {
 		instr Instr
+		v     VReg
 		next  *phiDefInstList
 	}
+
+	// desiredLoc represents a desired location for a VReg.
+	desiredLoc uint16
+	// desiredLocKind is a kind of desired location for a VReg.
+	desiredLocKind uint16
+)
+
+const (
+	// desiredLocKindUnspecified is a kind of desired location for a VReg that is not specified.
+	desiredLocKindUnspecified desiredLocKind = iota
+	// desiredLocKindStack is a kind of desired location for a VReg that is on the stack, only used for the phi values.
+	desiredLocKindStack
+	// desiredLocKindReg is a kind of desired location for a VReg that is in a register.
+	desiredLocKindReg
+	desiredLocUnspecified = desiredLoc(desiredLocKindUnspecified)
+	desiredLocStack       = desiredLoc(desiredLocKindStack)
 )
 
+func newDesiredLocReg(r RealReg) desiredLoc {
+	return desiredLoc(desiredLocKindReg) | desiredLoc(r<<2)
+}
+
+func (d desiredLoc) realReg() RealReg {
+	return RealReg(d >> 2)
+}
+
+func (d desiredLoc) stack() bool {
+	return d&3 == desiredLoc(desiredLocKindStack)
+}
+
 func resetPhiDefInstList(l *phiDefInstList) {
 	l.instr = nil
 	l.next = nil
+	l.v = VRegInvalid
 }
 
 func (s *state) dump(info *RegisterInfo) { //nolint:unused
@@ -180,6 +211,7 @@ func resetVrState(vs *vrState) {
 	vs.lca = nil
 	vs.isPhi = false
 	vs.phiDefInstList = nil
+	vs.desiredLoc = desiredLocUnspecified
 }
 
 func (s *state) getVRegState(v VRegID) *vrState {
@@ -223,8 +255,15 @@ func (vs *vrState) recordReload(f Function, blk Block) {
 	}
 }
 
-func (s *state) findOrSpillAllocatable(a *Allocator, allocatable []RealReg, forbiddenMask RegSet) (r RealReg) {
+func (s *state) findOrSpillAllocatable(a *Allocator, allocatable []RealReg, forbiddenMask RegSet, preferred RealReg) (r RealReg) {
 	r = RealRegInvalid
+	// First, check if the preferredMask has any allocatable register.
+	for _, candidateReal := range allocatable {
+		if !forbiddenMask.has(candidateReal) && !s.regsInUse.has(candidateReal) && candidateReal == preferred {
+			return candidateReal
+		}
+	}
+
 	var lastUseAt programCounter
 	var spillVReg VReg
 	for _, candidateReal := range allocatable {
@@ -246,11 +285,16 @@ func (s *state) findOrSpillAllocatable(a *Allocator, allocatable []RealReg, forb
 			continue
 		}
 
+		isPreferred := candidateReal == preferred
+
 		// last == -1 means the value won't be used anymore.
-		if last := s.getVRegState(using.ID()).lastUse; r == RealRegInvalid || last == -1 || (lastUseAt != -1 && last > lastUseAt) {
+		if last := s.getVRegState(using.ID()).lastUse; r == RealRegInvalid || isPreferred || last == -1 || (lastUseAt != -1 && last > lastUseAt) {
 			lastUseAt = last
 			r = candidateReal
 			spillVReg = using
+			if isPreferred {
+				break
+			}
 		}
 	}
 
@@ -588,6 +632,9 @@ func (a *Allocator) finalizeStartReg(blk Block) {
 	s.regsInUse.range_(func(allocated RealReg, v VReg) {
 		currentBlkState.startRegs.add(allocated, v)
 	})
+	if wazevoapi.RegAllocLoggingEnabled {
+		fmt.Printf("finalized start reg for blk%d: %s\n", blk.ID(), currentBlkState.startRegs.format(a.regInfo))
+	}
 }
 
 func (a *Allocator) allocBlock(f Function, blk Block) {
@@ -610,31 +657,87 @@ func (a *Allocator) allocBlock(f Function, blk Block) {
 		s.useRealReg(allocatedRealReg, vr)
 	})
 
+	desiredUpdated := a.vs2[:0]
+
 	// Update the last use of each VReg.
 	var pc programCounter
 	for instr := blk.InstrIteratorBegin(); instr != nil; instr = blk.InstrIteratorNext() {
-		for _, use := range instr.Uses(&a.vs) {
+		var use, def VReg
+		for _, use = range instr.Uses(&a.vs) {
 			if !use.IsRealReg() {
 				s.getVRegState(use.ID()).lastUse = pc
 			}
 		}
+
+		if instr.IsCopy() {
+			def = instr.Defs(&a.vs)[0]
+			r := def.RealReg()
+			if r != RealRegInvalid {
+				useID := use.ID()
+				vs := s.getVRegState(useID)
+				if !vs.isPhi { // TODO: no idea why do we need this.
+					vs.desiredLoc = newDesiredLocReg(r)
+					desiredUpdated = append(desiredUpdated, useID)
+				}
+			}
+		}
 		pc++
 	}
+
 	// Mark all live-out values by checking live-in of the successors.
+	// While doing so, we also update the desired register values.
+	var succ Block
 	for i, ns := 0, blk.Succs(); i < ns; i++ {
-		succ := blk.Succ(i)
+		succ = blk.Succ(i)
 		if succ == nil {
 			continue
 		}
 
 		succID := succ.ID()
-		succInfo := a.getOrAllocateBlockState(succID)
-		for _, v := range succInfo.liveIns {
+		succState := a.getOrAllocateBlockState(succID)
+		for _, v := range succState.liveIns {
 			if s.phiBlk(v) != succ {
 				st := s.getVRegState(v)
 				st.lastUse = programCounterLiveOut
 			}
 		}
+
+		if succState.startFromPredIndex > -1 {
+			if wazevoapi.RegAllocLoggingEnabled {
+				fmt.Printf("blk%d -> blk%d: start_regs: %s\n", bID, succID, succState.startRegs.format(a.regInfo))
+			}
+			succState.startRegs.range_(func(allocatedRealReg RealReg, vr VReg) {
+				vs := s.getVRegState(vr.ID())
+				vs.desiredLoc = newDesiredLocReg(allocatedRealReg)
+				desiredUpdated = append(desiredUpdated, vr.ID())
+			})
+			for _, p := range succ.BlockParams(&a.vs) {
+				vs := s.getVRegState(p.ID())
+				if vs.desiredLoc.realReg() == RealRegInvalid {
+					vs.desiredLoc = desiredLocStack
+				}
+			}
+		}
+	}
+
+	// Propagate the desired register values from the end of the block to the beginning.
+	for instr := blk.InstrRevIteratorBegin(); instr != nil; instr = blk.InstrRevIteratorNext() {
+		if instr.IsCopy() {
+			def := instr.Defs(&a.vs)[0]
+			defState := s.getVRegState(def.ID())
+			desired := defState.desiredLoc.realReg()
+			if desired == RealRegInvalid {
+				continue
+			}
+
+			use := instr.Uses(&a.vs)[0]
+			useID := use.ID()
+			useState := s.getVRegState(useID)
+			if s.phiBlk(useID) != succ && useState.desiredLoc == desiredLocUnspecified {
+				useState.desiredLoc = newDesiredLocReg(desired)
+				desiredUpdated = append(desiredUpdated, useID)
+			}
+		}
 	}
 
 	pc = 0
@@ -669,7 +772,9 @@ func (a *Allocator) allocBlock(f Function, blk Block) {
 				r := vs.r
 
 				if r == RealRegInvalid {
-					r = s.findOrSpillAllocatable(a, a.regInfo.AllocatableRegisters[use.RegType()], currentUsedSet)
+					r = s.findOrSpillAllocatable(a, a.regInfo.AllocatableRegisters[use.RegType()], currentUsedSet,
+						// Prefer the desired register if it's available.
+						vs.desiredLoc.realReg())
 					vs.recordReload(f, blk)
 					f.ReloadRegisterBefore(use.SetRealReg(r), instr)
 					s.useRealReg(r, use)
@@ -735,6 +840,30 @@ func (a *Allocator) allocBlock(f Function, blk Block) {
 			} else {
 				vState := s.getVRegState(def.ID())
 				r := vState.r
+
+				if desired := vState.desiredLoc.realReg(); desired != RealRegInvalid {
+					if r != desired {
+						if (vState.isPhi && vState.defBlk == succ) ||
+							// If this is not a phi and it's already assigned a real reg,
+							// this value has multiple definitions, hence we cannot assign the desired register.
+							(!s.regsInUse.has(desired) && r == RealRegInvalid) {
+							// If the phi value is passed via a real register, we force the value to be in the desired register.
+							if wazevoapi.RegAllocLoggingEnabled {
+								fmt.Printf("\t\tv%d is phi and desiredReg=%s\n", def.ID(), a.regInfo.RealRegName(desired))
+							}
+							if r != RealRegInvalid {
+								// If the value is already in a different real register, we release it to change the state.
+								// Otherwise, multiple registers might have the same values at the end, which results in
+								// messing up the merge state reconciliation.
+								s.releaseRealReg(r)
+							}
+							r = desired
+							s.releaseRealReg(r)
+							s.useRealReg(r, def)
+						}
+					}
+				}
+
 				// Allocate a new real register if `def` is not currently assigned one.
 				// It can happen when multiple instructions define the same VReg (e.g. const loads).
 				if r == RealRegInvalid {
@@ -746,19 +875,29 @@ func (a *Allocator) allocBlock(f Function, blk Block) {
 					}
 					if r == RealRegInvalid {
 						typ := def.RegType()
-						r = s.findOrSpillAllocatable(a, a.regInfo.AllocatableRegisters[typ], RegSet(0))
+						r = s.findOrSpillAllocatable(a, a.regInfo.AllocatableRegisters[typ], RegSet(0), RealRegInvalid)
 					}
 					s.useRealReg(r, def)
 				}
-				instr.AssignDef(def.SetRealReg(r))
+				dr := def.SetRealReg(r)
+				instr.AssignDef(dr)
 				if wazevoapi.RegAllocLoggingEnabled {
 					fmt.Printf("\tdefining v%d with %s\n", def.ID(), a.regInfo.RealRegName(r))
 				}
 				if vState.isPhi {
-					n := a.phiDefInstListPool.Allocate()
-					n.instr = instr
-					n.next = vState.phiDefInstList
-					vState.phiDefInstList = n
+					if vState.desiredLoc.stack() { // Stack based phi value.
+						f.StoreRegisterAfter(dr, instr)
+						// Release the real register as it's not used anymore.
+						s.releaseRealReg(r)
+					} else {
+						// Only the register based phis are necessary to track the defining instructions
+						// since the stack-based phis are already having stores inserted ^.
+						n := a.phiDefInstListPool.Allocate()
+						n.instr = instr
+						n.next = vState.phiDefInstList
+						n.v = dr
+						vState.phiDefInstList = n
+					}
 				} else {
 					vState.defInstr = instr
 					vState.defBlk = blk
@@ -780,6 +919,13 @@ func (a *Allocator) allocBlock(f Function, blk Block) {
 		currentBlkState.dump(a.regInfo)
 	}
 
+	// Reset the desired end location.
+	for _, v := range desiredUpdated {
+		vs := s.getVRegState(v)
+		vs.desiredLoc = desiredLocUnspecified
+	}
+	a.vs2 = desiredUpdated[:0]
+
 	for i := 0; i < blk.Succs(); i++ {
 		succ := blk.Succ(i)
 		if succ == nil {
@@ -939,11 +1085,11 @@ func (a *Allocator) reconcileEdge(f Function,
 				desiredVReg.ID(), a.regInfo.RealRegName(r), a.regInfo.RealRegName(er),
 			)
 		}
-		f.SwapAtEndOfBlock(
+		f.SwapBefore(
 			currentVReg.SetRealReg(r),
 			desiredVReg.SetRealReg(er),
 			freeReg,
-			pred,
+			pred.LastInstrForInsertion(),
 		)
 		s.allocatedRegSet = s.allocatedRegSet.add(freeReg.RealReg())
 		currentOccupantsRev[desiredVReg] = r
@@ -998,8 +1144,7 @@ func (a *Allocator) scheduleSpill(f Function, vs *vrState) {
 	// If the value is the phi value, we need to insert a spill after each phi definition.
 	if vs.isPhi {
 		for defInstr := vs.phiDefInstList; defInstr != nil; defInstr = defInstr.next {
-			def := defInstr.instr.Defs(&a.vs)[0]
-			f.StoreRegisterAfter(def, defInstr.instr)
+			f.StoreRegisterAfter(defInstr.v, defInstr.instr)
 		}
 		return
 	}


Test patch:
diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go
index 895e8471..a66d0589 100644
--- a/internal/engine/wazevo/backend/backend_test.go
+++ b/internal/engine/wazevo/backend/backend_test.go
@@ -73,17 +73,14 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	subs xzr, x4, x5
-	csel w8, w2, w3, eq
+	csel w0, w2, w3, eq
 	subs wzr, w3, wzr
-	csel x9, x4, x5, ne
+	csel x1, x4, x5, ne
 	fcmp d2, d3
 	fcsel s8, s0, s1, gt
 	fcmp s0, s1
-	fcsel d9, d2, d3, ne
-	mov v1.8b, v9.8b
+	fcsel d1, d2, d3, ne
 	mov v0.8b, v8.8b
-	mov x1, x9
-	mov x0, x8
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -107,14 +104,10 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
-	ldr d8, #8; b 16; data.f64 64.000000
-	mov v1.8b, v8.8b
-	ldr s8, #8; b 8; data.f32 32.000000
-	mov v0.8b, v8.8b
-	orr x8, xzr, #0x2
-	mov x1, x8
-	orr w8, wzr, #0x1
-	mov x0, x8
+	ldr d1, #8; b 16; data.f64 64.000000
+	ldr s0, #8; b 8; data.f32 32.000000
+	orr x1, xzr, #0x2
+	orr w0, wzr, #0x1
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -136,8 +129,7 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	add w8, w2, w3
-	sub w8, w8, w2
-	mov x0, x8
+	sub w0, w8, w2
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -174,22 +166,19 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	add x8, x2, x2
-	sub x8, x8, x2
+	sub x0, x8, x2
 	fadd s8, s0, s0
 	fsub s8, s8, s0
 	fmul s8, s8, s0
 	fdiv s8, s8, s0
 	fmax s8, s8, s0
-	fmin s8, s8, s0
-	fadd d9, d1, d1
-	fsub d9, d9, d1
-	fmul d9, d9, d1
-	fdiv d9, d9, d1
-	fmax d9, d9, d1
-	fmin d9, d9, d1
-	mov v1.8b, v9.8b
-	mov v0.8b, v8.8b
-	mov x0, x8
+	fmin s0, s8, s0
+	fadd d8, d1, d1
+	fsub d8, d8, d1
+	fmul d8, d8, d1
+	fdiv d8, d8, d1
+	fmax d8, d8, d1
+	fmin d1, d8, d1
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -209,8 +198,7 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
-	mov x8, xzr
-	mov x1, x8
+	mov x1, xzr
 	mov x0, x2
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
@@ -487,17 +475,15 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	mov x8, xzr
-	cbz w8, #0x18 L2
+	cbz w8, #0x14 L2
 L3 (SSA Block: blk1):
-	mov x8, xzr
-	mov x0, x8
+	mov x0, xzr
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L2 (SSA Block: blk2):
 L4 (SSA Block: blk3):
-	mov x8, xzr
-	mov x0, x8
+	mov x0, xzr
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -582,8 +568,7 @@ L4 (SSA Block: blk5):
 L3 (SSA Block: blk4):
 L5 (SSA Block: blk3):
 L6 (SSA Block: blk2):
-	mov x8, xzr
-	mov x0, x8
+	mov x0, xzr
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -619,10 +604,9 @@ L4 (SSA Block: blk5):
 	ret
 L3 (SSA Block: blk4):
 L5 (SSA Block: blk3):
-	load_const_block_arg x8, 0x1
-	orr w8, wzr, #0x1
-	mov x2, x8
-	b #-0x1c (L2)
+	load_const_block_arg x2, 0x1
+	orr w2, wzr, #0x1
+	b #-0x18 (L2)
 `,
 		},
 		{
@@ -658,35 +642,30 @@ L1 (SSA Block: blk0):
 			afterFinalizeARM64: `
 L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
-	sub sp, sp, #0x20
-	orr x27, xzr, #0x20
+	sub sp, sp, #0x10
+	orr x27, xzr, #0x10
 	str x27, [sp, #-0x10]!
 	str x0, [sp, #0x18]
 	str x1, [sp, #0x10]
 	str x1, [x0, #0x8]
 	bl f1
-	str w0, [sp, #0x20]
+	mov x2, x0
 	ldr x8, [sp, #0x10]
 	ldr x9, [sp, #0x18]
 	str x8, [x9, #0x8]
 	mov x0, x9
 	mov x1, x8
-	ldr w10, [sp, #0x20]
-	mov x2, x10
-	movz w10, #0x5, lsl 0
-	mov x3, x10
+	movz w3, #0x5, lsl 0
 	bl f2
-	str w0, [sp, #0x24]
+	mov x2, x0
 	ldr x8, [sp, #0x10]
 	ldr x9, [sp, #0x18]
 	str x8, [x9, #0x8]
 	mov x0, x9
 	mov x1, x8
-	ldr w8, [sp, #0x24]
-	mov x2, x8
 	bl f3
 	add sp, sp, #0x10
-	add sp, sp, #0x20
+	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 `,
@@ -1003,20 +982,15 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
-	sxtw x8, w2
-	uxtw x9, w2
-	sxtb x10, w3
-	sxth x11, w3
-	sxtw x12, w3
-	sxtb w13, w2
-	sxth w14, w2
-	mov x6, x14
-	mov x5, x13
-	mov x4, x12
-	mov x3, x11
-	mov x2, x10
-	mov x1, x9
-	mov x0, x8
+	sxtw x0, w2
+	uxtw x1, w2
+	sxtb x8, w3
+	sxth x9, w3
+	sxtw x4, w3
+	sxtb w5, w2
+	sxth w6, w2
+	mov x3, x9
+	mov x2, x8
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -1054,26 +1028,21 @@ L1 (SSA Block: blk0):
 L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
-	clz w8, w2
-	rbit w9, w2
-	clz w9, w9
+	clz w0, w2
+	rbit w8, w2
+	clz w1, w8
 	ins v8.d[0], x2
 	cnt v8.16b, v8.16b
 	uaddlv h8, v8.8b
-	mov x10, v8.d[0]
-	clz x11, x3
-	rbit x12, x3
-	clz x12, x12
+	mov x2, v8.d[0]
+	clz x8, x3
+	rbit x9, x3
+	clz x4, x9
 	ins v8.d[0], x3
 	cnt v8.16b, v8.16b
 	uaddlv h8, v8.8b
-	mov x13, v8.d[0]
-	mov x5, x13
-	mov x4, x12
-	mov x3, x11
-	mov x2, x10
-	mov x1, x9
-	mov x0, x8
+	mov x5, v8.d[0]
+	mov x3, x8
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -1087,49 +1056,36 @@ L1 (SSA Block: blk0):
 	orr x27, xzr, #0x20
 	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
-	str x19, [sp, #-0x10]!
-	str x20, [sp, #-0x10]!
-	orr x27, xzr, #0x20
-	str x27, [sp, #-0x10]!
+	str xzr, [sp, #-0x10]!
 	fcmp s0, s1
-	cset x8, eq
+	cset x0, eq
 	fcmp s0, s1
-	cset x9, ne
+	cset x1, ne
 	fcmp s0, s1
-	cset x10, mi
+	cset x2, mi
 	fcmp s0, s1
-	cset x11, gt
+	cset x3, gt
 	fcmp s0, s1
-	cset x12, ls
+	cset x4, ls
 	fcmp s0, s1
-	cset x13, ge
+	cset x5, ge
 	fcmp d2, d3
-	cset x14, eq
+	cset x6, eq
 	fcmp d2, d3
-	cset x15, ne
+	cset x7, ne
 	fcmp d2, d3
-	cset x16, mi
+	cset x8, mi
 	fcmp d2, d3
-	cset x17, gt
+	cset x9, gt
 	fcmp d2, d3
-	cset x19, ls
+	cset x10, ls
 	fcmp d2, d3
-	cset x20, ge
-	str w20, [sp, #0x58]
-	str w19, [sp, #0x50]
-	str w17, [sp, #0x48]
-	str w16, [sp, #0x40]
-	mov x7, x15
-	mov x6, x14
-	mov x5, x13
-	mov x4, x12
-	mov x3, x11
-	mov x2, x10
-	mov x1, x9
-	mov x0, x8
+	cset x11, ge
+	str w11, [sp, #0x38]
+	str w10, [sp, #0x30]
+	str w9, [sp, #0x28]
+	str w8, [sp, #0x20]
 	add sp, sp, #0x10
-	ldr x20, [sp], #0x10
-	ldr x19, [sp], #0x10
 	ldr x30, [sp], #0x10
 	add sp, sp, #0x20
 	ret
@@ -1169,197 +1125,188 @@ L16:
 	exit_sequence x10
 L17:
 	msr fpsr, xzr
-	fcvtzs x9, s1
-	mrs x10 fpsr
-	mov x11, x0
+	fcvtzs x1, s1
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v1.16b
-	subs xzr, x10, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L15)
 	fcmp s8, s8
-	mov x10, x11
+	mov x9, x10
 	b.vc #0x34, (L14)
-	movz x12, #0xc, lsl 0
-	str w12, [x10]
-	mov x12, sp
-	str x12, [x10, #0x38]
-	adr x12, #0x0
-	str x12, [x10, #0x30]
-	exit_sequence x10
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
+	mov x11, sp
+	str x11, [x9, #0x38]
+	adr x11, #0x0
+	str x11, [x9, #0x30]
+	exit_sequence x9
 L14:
-	movz x10, #0xb, lsl 0
-	str w10, [x11]
-	mov x10, sp
-	str x10, [x11, #0x38]
-	adr x10, #0x0
-	str x10, [x11, #0x30]
-	exit_sequence x11
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L15:
 	msr fpsr, xzr
-	fcvtzs w10, d0
-	mrs x11 fpsr
-	mov x12, x0
+	fcvtzs w2, d0
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v0.16b
-	subs xzr, x11, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L13)
 	fcmp d8, d8
-	mov x11, x12
+	mov x9, x10
 	b.vc #0x34, (L12)
-	movz x13, #0xc, lsl 0
-	str w13, [x11]
-	mov x13, sp
-	str x13, [x11, #0x38]
-	adr x13, #0x0
-	str x13, [x11, #0x30]
-	exit_sequence x11
-L12:
-	movz x11, #0xb, lsl 0
-	str w11, [x12]
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
 	mov x11, sp
-	str x11, [x12, #0x38]
+	str x11, [x9, #0x38]
 	adr x11, #0x0
-	str x11, [x12, #0x30]
-	exit_sequence x12
+	str x11, [x9, #0x30]
+	exit_sequence x9
+L12:
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L13:
 	msr fpsr, xzr
-	fcvtzs w11, s1
-	mrs x12 fpsr
-	mov x13, x0
+	fcvtzs w3, s1
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v1.16b
-	subs xzr, x12, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L11)
 	fcmp s8, s8
-	mov x12, x13
+	mov x9, x10
 	b.vc #0x34, (L10)
-	movz x14, #0xc, lsl 0
-	str w14, [x12]
-	mov x14, sp
-	str x14, [x12, #0x38]
-	adr x14, #0x0
-	str x14, [x12, #0x30]
-	exit_sequence x12
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
+	mov x11, sp
+	str x11, [x9, #0x38]
+	adr x11, #0x0
+	str x11, [x9, #0x30]
+	exit_sequence x9
 L10:
-	movz x12, #0xb, lsl 0
-	str w12, [x13]
-	mov x12, sp
-	str x12, [x13, #0x38]
-	adr x12, #0x0
-	str x12, [x13, #0x30]
-	exit_sequence x13
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L11:
 	msr fpsr, xzr
-	fcvtzu x12, d0
-	mrs x13 fpsr
-	mov x14, x0
+	fcvtzu x4, d0
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v0.16b
-	subs xzr, x13, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L9)
 	fcmp d8, d8
-	mov x13, x14
+	mov x9, x10
 	b.vc #0x34, (L8)
-	movz x15, #0xc, lsl 0
-	str w15, [x13]
-	mov x15, sp
-	str x15, [x13, #0x38]
-	adr x15, #0x0
-	str x15, [x13, #0x30]
-	exit_sequence x13
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
+	mov x11, sp
+	str x11, [x9, #0x38]
+	adr x11, #0x0
+	str x11, [x9, #0x30]
+	exit_sequence x9
 L8:
-	movz x13, #0xb, lsl 0
-	str w13, [x14]
-	mov x13, sp
-	str x13, [x14, #0x38]
-	adr x13, #0x0
-	str x13, [x14, #0x30]
-	exit_sequence x14
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L9:
 	msr fpsr, xzr
-	fcvtzu x13, s1
-	mrs x14 fpsr
-	mov x15, x0
+	fcvtzu x5, s1
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v1.16b
-	subs xzr, x14, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L7)
 	fcmp s8, s8
-	mov x14, x15
+	mov x9, x10
 	b.vc #0x34, (L6)
-	movz x16, #0xc, lsl 0
-	str w16, [x14]
-	mov x16, sp
-	str x16, [x14, #0x38]
-	adr x16, #0x0
-	str x16, [x14, #0x30]
-	exit_sequence x14
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
+	mov x11, sp
+	str x11, [x9, #0x38]
+	adr x11, #0x0
+	str x11, [x9, #0x30]
+	exit_sequence x9
 L6:
-	movz x14, #0xb, lsl 0
-	str w14, [x15]
-	mov x14, sp
-	str x14, [x15, #0x38]
-	adr x14, #0x0
-	str x14, [x15, #0x30]
-	exit_sequence x15
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L7:
 	msr fpsr, xzr
-	fcvtzu w14, d0
-	mrs x15 fpsr
-	mov x16, x0
+	fcvtzu w6, d0
+	mrs x9 fpsr
+	mov x10, x0
 	mov v8.16b, v0.16b
-	subs xzr, x15, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L5)
 	fcmp d8, d8
-	mov x15, x16
+	mov x9, x10
 	b.vc #0x34, (L4)
-	movz x17, #0xc, lsl 0
-	str w17, [x15]
-	mov x17, sp
-	str x17, [x15, #0x38]
-	adr x17, #0x0
-	str x17, [x15, #0x30]
-	exit_sequence x15
+	movz x11, #0xc, lsl 0
+	str w11, [x9]
+	mov x11, sp
+	str x11, [x9, #0x38]
+	adr x11, #0x0
+	str x11, [x9, #0x30]
+	exit_sequence x9
 L4:
-	movz x15, #0xb, lsl 0
-	str w15, [x16]
-	mov x15, sp
-	str x15, [x16, #0x38]
-	adr x15, #0x0
-	str x15, [x16, #0x30]
-	exit_sequence x16
+	movz x9, #0xb, lsl 0
+	str w9, [x10]
+	mov x9, sp
+	str x9, [x10, #0x38]
+	adr x9, #0x0
+	str x9, [x10, #0x30]
+	exit_sequence x10
 L5:
 	msr fpsr, xzr
-	fcvtzu w15, s1
-	mrs x16 fpsr
+	fcvtzu w7, s1
+	mrs x9 fpsr
 	mov v8.16b, v1.16b
-	subs xzr, x16, #0x1
+	subs xzr, x9, #0x1
 	b.ne #0x70, (L3)
 	fcmp s8, s8
-	mov x16, x0
+	mov x9, x0
 	b.vc #0x34, (L2)
-	movz x17, #0xc, lsl 0
-	str w17, [x16]
-	mov x17, sp
-	str x17, [x16, #0x38]
-	adr x17, #0x0
-	str x17, [x16, #0x30]
-	exit_sequence x16
+	movz x10, #0xc, lsl 0
+	str w10, [x9]
+	mov x10, sp
+	str x10, [x9, #0x38]
+	adr x10, #0x0
+	str x10, [x9, #0x30]
+	exit_sequence x9
 L2:
-	movz x16, #0xb, lsl 0
-	str w16, [x0]
-	mov x16, sp
-	str x16, [x0, #0x38]
-	adr x16, #0x0
-	str x16, [x0, #0x30]
+	movz x9, #0xb, lsl 0
+	str w9, [x0]
+	mov x9, sp
+	str x9, [x0, #0x38]
+	adr x9, #0x0
+	str x9, [x0, #0x30]
 	exit_sequence x0
 L3:
-	fcvt s8, d0
-	fcvt d9, s1
-	mov v1.8b, v9.8b
-	mov v0.8b, v8.8b
-	mov x7, x15
-	mov x6, x14
-	mov x5, x13
-	mov x4, x12
-	mov x3, x11
-	mov x2, x10
-	mov x1, x9
+	fcvt s0, d0
+	fcvt d1, s1
 	mov x0, x8
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
@@ -1374,20 +1321,13 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	fcvtzs x8, d0
-	fcvtzs x9, s1
-	fcvtzs w10, d0
-	fcvtzs w11, s1
-	fcvtzu x12, d0
-	fcvtzu x13, s1
-	fcvtzu w14, d0
-	fcvtzu w15, s1
-	mov x7, x15
-	mov x6, x14
-	mov x5, x13
-	mov x4, x12
-	mov x3, x11
-	mov x2, x10
-	mov x1, x9
+	fcvtzs x1, s1
+	fcvtzs w2, d0
+	fcvtzs w3, s1
+	fcvtzu x4, d0
+	fcvtzu x5, s1
+	fcvtzu w6, d0
+	fcvtzu w7, s1
 	mov x0, x8
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
@@ -1604,7 +1544,7 @@ L1 (SSA Block: blk0):
 	add w11, w11, w12
 	add w10, w10, w11
 	add w9, w9, w10
-	add w8, w8, w9
+	add w0, w8, w9
 	ldr s8, #8; b 8; data.f32 1.000000
 	fmul s8, s0, s8
 	ldr s9, #8; b 8; data.f32 2.000000
@@ -1663,9 +1603,7 @@ L1 (SSA Block: blk0):
 	fadd s11, s11, s12
 	fadd s10, s10, s11
 	fadd s9, s9, s10
-	fadd s8, s8, s9
-	mov v0.8b, v8.8b
-	mov x0, x8
+	fadd s0, s8, s9
 	add sp, sp, #0x10
 	ldr q27, [sp], #0x10
 	ldr q26, [sp], #0x10
@@ -1717,8 +1655,7 @@ L1 (SSA Block: blk0):
 	str w2, [sp, #0x10]
 	str x1, [x0, #0x8]
 	ldr x8, [x1, #0x8]
-	ldr x9, [x1, #0x10]
-	mov x1, x9
+	ldr x1, [x1, #0x10]
 	ldr w9, [sp, #0x10]
 	mov x3, x9
 	bl x8
@@ -1774,8 +1711,7 @@ L1 (SSA Block: blk0):
 L2:
 	ldr x9, [x1, #0x8]
 	add x8, x9, x8
-	ldr w8, [x8]
-	mov x0, x8
+	ldr w0, [x8]
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -1977,29 +1913,21 @@ L1 (SSA Block: blk0):
 	str w8, [sp, #0x2c]
 	ldr x9, [x1, #0x20]
 	str x9, [sp, #0x24]
-	ldr s8, [x1, #0x30]
-	str s8, [sp, #0x20]
-	ldr d9, [x1, #0x40]
-	str d9, [sp, #0x18]
+	ldr s0, [x1, #0x30]
+	str s0, [sp, #0x20]
+	ldr d1, [x1, #0x40]
+	str d1, [sp, #0x18]
 	str x1, [x0, #0x8]
 	bl f1
 	ldr x8, [sp, #0x10]
-	ldr w9, [x8, #0x10]
-	ldr x10, [x8, #0x20]
-	ldr s8, [x8, #0x30]
-	ldr d9, [x8, #0x40]
-	mov v3.8b, v9.8b
-	mov v2.8b, v8.8b
-	mov x3, x10
-	mov x2, x9
-	ldr d8, [sp, #0x18]
-	mov v1.8b, v8.8b
-	ldr s8, [sp, #0x20]
-	mov v0.8b, v8.8b
-	ldr x8, [sp, #0x24]
-	mov x1, x8
-	ldr w8, [sp, #0x2c]
-	mov x0, x8
+	ldr w2, [x8, #0x10]
+	ldr x3, [x8, #0x20]
+	ldr s2, [x8, #0x30]
+	ldr d3, [x8, #0x40]
+	ldr d1, [sp, #0x18]
+	ldr s0, [sp, #0x20]
+	ldr x1, [sp, #0x24]
+	ldr w0, [sp, #0x2c]
 	add sp, sp, #0x10
 	add sp, sp, #0x20
 	ldr x30, [sp], #0x10
@@ -2093,46 +2021,40 @@ L1 (SSA Block: blk0):
 	csel w8, w8, w2, hs
 	br_table_sequence x8, table_index=0
 L2 (SSA Block: blk7):
-	b #0x68 (L9)
+	b #0x54 (L9)
 L3 (SSA Block: blk8):
 L10 (SSA Block: blk5):
-	orr w8, wzr, #0xc
-	mov x0, x8
+	orr w0, wzr, #0xc
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L4 (SSA Block: blk9):
 L11 (SSA Block: blk4):
-	movz w8, #0xd, lsl 0
-	mov x0, x8
+	movz w0, #0xd, lsl 0
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L5 (SSA Block: blk10):
 L12 (SSA Block: blk3):
-	orr w8, wzr, #0xe
-	mov x0, x8
+	orr w0, wzr, #0xe
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L6 (SSA Block: blk11):
 L13 (SSA Block: blk2):
-	orr w8, wzr, #0xf
-	mov x0, x8
+	orr w0, wzr, #0xf
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L7 (SSA Block: blk12):
 L14 (SSA Block: blk1):
-	orr w8, wzr, #0x10
-	mov x0, x8
+	orr w0, wzr, #0x10
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L8 (SSA Block: blk13):
 L9 (SSA Block: blk6):
-	movz w8, #0xb, lsl 0
-	mov x0, x8
+	movz w0, #0xb, lsl 0
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
@@ -2151,8 +2073,7 @@ L1 (SSA Block: blk0):
 	mov v29.16b, v0.16b
 	mov v30.16b, v1.16b
 	ldr q8, #8; b 32; data.v128  0706050403020100 1f1e1d1c1b1a1918
-	tbl v8.16b, { v29.16b, v30.16b }, v8.16b
-	mov v0.16b, v8.16b
+	tbl v0.16b, { v29.16b, v30.16b }, v8.16b
 	add sp, sp, #0x10
 	ldr q30, [sp], #0x10
 	ldr q29, [sp], #0x10
@@ -2168,10 +2089,8 @@ L1 (SSA Block: blk0):
 	orr x27, xzr, #0x10
 	sub sp, sp, x27
 	stp x30, x27, [sp, #-0x10]!
-	str x19, [sp, #-0x10]!
-	orr x27, xzr, #0x10
-	str x27, [sp, #-0x10]!
-	ldr x8, [sp, #0x30]
+	str xzr, [sp, #-0x10]!
+	ldr x8, [sp, #0x20]
 	mov x9, xzr
 	uxtw x9, w9
 	add x10, x1, #0x10
@@ -2248,120 +2167,114 @@ L10:
 	str x14, [x13, #0x30]
 	exit_sequence x13
 L9:
-	ldaddal w4, w12, x12
-	orr w13, wzr, #0x18
-	uxtw x13, w13
-	add x14, x1, #0x10
-	ldar x14, x14
-	add x15, x13, #0x1
-	subs xzr, x14, x15
-	mov x14, x0
+	ldaddal w4, w2, x12
+	orr w12, wzr, #0x18
+	uxtw x12, w12
+	add x13, x1, #0x10
+	ldar x13, x13
+	add x14, x12, #0x1
+	subs xzr, x13, x14
+	mov x13, x0
 	b.hs #0x34, (L8)
-	movz x15, #0x4, lsl 0
-	str w15, [x14]
-	mov x15, sp
-	str x15, [x14, #0x38]
-	adr x15, #0x0
-	str x15, [x14, #0x30]
-	exit_sequence x14
+	movz x14, #0x4, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L8:
-	add x13, x10, x13
-	ldaddalb w5, w13, x13
-	orr w14, wzr, #0x20
-	uxtw x14, w14
-	add x15, x1, #0x10
-	ldar x15, x15
-	add x16, x14, #0x2
-	subs xzr, x15, x16
-	mov x15, x0
+	add x12, x10, x12
+	ldaddalb w5, w3, x12
+	orr w12, wzr, #0x20
+	uxtw x12, w12
+	add x13, x1, #0x10
+	ldar x13, x13
+	add x14, x12, #0x2
+	subs xzr, x13, x14
+	mov x13, x0
 	b.hs #0x34, (L7)
-	movz x16, #0x4, lsl 0
-	str w16, [x15]
-	mov x16, sp
-	str x16, [x15, #0x38]
-	adr x16, #0x0
-	str x16, [x15, #0x30]
-	exit_sequence x15
+	movz x14, #0x4, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L7:
-	add x14, x10, x14
-	ands xzr, x14, #0x1
-	mov x15, x0
+	add x12, x10, x12
+	ands xzr, x12, #0x1
+	mov x13, x0
 	b.eq #0x34, (L6)
-	movz x16, #0x17, lsl 0
-	str w16, [x15]
-	mov x16, sp
-	str x16, [x15, #0x38]
-	adr x16, #0x0
-	str x16, [x15, #0x30]
-	exit_sequence x15
+	movz x14, #0x17, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L6:
-	ldaddalh w6, w14, x14
-	movz w15, #0x28, lsl 0
-	uxtw x15, w15
-	add x16, x1, #0x10
-	ldar x16, x16
-	add x17, x15, #0x4
-	subs xzr, x16, x17
-	mov x16, x0
+	ldaddalh w6, w4, x12
+	movz w12, #0x28, lsl 0
+	uxtw x12, w12
+	add x13, x1, #0x10
+	ldar x13, x13
+	add x14, x12, #0x4
+	subs xzr, x13, x14
+	mov x13, x0
 	b.hs #0x34, (L5)
-	movz x17, #0x4, lsl 0
-	str w17, [x16]
-	mov x17, sp
-	str x17, [x16, #0x38]
-	adr x17, #0x0
-	str x17, [x16, #0x30]
-	exit_sequence x16
+	movz x14, #0x4, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L5:
-	add x15, x10, x15
-	ands xzr, x15, #0x3
-	mov x16, x0
+	add x12, x10, x12
+	ands xzr, x12, #0x3
+	mov x13, x0
 	b.eq #0x34, (L4)
-	movz x17, #0x17, lsl 0
-	str w17, [x16]
-	mov x17, sp
-	str x17, [x16, #0x38]
-	adr x17, #0x0
-	str x17, [x16, #0x30]
-	exit_sequence x16
+	movz x14, #0x17, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L4:
-	ldaddal w7, w15, x15
-	orr w16, wzr, #0x30
-	uxtw x16, w16
-	add x17, x1, #0x10
-	ldar x17, x17
-	add x19, x16, #0x8
-	subs xzr, x17, x19
-	mov x17, x0
+	ldaddal w7, w5, x12
+	orr w12, wzr, #0x30
+	uxtw x12, w12
+	add x13, x1, #0x10
+	ldar x13, x13
+	add x14, x12, #0x8
+	subs xzr, x13, x14
+	mov x13, x0
 	b.hs #0x34, (L3)
-	movz x19, #0x4, lsl 0
-	str w19, [x17]
-	mov x19, sp
-	str x19, [x17, #0x38]
-	adr x19, #0x0
-	str x19, [x17, #0x30]
-	exit_sequence x17
+	movz x14, #0x4, lsl 0
+	str w14, [x13]
+	mov x14, sp
+	str x14, [x13, #0x38]
+	adr x14, #0x0
+	str x14, [x13, #0x30]
+	exit_sequence x13
 L3:
-	add x10, x10, x16
+	add x10, x10, x12
 	ands xzr, x10, #0x7
 	b.eq #0x34, (L2)
-	movz x16, #0x17, lsl 0
-	str w16, [x0]
-	mov x16, sp
-	str x16, [x0, #0x38]
-	adr x16, #0x0
-	str x16, [x0, #0x30]
+	movz x12, #0x17, lsl 0
+	str w12, [x0]
+	mov x12, sp
+	str x12, [x0, #0x38]
+	adr x12, #0x0
+	str x12, [x0, #0x30]
 	exit_sequence x0
 L2:
-	ldaddal x8, x8, x10
-	mov x6, x8
-	mov x5, x15
-	mov x4, x14
-	mov x3, x13
-	mov x2, x12
+	ldaddal x8, x6, x10
 	mov x1, x11
 	mov x0, x9
 	add sp, sp, #0x10
-	ldr x19, [sp], #0x10
 	ldr x30, [sp], #0x10
 	add sp, sp, #0x10
 	ret
@@ -2392,16 +2305,14 @@ L1 (SSA Block: blk0):
 	stp x30, xzr, [sp, #-0x10]!
 	str xzr, [sp, #-0x10]!
 	ands wzr, w2, w3
-	b.ne #0x18, (L2)
+	b.ne #0x14, (L2)
 L3 (SSA Block: blk1):
-	orr w8, wzr, #0x1
-	mov x0, x8
+	orr w0, wzr, #0x1
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
 L2 (SSA Block: blk2):
-	mov x8, xzr
-	mov x0, x8
+	mov x0, xzr
 	add sp, sp, #0x10
 	ldr x30, [sp], #0x10
 	ret
diff --git a/internal/engine/wazevo/backend/regalloc/api_test.go b/internal/engine/wazevo/backend/regalloc/api_test.go
index 7642c6fd..12ad1bf6 100644
--- a/internal/engine/wazevo/backend/regalloc/api_test.go
+++ b/internal/engine/wazevo/backend/regalloc/api_test.go
@@ -46,7 +46,7 @@ func (m *mockFunction) LowestCommonAncestor(blk1, blk2 Block) Block { panic("TOD
 
 func (m *mockFunction) Idom(blk Block) Block { panic("TODO") }
 
-func (m *mockFunction) SwapAtEndOfBlock(x1, x2, tmp VReg, block Block) { panic("TODO") }
+func (m *mockFunction) SwapBefore(x1, x2, tmp VReg, instr Instr) { panic("TODO") }
 
 func (m *mockFunction) InsertMoveBefore(dst, src VReg, instr Instr) { panic("TODO") }