github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/regalloc.go (about) 1 package backend 2 3 import ( 4 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 5 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 6 ) 7 8 // RegAllocFunctionMachine is the interface for the machine specific logic that will be used in RegAllocFunction. 9 type RegAllocFunctionMachine[I regalloc.InstrConstraint] interface { 10 // InsertMoveBefore inserts the move instruction from src to dst before the given instruction. 11 InsertMoveBefore(dst, src regalloc.VReg, instr I) 12 // InsertStoreRegisterAt inserts the instruction(s) to store the given virtual register at the given instruction. 13 // If after is true, the instruction(s) will be inserted after the given instruction, otherwise before. 14 InsertStoreRegisterAt(v regalloc.VReg, instr I, after bool) I 15 // InsertReloadRegisterAt inserts the instruction(s) to reload the given virtual register at the given instruction. 16 // If after is true, the instruction(s) will be inserted after the given instruction, otherwise before. 17 InsertReloadRegisterAt(v regalloc.VReg, instr I, after bool) I 18 // ClobberedRegisters is called when the register allocation is done and the clobbered registers are known. 19 ClobberedRegisters(regs []regalloc.VReg) 20 // Swap swaps the two virtual registers after the given instruction. 21 Swap(cur I, x1, x2, tmp regalloc.VReg) 22 // LastInstrForInsertion implements LastInstrForInsertion of regalloc.Function. See its comment for details. 23 LastInstrForInsertion(begin, end I) I 24 // SSABlockLabel returns the label of the given ssa.BasicBlockID. 25 SSABlockLabel(id ssa.BasicBlockID) Label 26 } 27 28 type ( 29 // RegAllocFunction implements regalloc.Function. 30 RegAllocFunction[I regalloc.InstrConstraint, m RegAllocFunctionMachine[I]] struct { 31 m m 32 ssb ssa.Builder 33 c Compiler 34 // iter is the iterator for reversePostOrderBlocks 35 iter int 36 reversePostOrderBlocks []RegAllocBlock[I, m] 37 // labelToRegAllocBlockIndex maps label to the index of reversePostOrderBlocks. 38 labelToRegAllocBlockIndex map[Label]int 39 loopNestingForestRoots []ssa.BasicBlock 40 } 41 42 // RegAllocBlock implements regalloc.Block. 43 RegAllocBlock[I regalloc.InstrConstraint, m RegAllocFunctionMachine[I]] struct { 44 // f is the function this instruction belongs to. Used to reuse the regAllocFunctionImpl.predsSlice slice for Defs() and Uses(). 45 f *RegAllocFunction[I, m] 46 sb ssa.BasicBlock 47 l Label 48 begin, end I 49 loopNestingForestChildren []ssa.BasicBlock 50 cur I 51 id int 52 cachedLastInstrForInsertion I 53 } 54 ) 55 56 // NewRegAllocFunction returns a new RegAllocFunction. 57 func NewRegAllocFunction[I regalloc.InstrConstraint, M RegAllocFunctionMachine[I]](m M, ssb ssa.Builder, c Compiler) *RegAllocFunction[I, M] { 58 return &RegAllocFunction[I, M]{ 59 m: m, 60 ssb: ssb, 61 c: c, 62 labelToRegAllocBlockIndex: make(map[Label]int), 63 } 64 } 65 66 // AddBlock adds a new block to the function. 67 func (f *RegAllocFunction[I, M]) AddBlock(sb ssa.BasicBlock, l Label, begin, end I) { 68 i := len(f.reversePostOrderBlocks) 69 f.reversePostOrderBlocks = append(f.reversePostOrderBlocks, RegAllocBlock[I, M]{ 70 f: f, 71 sb: sb, 72 l: l, 73 begin: begin, 74 end: end, 75 id: int(sb.ID()), 76 }) 77 f.labelToRegAllocBlockIndex[l] = i 78 } 79 80 // Reset resets the function for the next compilation. 81 func (f *RegAllocFunction[I, M]) Reset() { 82 f.reversePostOrderBlocks = f.reversePostOrderBlocks[:0] 83 f.iter = 0 84 } 85 86 // StoreRegisterAfter implements regalloc.Function StoreRegisterAfter. 87 func (f *RegAllocFunction[I, M]) StoreRegisterAfter(v regalloc.VReg, instr regalloc.Instr) { 88 m := f.m 89 m.InsertStoreRegisterAt(v, instr.(I), true) 90 } 91 92 // ReloadRegisterBefore implements regalloc.Function ReloadRegisterBefore. 93 func (f *RegAllocFunction[I, M]) ReloadRegisterBefore(v regalloc.VReg, instr regalloc.Instr) { 94 m := f.m 95 m.InsertReloadRegisterAt(v, instr.(I), false) 96 } 97 98 // ReloadRegisterAfter implements regalloc.Function ReloadRegisterAfter. 99 func (f *RegAllocFunction[I, M]) ReloadRegisterAfter(v regalloc.VReg, instr regalloc.Instr) { 100 m := f.m 101 m.InsertReloadRegisterAt(v, instr.(I), true) 102 } 103 104 // StoreRegisterBefore implements regalloc.Function StoreRegisterBefore. 105 func (f *RegAllocFunction[I, M]) StoreRegisterBefore(v regalloc.VReg, instr regalloc.Instr) { 106 m := f.m 107 m.InsertStoreRegisterAt(v, instr.(I), false) 108 } 109 110 // ClobberedRegisters implements regalloc.Function ClobberedRegisters. 111 func (f *RegAllocFunction[I, M]) ClobberedRegisters(regs []regalloc.VReg) { 112 f.m.ClobberedRegisters(regs) 113 } 114 115 // SwapBefore implements regalloc.Function SwapBefore. 116 func (f *RegAllocFunction[I, M]) SwapBefore(x1, x2, tmp regalloc.VReg, instr regalloc.Instr) { 117 f.m.Swap(instr.Prev().(I), x1, x2, tmp) 118 } 119 120 // PostOrderBlockIteratorBegin implements regalloc.Function PostOrderBlockIteratorBegin. 121 func (f *RegAllocFunction[I, M]) PostOrderBlockIteratorBegin() regalloc.Block { 122 f.iter = len(f.reversePostOrderBlocks) - 1 123 return f.PostOrderBlockIteratorNext() 124 } 125 126 // PostOrderBlockIteratorNext implements regalloc.Function PostOrderBlockIteratorNext. 127 func (f *RegAllocFunction[I, M]) PostOrderBlockIteratorNext() regalloc.Block { 128 if f.iter < 0 { 129 return nil 130 } 131 b := &f.reversePostOrderBlocks[f.iter] 132 f.iter-- 133 return b 134 } 135 136 // ReversePostOrderBlockIteratorBegin implements regalloc.Function ReversePostOrderBlockIteratorBegin. 137 func (f *RegAllocFunction[I, M]) ReversePostOrderBlockIteratorBegin() regalloc.Block { 138 f.iter = 0 139 return f.ReversePostOrderBlockIteratorNext() 140 } 141 142 // ReversePostOrderBlockIteratorNext implements regalloc.Function ReversePostOrderBlockIteratorNext. 143 func (f *RegAllocFunction[I, M]) ReversePostOrderBlockIteratorNext() regalloc.Block { 144 if f.iter >= len(f.reversePostOrderBlocks) { 145 return nil 146 } 147 b := &f.reversePostOrderBlocks[f.iter] 148 f.iter++ 149 return b 150 } 151 152 // LoopNestingForestRoots implements regalloc.Function LoopNestingForestRoots. 153 func (f *RegAllocFunction[I, M]) LoopNestingForestRoots() int { 154 f.loopNestingForestRoots = f.ssb.LoopNestingForestRoots() 155 return len(f.loopNestingForestRoots) 156 } 157 158 // LoopNestingForestRoot implements regalloc.Function LoopNestingForestRoot. 159 func (f *RegAllocFunction[I, M]) LoopNestingForestRoot(i int) regalloc.Block { 160 blk := f.loopNestingForestRoots[i] 161 l := f.m.SSABlockLabel(blk.ID()) 162 index := f.labelToRegAllocBlockIndex[l] 163 return &f.reversePostOrderBlocks[index] 164 } 165 166 // InsertMoveBefore implements regalloc.Function InsertMoveBefore. 167 func (f *RegAllocFunction[I, M]) InsertMoveBefore(dst, src regalloc.VReg, instr regalloc.Instr) { 168 f.m.InsertMoveBefore(dst, src, instr.(I)) 169 } 170 171 // LowestCommonAncestor implements regalloc.Function LowestCommonAncestor. 172 func (f *RegAllocFunction[I, M]) LowestCommonAncestor(blk1, blk2 regalloc.Block) regalloc.Block { 173 ret := f.ssb.LowestCommonAncestor(blk1.(*RegAllocBlock[I, M]).sb, blk2.(*RegAllocBlock[I, M]).sb) 174 l := f.m.SSABlockLabel(ret.ID()) 175 index := f.labelToRegAllocBlockIndex[l] 176 return &f.reversePostOrderBlocks[index] 177 } 178 179 // Idom implements regalloc.Function Idom. 180 func (f *RegAllocFunction[I, M]) Idom(blk regalloc.Block) regalloc.Block { 181 builder := f.ssb 182 idom := builder.Idom(blk.(*RegAllocBlock[I, M]).sb) 183 if idom == nil { 184 panic("BUG: idom must not be nil") 185 } 186 l := f.m.SSABlockLabel(idom.ID()) 187 index := f.labelToRegAllocBlockIndex[l] 188 return &f.reversePostOrderBlocks[index] 189 } 190 191 // ID implements regalloc.Block. 192 func (r *RegAllocBlock[I, m]) ID() int32 { return int32(r.id) } 193 194 // BlockParams implements regalloc.Block. 195 func (r *RegAllocBlock[I, m]) BlockParams(regs *[]regalloc.VReg) []regalloc.VReg { 196 c := r.f.c 197 *regs = (*regs)[:0] 198 for i := 0; i < r.sb.Params(); i++ { 199 v := c.VRegOf(r.sb.Param(i)) 200 *regs = append(*regs, v) 201 } 202 return *regs 203 } 204 205 // InstrIteratorBegin implements regalloc.Block. 206 func (r *RegAllocBlock[I, m]) InstrIteratorBegin() regalloc.Instr { 207 r.cur = r.begin 208 return r.cur 209 } 210 211 // InstrIteratorNext implements regalloc.Block. 212 func (r *RegAllocBlock[I, m]) InstrIteratorNext() regalloc.Instr { 213 for { 214 if r.cur == r.end { 215 return nil 216 } 217 instr := r.cur.Next() 218 r.cur = instr.(I) 219 if instr == nil { 220 return nil 221 } else if instr.AddedBeforeRegAlloc() { 222 // Only concerned about the instruction added before regalloc. 223 return instr 224 } 225 } 226 } 227 228 // InstrRevIteratorBegin implements regalloc.Block. 229 func (r *RegAllocBlock[I, m]) InstrRevIteratorBegin() regalloc.Instr { 230 r.cur = r.end 231 return r.cur 232 } 233 234 // InstrRevIteratorNext implements regalloc.Block. 235 func (r *RegAllocBlock[I, m]) InstrRevIteratorNext() regalloc.Instr { 236 for { 237 if r.cur == r.begin { 238 return nil 239 } 240 instr := r.cur.Prev() 241 r.cur = instr.(I) 242 if instr == nil { 243 return nil 244 } else if instr.AddedBeforeRegAlloc() { 245 // Only concerned about the instruction added before regalloc. 246 return instr 247 } 248 } 249 } 250 251 // FirstInstr implements regalloc.Block. 252 func (r *RegAllocBlock[I, m]) FirstInstr() regalloc.Instr { 253 return r.begin 254 } 255 256 // EndInstr implements regalloc.Block. 257 func (r *RegAllocBlock[I, m]) EndInstr() regalloc.Instr { 258 return r.end 259 } 260 261 // LastInstrForInsertion implements regalloc.Block. 262 func (r *RegAllocBlock[I, m]) LastInstrForInsertion() regalloc.Instr { 263 var nil I 264 if r.cachedLastInstrForInsertion == nil { 265 r.cachedLastInstrForInsertion = r.f.m.LastInstrForInsertion(r.begin, r.end) 266 } 267 return r.cachedLastInstrForInsertion 268 } 269 270 // Preds implements regalloc.Block. 271 func (r *RegAllocBlock[I, m]) Preds() int { return r.sb.Preds() } 272 273 // Pred implements regalloc.Block. 274 func (r *RegAllocBlock[I, m]) Pred(i int) regalloc.Block { 275 sb := r.sb 276 pred := sb.Pred(i) 277 l := r.f.m.SSABlockLabel(pred.ID()) 278 index := r.f.labelToRegAllocBlockIndex[l] 279 return &r.f.reversePostOrderBlocks[index] 280 } 281 282 // Entry implements regalloc.Block. 283 func (r *RegAllocBlock[I, m]) Entry() bool { return r.sb.EntryBlock() } 284 285 // Succs implements regalloc.Block. 286 func (r *RegAllocBlock[I, m]) Succs() int { 287 return r.sb.Succs() 288 } 289 290 // Succ implements regalloc.Block. 291 func (r *RegAllocBlock[I, m]) Succ(i int) regalloc.Block { 292 sb := r.sb 293 succ := sb.Succ(i) 294 if succ.ReturnBlock() { 295 return nil 296 } 297 l := r.f.m.SSABlockLabel(succ.ID()) 298 index := r.f.labelToRegAllocBlockIndex[l] 299 return &r.f.reversePostOrderBlocks[index] 300 } 301 302 // LoopHeader implements regalloc.Block. 303 func (r *RegAllocBlock[I, m]) LoopHeader() bool { 304 return r.sb.LoopHeader() 305 } 306 307 // LoopNestingForestChildren implements regalloc.Block. 308 func (r *RegAllocBlock[I, m]) LoopNestingForestChildren() int { 309 r.loopNestingForestChildren = r.sb.LoopNestingForestChildren() 310 return len(r.loopNestingForestChildren) 311 } 312 313 // LoopNestingForestChild implements regalloc.Block. 314 func (r *RegAllocBlock[I, m]) LoopNestingForestChild(i int) regalloc.Block { 315 blk := r.loopNestingForestChildren[i] 316 l := r.f.m.SSABlockLabel(blk.ID()) 317 index := r.f.labelToRegAllocBlockIndex[l] 318 return &r.f.reversePostOrderBlocks[index] 319 }