github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/regalloc/api.go (about) 1 package regalloc 2 3 import "fmt" 4 5 // These interfaces are implemented by ISA-specific backends to abstract away the details, and allow the register 6 // allocators to work on any ISA. 7 // 8 // TODO: the interfaces are not stabilized yet, especially x64 will need some changes. E.g. x64 has an addressing mode 9 // where index can be in memory. That kind of info will be useful to reduce the register pressure, and should be leveraged 10 // by the register allocators, like https://docs.rs/regalloc2/latest/regalloc2/enum.OperandConstraint.html 11 12 type ( 13 // Function is the top-level interface to do register allocation, which corresponds to a CFG containing 14 // Blocks(s). 15 Function interface { 16 // PostOrderBlockIteratorBegin returns the first block in the post-order traversal of the CFG. 17 // In other words, the last blocks in the CFG will be returned first. 18 PostOrderBlockIteratorBegin() Block 19 // PostOrderBlockIteratorNext returns the next block in the post-order traversal of the CFG. 20 PostOrderBlockIteratorNext() Block 21 // ReversePostOrderBlockIteratorBegin returns the first block in the reverse post-order traversal of the CFG. 22 // In other words, the first blocks in the CFG will be returned first. 23 ReversePostOrderBlockIteratorBegin() Block 24 // ReversePostOrderBlockIteratorNext returns the next block in the reverse post-order traversal of the CFG. 25 ReversePostOrderBlockIteratorNext() Block 26 // ClobberedRegisters tell the clobbered registers by this function. 27 ClobberedRegisters([]VReg) 28 // LoopNestingForestRoots returns the number of roots of the loop nesting forest in a function. 29 LoopNestingForestRoots() int 30 // LoopNestingForestRoot returns the i-th root of the loop nesting forest in a function. 31 LoopNestingForestRoot(i int) Block 32 // LowestCommonAncestor returns the lowest common ancestor of two blocks in the dominator tree. 33 LowestCommonAncestor(blk1, blk2 Block) Block 34 // Idom returns the immediate dominator of the given block. 35 Idom(blk Block) Block 36 37 // Followings are for rewriting the function. 38 39 // SwapAtEndOfBlock swaps the two virtual registers at the end of the given block. 40 SwapBefore(x1, x2, tmp VReg, instr Instr) 41 // StoreRegisterBefore inserts store instruction(s) before the given instruction for the given virtual register. 42 StoreRegisterBefore(v VReg, instr Instr) 43 // StoreRegisterAfter inserts store instruction(s) after the given instruction for the given virtual register. 44 StoreRegisterAfter(v VReg, instr Instr) 45 // ReloadRegisterBefore inserts reload instruction(s) before the given instruction for the given virtual register. 46 ReloadRegisterBefore(v VReg, instr Instr) 47 // ReloadRegisterAfter inserts reload instruction(s) after the given instruction for the given virtual register. 48 ReloadRegisterAfter(v VReg, instr Instr) 49 // InsertMoveBefore inserts move instruction(s) before the given instruction for the given virtual registers. 50 InsertMoveBefore(dst, src VReg, instr Instr) 51 } 52 53 // Block is a basic block in the CFG of a function, and it consists of multiple instructions, and predecessor Block(s). 54 Block interface { 55 // ID returns the unique identifier of this block which is ordered in the reverse post-order traversal of the CFG. 56 ID() int32 57 // BlockParams returns the virtual registers used as the parameters of this block. 58 BlockParams(*[]VReg) []VReg 59 // InstrIteratorBegin returns the first instruction in this block. Instructions added after lowering must be skipped. 60 // Note: multiple Instr(s) will not be held at the same time, so it's safe to use the same impl for the return Instr. 61 InstrIteratorBegin() Instr 62 // InstrIteratorNext returns the next instruction in this block. Instructions added after lowering must be skipped. 63 // Note: multiple Instr(s) will not be held at the same time, so it's safe to use the same impl for the return Instr. 64 InstrIteratorNext() Instr 65 // InstrRevIteratorBegin is the same as InstrIteratorBegin, but in the reverse order. 66 InstrRevIteratorBegin() Instr 67 // InstrRevIteratorNext is the same as InstrIteratorNext, but in the reverse order. 68 InstrRevIteratorNext() Instr 69 // FirstInstr returns the fist instruction in this block where instructions will be inserted after it. 70 FirstInstr() Instr 71 // EndInstr returns the end instruction in this block. 72 EndInstr() Instr 73 // LastInstrForInsertion returns the last instruction in this block where instructions will be inserted before it. 74 // Such insertions only happen when we need to insert spill/reload instructions to adjust the merge edges. 75 // At the time of register allocation, all the critical edges are already split, so there is no need 76 // to worry about the case where branching instruction has multiple successors. 77 // Therefore, usually, it is the nop instruction, but if the block ends with an unconditional branching, then it returns 78 // the unconditional branch, not the nop. In other words it is either nop or unconditional branch. 79 LastInstrForInsertion() Instr 80 // Preds returns the number of predecessors of this block in the CFG. 81 Preds() int 82 // Pred returns the i-th predecessor of this block in the CFG. 83 Pred(i int) Block 84 // Entry returns true if the block is for the entry block. 85 Entry() bool 86 // Succs returns the number of successors of this block in the CFG. 87 Succs() int 88 // Succ returns the i-th successor of this block in the CFG. 89 Succ(i int) Block 90 // LoopHeader returns true if this block is a loop header. 91 LoopHeader() bool 92 // LoopNestingForestChildren returns the number of children of this block in the loop nesting forest. 93 LoopNestingForestChildren() int 94 // LoopNestingForestChild returns the i-th child of this block in the loop nesting forest. 95 LoopNestingForestChild(i int) Block 96 } 97 98 // Instr is an instruction in a block, abstracting away the underlying ISA. 99 Instr interface { 100 fmt.Stringer 101 // Next returns the next instruction in the same block. 102 Next() Instr 103 // Prev returns the previous instruction in the same block. 104 Prev() Instr 105 // Defs returns the virtual registers defined by this instruction. 106 Defs(*[]VReg) []VReg 107 // Uses returns the virtual registers used by this instruction. 108 // Note: multiple returned []VReg will not be held at the same time, so it's safe to use the same slice for this. 109 Uses(*[]VReg) []VReg 110 // AssignUse assigns the RealReg-allocated virtual register used by this instruction at the given index. 111 AssignUse(index int, v VReg) 112 // AssignDef assigns a RealReg-allocated virtual register defined by this instruction. 113 // This only accepts one register because we don't allocate registers for multi-def instructions (i.e. call instruction) 114 AssignDef(VReg) 115 // IsCopy returns true if this instruction is a move instruction between two registers. 116 // If true, the instruction is of the form of dst = src, and if the src and dst do not interfere with each other, 117 // we could coalesce them, and hence the copy can be eliminated from the final code. 118 IsCopy() bool 119 // IsCall returns true if this instruction is a call instruction. The result is used to insert 120 // caller saved register spills and restores. 121 IsCall() bool 122 // IsIndirectCall returns true if this instruction is an indirect call instruction which calls a function pointer. 123 // The result is used to insert caller saved register spills and restores. 124 IsIndirectCall() bool 125 // IsReturn returns true if this instruction is a return instruction. 126 IsReturn() bool 127 // AddedBeforeRegAlloc returns true if this instruction is added before register allocation. 128 AddedBeforeRegAlloc() bool 129 } 130 131 // InstrConstraint is an interface for arch-specific instruction constraints. 132 InstrConstraint interface { 133 comparable 134 Instr 135 } 136 )