github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/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  		// Done tells the implementation that register allocation is done, and it can finalize the stack
    29  		Done()
    30  		// LoopNestingForestRoots returns the number of roots of the loop nesting forest in a function.
    31  		LoopNestingForestRoots() int
    32  		// LoopNestingForestRoot returns the i-th root of the loop nesting forest in a function.
    33  		LoopNestingForestRoot(i int) Block
    34  		// LowestCommonAncestor returns the lowest common ancestor of two blocks in the dominator tree.
    35  		LowestCommonAncestor(blk1, blk2 Block) Block
    36  		// Idom returns the immediate dominator of the given block.
    37  		Idom(blk Block) Block
    38  
    39  		// Followings are for rewriting the function.
    40  
    41  		// SwapAtEndOfBlock swaps the two virtual registers at the end of the given block.
    42  		SwapAtEndOfBlock(x1, x2, tmp VReg, block Block)
    43  		// StoreRegisterBefore inserts store instruction(s) before the given instruction for the given virtual register.
    44  		StoreRegisterBefore(v VReg, instr Instr)
    45  		// StoreRegisterAfter inserts store instruction(s) after the given instruction for the given virtual register.
    46  		StoreRegisterAfter(v VReg, instr Instr)
    47  		// ReloadRegisterBefore inserts reload instruction(s) before the given instruction for the given virtual register.
    48  		ReloadRegisterBefore(v VReg, instr Instr)
    49  		// ReloadRegisterAfter inserts reload instruction(s) after the given instruction for the given virtual register.
    50  		ReloadRegisterAfter(v VReg, instr Instr)
    51  		// InsertMoveBefore inserts move instruction(s) before the given instruction for the given virtual registers.
    52  		InsertMoveBefore(dst, src VReg, instr Instr)
    53  	}
    54  
    55  	// Block is a basic block in the CFG of a function, and it consists of multiple instructions, and predecessor Block(s).
    56  	Block interface {
    57  		// ID returns the unique identifier of this block which is ordered in the reverse post-order traversal of the CFG.
    58  		ID() int
    59  		// BlockParams returns the virtual registers used as the parameters of this block.
    60  		BlockParams(*[]VReg) []VReg
    61  		// InstrIteratorBegin returns the first instruction in this block. Instructions added after lowering must be skipped.
    62  		// 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.
    63  		InstrIteratorBegin() Instr
    64  		// InstrIteratorNext returns the next instruction in this block. Instructions added after lowering must be skipped.
    65  		// 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.
    66  		InstrIteratorNext() Instr
    67  		// InstrRevIteratorBegin is the same as InstrIteratorBegin, but in the reverse order.
    68  		InstrRevIteratorBegin() Instr
    69  		// InstrRevIteratorNext is the same as InstrIteratorNext, but in the reverse order.
    70  		InstrRevIteratorNext() Instr
    71  		// FirstInstr returns the fist instruction in this block where instructions will be inserted after it.
    72  		FirstInstr() Instr
    73  		// LastInstr 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  		// If the very last instruction is the unconditional branching, then the returned instruction is the one before it.
    76  		// Note that at the time of register allocation, all the critical edges are already split, so there is no need
    77  		// to worry about the case where branching instruction has multiple successors.
    78  		LastInstr() Instr
    79  		// Preds returns the number of predecessors of this block in the CFG.
    80  		Preds() int
    81  		// Pred returns the i-th predecessor of this block in the CFG.
    82  		Pred(i int) Block
    83  		// Entry returns true if the block is for the entry block.
    84  		Entry() bool
    85  		// Succs returns the number of successors of this block in the CFG.
    86  		Succs() int
    87  		// Succ returns the i-th successor of this block in the CFG.
    88  		Succ(i int) Block
    89  		// LoopHeader returns true if this block is a loop header.
    90  		LoopHeader() bool
    91  		// LoopNestingForestChildren returns the number of children of this block in the loop nesting forest.
    92  		LoopNestingForestChildren() int
    93  		// LoopNestingForestChild returns the i-th child of this block in the loop nesting forest.
    94  		LoopNestingForestChild(i int) Block
    95  	}
    96  
    97  	// Instr is an instruction in a block, abstracting away the underlying ISA.
    98  	Instr interface {
    99  		fmt.Stringer
   100  
   101  		// Defs returns the virtual registers defined by this instruction.
   102  		Defs(*[]VReg) []VReg
   103  		// Uses returns the virtual registers used by this instruction.
   104  		// Note: multiple returned []VReg will not be held at the same time, so it's safe to use the same slice for this.
   105  		Uses(*[]VReg) []VReg
   106  		// AssignUse assigns the RealReg-allocated virtual register used by this instruction at the given index.
   107  		AssignUse(index int, v VReg)
   108  		// AssignDef assigns a RealReg-allocated virtual register defined by this instruction.
   109  		// This only accepts one register because we don't allocate registers for multi-def instructions (i.e. call instruction)
   110  		AssignDef(VReg)
   111  		// IsCopy returns true if this instruction is a move instruction between two registers.
   112  		// If true, the instruction is of the form of dst = src, and if the src and dst do not interfere with each other,
   113  		// we could coalesce them, and hence the copy can be eliminated from the final code.
   114  		IsCopy() bool
   115  		// IsCall returns true if this instruction is a call instruction. The result is used to insert
   116  		// caller saved register spills and restores.
   117  		IsCall() bool
   118  		// IsIndirectCall returns true if this instruction is an indirect call instruction which calls a function pointer.
   119  		//  The result is used to insert caller saved register spills and restores.
   120  		IsIndirectCall() bool
   121  		// IsReturn returns true if this instruction is a return instruction.
   122  		IsReturn() bool
   123  	}
   124  )