github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/regalloc/api_test.go (about) 1 package regalloc 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // Following mock types are used for testing. 9 type ( 10 // mockFunction implements Function. 11 mockFunction struct { 12 iter int 13 blocks []*mockBlock 14 befores, afters []storeOrReloadInfo 15 lnfRoots []*mockBlock 16 } 17 18 storeOrReloadInfo struct { 19 reload bool 20 v VReg 21 instr Instr 22 } 23 24 // mockBlock implements Block. 25 mockBlock struct { 26 id int32 27 instructions []*mockInstr 28 preds, succs []*mockBlock 29 _preds, _succs []Block 30 iter int 31 _entry bool 32 _loop bool 33 lnfChildren []*mockBlock 34 blockParams []VReg 35 } 36 37 // mockInstr implements Instr. 38 mockInstr struct { 39 next, prev *mockInstr 40 defs, uses []VReg 41 isCopy, isCall, isIndirect bool 42 } 43 ) 44 45 func (m *mockFunction) LowestCommonAncestor(blk1, blk2 Block) Block { panic("TODO") } 46 47 func (m *mockFunction) Idom(blk Block) Block { panic("TODO") } 48 49 func (m *mockFunction) SwapBefore(x1, x2, tmp VReg, instr Instr) { panic("TODO") } 50 51 func (m *mockFunction) InsertMoveBefore(dst, src VReg, instr Instr) { panic("TODO") } 52 53 func newMockFunction(blocks ...*mockBlock) *mockFunction { 54 return &mockFunction{blocks: blocks} 55 } 56 57 func (m *mockFunction) loopNestingForestRoots(blocks ...*mockBlock) { 58 m.lnfRoots = blocks 59 } 60 61 func newMockBlock(id int32, instructions ...*mockInstr) *mockBlock { 62 if len(instructions) > 0 { 63 instructions[0].prev = nil 64 for i := 1; i < len(instructions); i++ { 65 instructions[i].prev = instructions[i-1] 66 instructions[i-1].next = instructions[i] 67 } 68 instructions[len(instructions)-1].next = nil 69 } 70 return &mockBlock{id: id, instructions: instructions} 71 } 72 73 func newMockInstr() *mockInstr { 74 return &mockInstr{} 75 } 76 77 // String implements fmt.Stringer for debugging. 78 func (m *mockFunction) String() string { 79 var block []string 80 for _, b := range m.blocks { 81 block = append(block, "\t"+b.String()) 82 } 83 return fmt.Sprintf("mockFunction:\n%s", strings.Join(block, ",\n")) 84 } 85 86 // String implements fmt.Stringer for debugging. 87 func (m *mockInstr) String() string { 88 return fmt.Sprintf("mockInstr{defs=%v, uses=%v}", m.defs, m.uses) 89 } 90 91 // String implements fmt.Stringer for debugging. 92 func (m *mockBlock) String() string { 93 var preds []int32 94 for _, p := range m.preds { 95 preds = append(preds, p.id) 96 } 97 return fmt.Sprintf("mockBlock{\n\tid=%v,\n\tinstructions=%v,\n\tpreds=%v,\n}", m.id, preds, m.instructions) 98 } 99 100 func (m *mockBlock) addPred(b *mockBlock) { 101 m.preds = append(m.preds, b) 102 m._preds = append(m._preds, b) 103 b._succs = append(b._succs, m) 104 b.succs = append(b.succs, m) 105 } 106 107 func (m *mockInstr) use(uses ...VReg) *mockInstr { 108 m.uses = uses 109 return m 110 } 111 112 func (m *mockInstr) def(defs ...VReg) *mockInstr { 113 m.defs = defs 114 return m 115 } 116 117 func (m *mockBlock) loop(children ...*mockBlock) *mockBlock { 118 m._loop = true 119 m.lnfChildren = children 120 return m 121 } 122 123 func (m *mockBlock) entry() *mockBlock { 124 m._entry = true 125 return m 126 } 127 128 func (m *mockInstr) asCopy() *mockInstr { 129 m.isCopy = true 130 return m 131 } 132 133 func (m *mockInstr) asCall() *mockInstr { //nolint:unused 134 m.isCall = true 135 return m 136 } 137 138 func (m *mockInstr) asIndirectCall() *mockInstr { //nolint:unused 139 m.isIndirect = true 140 return m 141 } 142 143 // StoreRegisterAfter implements Function.StoreRegisterAfter. 144 func (m *mockFunction) StoreRegisterAfter(v VReg, instr Instr) { 145 m.afters = append(m.afters, storeOrReloadInfo{false, v, instr}) 146 } 147 148 // ReloadRegisterBefore implements Function.ReloadRegisterBefore. 149 func (m *mockFunction) ReloadRegisterBefore(v VReg, instr Instr) { 150 m.befores = append(m.befores, storeOrReloadInfo{true, v, instr}) 151 } 152 153 // StoreRegisterBefore implements Function.StoreRegisterBefore. 154 func (m *mockFunction) StoreRegisterBefore(v VReg, instr Instr) { 155 m.befores = append(m.befores, storeOrReloadInfo{false, v, instr}) 156 } 157 158 // ReloadRegisterAfter implements Function.ReloadRegisterAfter. 159 func (m *mockFunction) ReloadRegisterAfter(v VReg, instr Instr) { 160 m.afters = append(m.afters, storeOrReloadInfo{true, v, instr}) 161 } 162 163 // ClobberedRegisters implements Function.ClobberedRegisters. 164 func (m *mockFunction) ClobberedRegisters(regs []VReg) { 165 // TODO implement me 166 panic("implement me") 167 } 168 169 // Done implements Function.Done. 170 func (m *mockFunction) Done() {} 171 172 // PostOrderBlockIteratorBegin implements Block. 173 func (m *mockFunction) PostOrderBlockIteratorBegin() Block { 174 m.iter = 1 175 l := len(m.blocks) 176 return m.blocks[l-1] 177 } 178 179 // PostOrderBlockIteratorNext implements Block. 180 func (m *mockFunction) PostOrderBlockIteratorNext() Block { 181 if m.iter == len(m.blocks) { 182 return nil 183 } 184 l := len(m.blocks) 185 ret := m.blocks[l-m.iter-1] 186 m.iter++ 187 return ret 188 } 189 190 // ReversePostOrderBlockIteratorBegin implements Block. 191 func (m *mockFunction) ReversePostOrderBlockIteratorBegin() Block { 192 m.iter = 1 193 return m.blocks[0] 194 } 195 196 // ReversePostOrderBlockIteratorNext implements Block. 197 func (m *mockFunction) ReversePostOrderBlockIteratorNext() Block { 198 if m.iter == len(m.blocks) { 199 return nil 200 } 201 ret := m.blocks[m.iter] 202 m.iter++ 203 return ret 204 } 205 206 // ID implements Block. 207 func (m *mockBlock) ID() int32 { 208 return m.id 209 } 210 211 // InstrIteratorBegin implements Block. 212 func (m *mockBlock) InstrIteratorBegin() Instr { 213 if len(m.instructions) == 0 { 214 return nil 215 } 216 m.iter = 1 217 return m.instructions[0] 218 } 219 220 // InstrIteratorNext implements Block. 221 func (m *mockBlock) InstrIteratorNext() Instr { 222 if m.iter == len(m.instructions) { 223 return nil 224 } 225 ret := m.instructions[m.iter] 226 m.iter++ 227 return ret 228 } 229 230 // InstrRevIteratorBegin implements Block. 231 func (m *mockBlock) InstrRevIteratorBegin() Instr { 232 if len(m.instructions) == 0 { 233 return nil 234 } 235 m.iter = len(m.instructions) 236 return m.InstrRevIteratorNext() 237 } 238 239 // InstrRevIteratorNext implements Block. 240 func (m *mockBlock) InstrRevIteratorNext() Instr { 241 m.iter-- 242 if m.iter < 0 { 243 return nil 244 } 245 return m.instructions[m.iter] 246 } 247 248 // Preds implements Block. 249 func (m *mockBlock) Preds() int { 250 return len(m._preds) 251 } 252 253 // BlockParams implements Block. 254 func (m *mockBlock) BlockParams(ret *[]VReg) []VReg { 255 *ret = append((*ret)[:0], m.blockParams...) 256 return *ret 257 } 258 259 func (m *mockBlock) blockParam(v VReg) { 260 m.blockParams = append(m.blockParams, v) 261 } 262 263 // Pred implements Instr. 264 func (m *mockBlock) Pred(i int) Block { return m._preds[i] } 265 266 // Defs implements Instr. 267 func (m *mockInstr) Defs(ret *[]VReg) []VReg { 268 *ret = append((*ret)[:0], m.defs...) 269 return *ret 270 } 271 272 // AddedBeforeRegAlloc implements Instr. 273 func (m *mockInstr) AddedBeforeRegAlloc() bool { return true } 274 275 // Uses implements Instr. 276 func (m *mockInstr) Uses(ret *[]VReg) []VReg { 277 *ret = append((*ret)[:0], m.uses...) 278 return *ret 279 } 280 281 // IsCopy implements Instr. 282 func (m *mockInstr) IsCopy() bool { return m.isCopy } 283 284 // IsCall implements Instr. 285 func (m *mockInstr) IsCall() bool { return m.isCall } 286 287 // IsIndirectCall implements Instr. 288 func (m *mockInstr) IsIndirectCall() bool { return m.isIndirect } 289 290 // IsReturn implements Instr. 291 func (m *mockInstr) IsReturn() bool { return false } 292 293 // Next implements Instr. 294 func (m *mockInstr) Next() Instr { return m.next } 295 296 // Prev implements Instr. 297 func (m *mockInstr) Prev() Instr { return m.prev } 298 299 // Entry implements Entry. 300 func (m *mockBlock) Entry() bool { return m._entry } 301 302 // AssignUses implements Instr. 303 func (m *mockInstr) AssignUse(index int, reg VReg) { 304 if index >= len(m.uses) { 305 m.uses = append(m.uses, make([]VReg, 5)...) 306 } 307 m.uses[index] = reg 308 } 309 310 // AssignDef implements Instr. 311 func (m *mockInstr) AssignDef(reg VReg) { 312 m.defs = []VReg{reg} 313 } 314 315 var ( 316 _ Function = (*mockFunction)(nil) 317 _ Block = (*mockBlock)(nil) 318 _ Instr = (*mockInstr)(nil) 319 ) 320 321 func (m *mockFunction) LoopNestingForestRoots() int { 322 return len(m.lnfRoots) 323 } 324 325 func (m *mockFunction) LoopNestingForestRoot(i int) Block { 326 return m.lnfRoots[i] 327 } 328 329 func (m *mockBlock) LoopHeader() bool { 330 return m._loop 331 } 332 333 func (m *mockBlock) Succs() int { 334 return len(m.succs) 335 } 336 337 func (m *mockBlock) Succ(i int) Block { 338 return m.succs[i] 339 } 340 341 func (m *mockBlock) LoopNestingForestChildren() int { 342 return len(m.lnfChildren) 343 } 344 345 func (m *mockBlock) LoopNestingForestChild(i int) Block { 346 return m.lnfChildren[i] 347 } 348 349 func (m *mockBlock) BeginInstr() Instr { 350 if len(m.instructions) == 0 { 351 return nil 352 } 353 return m.instructions[0] 354 } 355 356 func (m *mockBlock) EndInstr() Instr { 357 if len(m.instructions) == 0 { 358 return nil 359 } 360 return m.instructions[len(m.instructions)-1] 361 } 362 363 func (m *mockBlock) LastInstrForInsertion() Instr { 364 if len(m.instructions) == 0 { 365 return nil 366 } 367 return m.instructions[len(m.instructions)-1] 368 } 369 370 func (m *mockBlock) FirstInstr() Instr { 371 return m.instructions[0] 372 }