github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go (about) 1 package arm64 2 3 // This file implements the interfaces required for register allocations. See backend.RegAllocFunctionMachine. 4 5 import ( 6 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend" 7 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 8 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 9 ) 10 11 // ClobberedRegisters implements backend.RegAllocFunctionMachine. 12 func (m *machine) ClobberedRegisters(regs []regalloc.VReg) { 13 m.clobberedRegs = append(m.clobberedRegs[:0], regs...) 14 } 15 16 // Swap implements backend.RegAllocFunctionMachine. 17 func (m *machine) Swap(cur *instruction, x1, x2, tmp regalloc.VReg) { 18 prevNext := cur.next 19 var mov1, mov2, mov3 *instruction 20 if x1.RegType() == regalloc.RegTypeInt { 21 if !tmp.Valid() { 22 tmp = tmpRegVReg 23 } 24 mov1 = m.allocateInstr().asMove64(tmp, x1) 25 mov2 = m.allocateInstr().asMove64(x1, x2) 26 mov3 = m.allocateInstr().asMove64(x2, tmp) 27 cur = linkInstr(cur, mov1) 28 cur = linkInstr(cur, mov2) 29 cur = linkInstr(cur, mov3) 30 linkInstr(cur, prevNext) 31 } else { 32 if !tmp.Valid() { 33 r2 := x2.RealReg() 34 // Temporarily spill x1 to stack. 35 cur = m.InsertStoreRegisterAt(x1, cur, true).prev 36 // Then move x2 to x1. 37 cur = linkInstr(cur, m.allocateInstr().asFpuMov128(x1, x2)) 38 linkInstr(cur, prevNext) 39 // Then reload the original value on x1 from stack to r2. 40 m.InsertReloadRegisterAt(x1.SetRealReg(r2), cur, true) 41 } else { 42 mov1 = m.allocateInstr().asFpuMov128(tmp, x1) 43 mov2 = m.allocateInstr().asFpuMov128(x1, x2) 44 mov3 = m.allocateInstr().asFpuMov128(x2, tmp) 45 cur = linkInstr(cur, mov1) 46 cur = linkInstr(cur, mov2) 47 cur = linkInstr(cur, mov3) 48 linkInstr(cur, prevNext) 49 } 50 } 51 } 52 53 // InsertMoveBefore implements backend.RegAllocFunctionMachine. 54 func (m *machine) InsertMoveBefore(dst, src regalloc.VReg, instr *instruction) { 55 typ := src.RegType() 56 if typ != dst.RegType() { 57 panic("BUG: src and dst must have the same type") 58 } 59 60 mov := m.allocateInstr() 61 if typ == regalloc.RegTypeInt { 62 mov.asMove64(dst, src) 63 } else { 64 mov.asFpuMov128(dst, src) 65 } 66 67 cur := instr.prev 68 prevNext := cur.next 69 cur = linkInstr(cur, mov) 70 linkInstr(cur, prevNext) 71 } 72 73 // SSABlockLabel implements backend.RegAllocFunctionMachine. 74 func (m *machine) SSABlockLabel(id ssa.BasicBlockID) backend.Label { 75 return m.executableContext.SsaBlockIDToLabels[id] 76 } 77 78 // InsertStoreRegisterAt implements backend.RegAllocFunctionMachine. 79 func (m *machine) InsertStoreRegisterAt(v regalloc.VReg, instr *instruction, after bool) *instruction { 80 if !v.IsRealReg() { 81 panic("BUG: VReg must be backed by real reg to be stored") 82 } 83 84 typ := m.compiler.TypeOf(v) 85 86 var prevNext, cur *instruction 87 if after { 88 cur, prevNext = instr, instr.next 89 } else { 90 cur, prevNext = instr.prev, instr 91 } 92 93 offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size()) 94 var amode addressMode 95 cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true) 96 store := m.allocateInstr() 97 store.asStore(operandNR(v), amode, typ.Bits()) 98 99 cur = linkInstr(cur, store) 100 return linkInstr(cur, prevNext) 101 } 102 103 // InsertReloadRegisterAt implements backend.RegAllocFunctionMachine. 104 func (m *machine) InsertReloadRegisterAt(v regalloc.VReg, instr *instruction, after bool) *instruction { 105 if !v.IsRealReg() { 106 panic("BUG: VReg must be backed by real reg to be stored") 107 } 108 109 typ := m.compiler.TypeOf(v) 110 111 var prevNext, cur *instruction 112 if after { 113 cur, prevNext = instr, instr.next 114 } else { 115 cur, prevNext = instr.prev, instr 116 } 117 118 offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size()) 119 var amode addressMode 120 cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true) 121 load := m.allocateInstr() 122 switch typ { 123 case ssa.TypeI32, ssa.TypeI64: 124 load.asULoad(operandNR(v), amode, typ.Bits()) 125 case ssa.TypeF32, ssa.TypeF64: 126 load.asFpuLoad(operandNR(v), amode, typ.Bits()) 127 case ssa.TypeV128: 128 load.asFpuLoad(operandNR(v), amode, 128) 129 default: 130 panic("TODO") 131 } 132 133 cur = linkInstr(cur, load) 134 return linkInstr(cur, prevNext) 135 } 136 137 // LastInstrForInsertion implements backend.RegAllocFunctionMachine. 138 func (m *machine) LastInstrForInsertion(begin, end *instruction) *instruction { 139 cur := end 140 for cur.kind == nop0 { 141 cur = cur.prev 142 if cur == begin { 143 return end 144 } 145 } 146 switch cur.kind { 147 case br: 148 return cur 149 default: 150 return end 151 } 152 }