github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/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 int 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 defs, uses []VReg 40 isCopy, isCall, isIndirect bool 41 } 42 ) 43 44 func (m *mockFunction) LowestCommonAncestor(blk1, blk2 Block) Block { panic("TODO") } 45 46 func (m *mockFunction) Idom(blk Block) Block { panic("TODO") } 47 48 func (m *mockFunction) SwapAtEndOfBlock(x1, x2, tmp VReg, block Block) { panic("TODO") } 49 50 func (m *mockFunction) InsertMoveBefore(dst, src VReg, instr Instr) { panic("TODO") } 51 52 func newMockFunction(blocks ...*mockBlock) *mockFunction { 53 return &mockFunction{blocks: blocks} 54 } 55 56 func (m *mockFunction) loopNestingForestRoots(blocks ...*mockBlock) { 57 m.lnfRoots = blocks 58 } 59 60 func newMockBlock(id int, instructions ...*mockInstr) *mockBlock { 61 return &mockBlock{id: id, instructions: instructions} 62 } 63 64 func newMockInstr() *mockInstr { 65 return &mockInstr{} 66 } 67 68 // String implements fmt.Stringer for debugging. 69 func (m *mockFunction) String() string { 70 var block []string 71 for _, b := range m.blocks { 72 block = append(block, "\t"+b.String()) 73 } 74 return fmt.Sprintf("mockFunction:\n%s", strings.Join(block, ",\n")) 75 } 76 77 // String implements fmt.Stringer for debugging. 78 func (m *mockInstr) String() string { 79 return fmt.Sprintf("mockInstr{defs=%v, uses=%v}", m.defs, m.uses) 80 } 81 82 // String implements fmt.Stringer for debugging. 83 func (m *mockBlock) String() string { 84 var preds []int 85 for _, p := range m.preds { 86 preds = append(preds, p.id) 87 } 88 return fmt.Sprintf("mockBlock{\n\tid=%v,\n\tinstructions=%v,\n\tpreds=%v,\n}", m.id, preds, m.instructions) 89 } 90 91 func (m *mockBlock) addPred(b *mockBlock) { 92 m.preds = append(m.preds, b) 93 m._preds = append(m._preds, b) 94 b._succs = append(b._succs, m) 95 b.succs = append(b.succs, m) 96 } 97 98 func (m *mockInstr) use(uses ...VReg) *mockInstr { 99 m.uses = uses 100 return m 101 } 102 103 func (m *mockInstr) def(defs ...VReg) *mockInstr { 104 m.defs = defs 105 return m 106 } 107 108 func (m *mockBlock) loop(children ...*mockBlock) *mockBlock { 109 m._loop = true 110 m.lnfChildren = children 111 return m 112 } 113 114 func (m *mockBlock) entry() *mockBlock { 115 m._entry = true 116 return m 117 } 118 119 func (m *mockInstr) asCopy() *mockInstr { 120 m.isCopy = true 121 return m 122 } 123 124 func (m *mockInstr) asCall() *mockInstr { //nolint:unused 125 m.isCall = true 126 return m 127 } 128 129 func (m *mockInstr) asIndirectCall() *mockInstr { //nolint:unused 130 m.isIndirect = true 131 return m 132 } 133 134 // StoreRegisterAfter implements Function.StoreRegisterAfter. 135 func (m *mockFunction) StoreRegisterAfter(v VReg, instr Instr) { 136 m.afters = append(m.afters, storeOrReloadInfo{false, v, instr}) 137 } 138 139 // ReloadRegisterBefore implements Function.ReloadRegisterBefore. 140 func (m *mockFunction) ReloadRegisterBefore(v VReg, instr Instr) { 141 m.befores = append(m.befores, storeOrReloadInfo{true, v, instr}) 142 } 143 144 // StoreRegisterBefore implements Function.StoreRegisterBefore. 145 func (m *mockFunction) StoreRegisterBefore(v VReg, instr Instr) { 146 m.befores = append(m.befores, storeOrReloadInfo{false, v, instr}) 147 } 148 149 // ReloadRegisterAfter implements Function.ReloadRegisterAfter. 150 func (m *mockFunction) ReloadRegisterAfter(v VReg, instr Instr) { 151 m.afters = append(m.afters, storeOrReloadInfo{true, v, instr}) 152 } 153 154 // ClobberedRegisters implements Function.ClobberedRegisters. 155 func (m *mockFunction) ClobberedRegisters(regs []VReg) { 156 // TODO implement me 157 panic("implement me") 158 } 159 160 // Done implements Function.Done. 161 func (m *mockFunction) Done() {} 162 163 // PostOrderBlockIteratorBegin implements Block. 164 func (m *mockFunction) PostOrderBlockIteratorBegin() Block { 165 m.iter = 1 166 l := len(m.blocks) 167 return m.blocks[l-1] 168 } 169 170 // PostOrderBlockIteratorNext implements Block. 171 func (m *mockFunction) PostOrderBlockIteratorNext() Block { 172 if m.iter == len(m.blocks) { 173 return nil 174 } 175 l := len(m.blocks) 176 ret := m.blocks[l-m.iter-1] 177 m.iter++ 178 return ret 179 } 180 181 // ReversePostOrderBlockIteratorBegin implements Block. 182 func (m *mockFunction) ReversePostOrderBlockIteratorBegin() Block { 183 m.iter = 1 184 return m.blocks[0] 185 } 186 187 // ReversePostOrderBlockIteratorNext implements Block. 188 func (m *mockFunction) ReversePostOrderBlockIteratorNext() Block { 189 if m.iter == len(m.blocks) { 190 return nil 191 } 192 ret := m.blocks[m.iter] 193 m.iter++ 194 return ret 195 } 196 197 // ID implements Block. 198 func (m *mockBlock) ID() int { 199 return m.id 200 } 201 202 // InstrIteratorBegin implements Block. 203 func (m *mockBlock) InstrIteratorBegin() Instr { 204 if len(m.instructions) == 0 { 205 return nil 206 } 207 m.iter = 1 208 return m.instructions[0] 209 } 210 211 // InstrIteratorNext implements Block. 212 func (m *mockBlock) InstrIteratorNext() Instr { 213 if m.iter == len(m.instructions) { 214 return nil 215 } 216 ret := m.instructions[m.iter] 217 m.iter++ 218 return ret 219 } 220 221 // InstrRevIteratorBegin implements Block. 222 func (m *mockBlock) InstrRevIteratorBegin() Instr { 223 if len(m.instructions) == 0 { 224 return nil 225 } 226 m.iter = len(m.instructions) 227 return m.InstrRevIteratorNext() 228 } 229 230 // InstrRevIteratorNext implements Block. 231 func (m *mockBlock) InstrRevIteratorNext() Instr { 232 m.iter-- 233 if m.iter < 0 { 234 return nil 235 } 236 return m.instructions[m.iter] 237 } 238 239 // Preds implements Block. 240 func (m *mockBlock) Preds() int { 241 return len(m._preds) 242 } 243 244 // BlockParams implements Block. 245 func (m *mockBlock) BlockParams(ret *[]VReg) []VReg { 246 *ret = append((*ret)[:0], m.blockParams...) 247 return *ret 248 } 249 250 func (m *mockBlock) blockParam(v VReg) { 251 m.blockParams = append(m.blockParams, v) 252 } 253 254 // Pred implements Instr. 255 func (m *mockBlock) Pred(i int) Block { return m._preds[i] } 256 257 // Defs implements Instr. 258 func (m *mockInstr) Defs(ret *[]VReg) []VReg { 259 *ret = append((*ret)[:0], m.defs...) 260 return *ret 261 } 262 263 // Uses implements Instr. 264 func (m *mockInstr) Uses(ret *[]VReg) []VReg { 265 *ret = append((*ret)[:0], m.uses...) 266 return *ret 267 } 268 269 // IsCopy implements Instr. 270 func (m *mockInstr) IsCopy() bool { return m.isCopy } 271 272 // IsCall implements Instr. 273 func (m *mockInstr) IsCall() bool { return m.isCall } 274 275 // IsIndirectCall implements Instr. 276 func (m *mockInstr) IsIndirectCall() bool { return m.isIndirect } 277 278 // IsReturn implements Instr. 279 func (m *mockInstr) IsReturn() bool { return false } 280 281 // Entry implements Entry. 282 func (m *mockBlock) Entry() bool { return m._entry } 283 284 // AssignUses implements Instr. 285 func (m *mockInstr) AssignUse(index int, reg VReg) { 286 if index >= len(m.uses) { 287 m.uses = append(m.uses, make([]VReg, 5)...) 288 } 289 m.uses[index] = reg 290 } 291 292 // AssignDef implements Instr. 293 func (m *mockInstr) AssignDef(reg VReg) { 294 m.defs = []VReg{reg} 295 } 296 297 var ( 298 _ Function = (*mockFunction)(nil) 299 _ Block = (*mockBlock)(nil) 300 _ Instr = (*mockInstr)(nil) 301 ) 302 303 func (m *mockFunction) LoopNestingForestRoots() int { 304 return len(m.lnfRoots) 305 } 306 307 func (m *mockFunction) LoopNestingForestRoot(i int) Block { 308 return m.lnfRoots[i] 309 } 310 311 func (m *mockBlock) LoopHeader() bool { 312 return m._loop 313 } 314 315 func (m *mockBlock) Succs() int { 316 return len(m.succs) 317 } 318 319 func (m *mockBlock) Succ(i int) Block { 320 return m.succs[i] 321 } 322 323 func (m *mockBlock) LoopNestingForestChildren() int { 324 return len(m.lnfChildren) 325 } 326 327 func (m *mockBlock) LoopNestingForestChild(i int) Block { 328 return m.lnfChildren[i] 329 } 330 331 func (m *mockBlock) LastInstr() Instr { 332 return m.instructions[len(m.instructions)-1] 333 } 334 335 func (m *mockBlock) FirstInstr() Instr { 336 return m.instructions[0] 337 }