package regalloc
import "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
Package regalloc performs register allocation. The algorithm can work on any ISA by implementing the interfaces in api.go.
References:
- https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/lectures/17/Slides17.pdf
- https://en.wikipedia.org/wiki/Chaitin%27s_algorithm
- https://llvm.org/ProjectsWithLLVM/2004-Fall-CS426-LS.pdf
- https://pfalcon.github.io/ssabook/latest/book-full.pdf: Chapter 9. for liveness analysis.
- https://github.com/golang/go/blob/release-branch.go1.21/src/cmd/compile/internal/ssa/regalloc.go
Index ¶
- Constants
- type Allocator
- func NewAllocator[I Instr, B Block[I], F Function[I, B]](allocatableRegs *RegisterInfo) Allocator[I, B, F]
- func (a *Allocator[I, B, F]) DoAllocation(f F)
- func (a *Allocator[I, B, F]) Reset()
- type Block
- type Function
- type Instr
- type RealReg
- type RegSet
- type RegType
- type RegisterInfo
- type VReg
- func FromRealReg(r RealReg, typ RegType) VReg
- func (v VReg) ID() VRegID
- func (v VReg) IsRealReg() bool
- func (v VReg) RealReg() RealReg
- func (v VReg) RegType() RegType
- func (v VReg) SetRealReg(r RealReg) VReg
- func (v VReg) SetRegType(t RegType) VReg
- func (v VReg) String() string
- func (v VReg) Valid() bool
- type VRegID
Constants ¶
const ( VRegIDNonReservedBegin = vRegIDReservedForRealNum VRegInvalid = VReg(vRegIDInvalid) )
Types ¶
type Allocator ¶
type Allocator[I Instr, B Block[I], F Function[I, B]] struct { // contains filtered or unexported fields }
Allocator is a register allocator.
func NewAllocator ¶
func NewAllocator[I Instr, B Block[I], F Function[I, B]](allocatableRegs *RegisterInfo) Allocator[I, B, F]
NewAllocator returns a new Allocator.
func (*Allocator[I, B, F]) DoAllocation ¶
func (a *Allocator[I, B, F]) DoAllocation(f F)
DoAllocation performs register allocation on the given Function.
func (*Allocator[I, B, F]) Reset ¶
func (a *Allocator[I, B, F]) Reset()
Reset resets the allocator's internal state so that it can be reused.
type Block ¶
type Block[I Instr] interface { comparable // ID returns the unique identifier of this block which is ordered in the reverse post-order traversal of the CFG. ID() int32 // InstrIteratorBegin returns the first instruction in this block. Instructions added after lowering must be skipped. // 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. InstrIteratorBegin() I // InstrIteratorNext returns the next instruction in this block. Instructions added after lowering must be skipped. // 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. InstrIteratorNext() I // InstrRevIteratorBegin is the same as InstrIteratorBegin, but in the reverse order. InstrRevIteratorBegin() I // InstrRevIteratorNext is the same as InstrIteratorNext, but in the reverse order. InstrRevIteratorNext() I // FirstInstr returns the fist instruction in this block where instructions will be inserted after it. FirstInstr() I // LastInstrForInsertion returns the last instruction in this block where instructions will be inserted before it. // Such insertions only happen when we need to insert spill/reload instructions to adjust the merge edges. // At the time of register allocation, all the critical edges are already split, so there is no need // to worry about the case where branching instruction has multiple successors. // Therefore, usually, it is the nop instruction, but if the block ends with an unconditional branching, then it returns // the unconditional branch, not the nop. In other words it is either nop or unconditional branch. LastInstrForInsertion() I // Preds returns the number of predecessors of this block in the CFG. Preds() int // Entry returns true if the block is for the entry block. Entry() bool // Succs returns the number of successors of this block in the CFG. Succs() int // LoopHeader returns true if this block is a loop header. LoopHeader() bool // LoopNestingForestChildren returns the number of children of this block in the loop nesting forest. LoopNestingForestChildren() int }
Block is a basic block in the CFG of a function, and it consists of multiple instructions, and predecessor Block(s). Right now, this corresponds to a ssa.BasicBlock lowered to the machine level.
type Function ¶
type Function[I Instr, B Block[I]] interface { // PostOrderBlockIteratorBegin returns the first block in the post-order traversal of the CFG. // In other words, the last blocks in the CFG will be returned first. PostOrderBlockIteratorBegin() B // PostOrderBlockIteratorNext returns the next block in the post-order traversal of the CFG. PostOrderBlockIteratorNext() B // ReversePostOrderBlockIteratorBegin returns the first block in the reverse post-order traversal of the CFG. // In other words, the first blocks in the CFG will be returned first. ReversePostOrderBlockIteratorBegin() B // ReversePostOrderBlockIteratorNext returns the next block in the reverse post-order traversal of the CFG. ReversePostOrderBlockIteratorNext() B // ClobberedRegisters tell the clobbered registers by this function. ClobberedRegisters([]VReg) // LoopNestingForestRoots returns the number of roots of the loop nesting forest in a function. LoopNestingForestRoots() int // LoopNestingForestRoot returns the i-th root of the loop nesting forest in a function. LoopNestingForestRoot(i int) B // LowestCommonAncestor returns the lowest common ancestor of two blocks in the dominator tree. LowestCommonAncestor(blk1, blk2 B) B // Idom returns the immediate dominator of the given block. Idom(blk B) B // LoopNestingForestChild returns the i-th child of the block in the loop nesting forest. LoopNestingForestChild(b B, i int) B // Pred returns the i-th predecessor of the block in the CFG. Pred(b B, i int) B // Succ returns the i-th successor of the block in the CFG. Succ(b B, i int) B // BlockParams returns the virtual registers used as the parameters of this block. BlockParams(B, *[]VReg) []VReg // SwapBefore swaps the two virtual registers at the end of the given block. SwapBefore(x1, x2, tmp VReg, instr I) // StoreRegisterBefore inserts store instruction(s) before the given instruction for the given virtual register. StoreRegisterBefore(v VReg, instr I) // StoreRegisterAfter inserts store instruction(s) after the given instruction for the given virtual register. StoreRegisterAfter(v VReg, instr I) // ReloadRegisterBefore inserts reload instruction(s) before the given instruction for the given virtual register. ReloadRegisterBefore(v VReg, instr I) // ReloadRegisterAfter inserts reload instruction(s) after the given instruction for the given virtual register. ReloadRegisterAfter(v VReg, instr I) // InsertMoveBefore inserts move instruction(s) before the given instruction for the given virtual registers. InsertMoveBefore(dst, src VReg, instr I) }
Function is the top-level interface to do register allocation, which corresponds to a CFG containing Blocks(s).
I is the type of the instruction, and B is the type of the basic block.
type Instr ¶
type Instr interface { comparable fmt.Stringer // Defs returns the virtual registers defined by this instruction. Defs(*[]VReg) []VReg // Uses returns the virtual registers used by this instruction. // Note: multiple returned []VReg will not be held at the same time, so it's safe to use the same slice for this. Uses(*[]VReg) []VReg // AssignUse assigns the RealReg-allocated virtual register used by this instruction at the given index. AssignUse(index int, v VReg) // AssignDef assigns a RealReg-allocated virtual register defined by this instruction. // This only accepts one register because we don't allocate registers for multi-def instructions (i.e. call instruction) AssignDef(VReg) // IsCopy returns true if this instruction is a move instruction between two registers. // If true, the instruction is of the form of dst = src, and if the src and dst do not interfere with each other, // we could coalesce them, and hence the copy can be eliminated from the final code. IsCopy() bool // IsCall returns true if this instruction is a call instruction. The result is used to insert // caller saved register spills and restores. IsCall() bool // IsIndirectCall returns true if this instruction is an indirect call instruction which calls a function pointer. // The result is used to insert caller saved register spills and restores. IsIndirectCall() bool // IsReturn returns true if this instruction is a return instruction. IsReturn() bool }
Instr is an instruction in a block, abstracting away the underlying ISA.
type RealReg ¶
type RealReg byte
RealReg represents a physical register.
const RealRegInvalid RealReg = 0
func (RealReg) String ¶
String implements fmt.Stringer.
type RegSet ¶
type RegSet uint64
RegSet represents a set of registers.
func NewRegSet ¶
NewRegSet returns a new RegSet with the given registers.
func (RegSet) Range ¶
type RegType ¶
type RegType byte
RegType represents the type of a register.
func RegTypeOf ¶
RegTypeOf returns the RegType of the given ssa.Type.
func (RegType) String ¶
String implements fmt.Stringer.
type RegisterInfo ¶
type RegisterInfo struct { // AllocatableRegisters is a 2D array of allocatable RealReg, indexed by regTypeNum and regNum. // The order matters: the first element is the most preferred one when allocating. AllocatableRegisters [NumRegType][]RealReg CalleeSavedRegisters RegSet CallerSavedRegisters RegSet RealRegToVReg []VReg // RealRegName returns the name of the given RealReg for debugging. RealRegName func(r RealReg) string RealRegType func(r RealReg) RegType }
RegisterInfo holds the statically-known ISA-specific register information.
type VReg ¶
type VReg uint64
VReg represents a register which is assigned to an SSA value. This is used to represent a register in the backend. A VReg may or may not be a physical register, and the info of physical register can be obtained by RealReg.
func FromRealReg ¶
FromRealReg returns a VReg from the given RealReg and RegType. This is used to represent a specific pre-colored register in the backend.
func (VReg) ID ¶
ID returns the VRegID of this VReg.
func (VReg) IsRealReg ¶
IsRealReg returns true if this VReg is backed by a physical register.
func (VReg) RealReg ¶
RealReg returns the RealReg of this VReg.
func (VReg) RegType ¶
RegType returns the RegType of this VReg.
func (VReg) SetRealReg ¶
SetRealReg sets the RealReg of this VReg and returns the updated VReg.
func (VReg) SetRegType ¶
SetRegType sets the RegType of this VReg and returns the updated VReg.
func (VReg) String ¶
String implements fmt.Stringer.
func (VReg) Valid ¶
Valid returns true if this VReg is Valid.
type VRegID ¶
type VRegID uint32
VRegID is the lower 32bit of VReg, which is the pure identifier of VReg without RealReg info.
Source Files ¶
api.go reg.go regalloc.go regset.go
- Version
- v1.9.0 (latest)
- Published
- Feb 18, 2025
- Platform
- linux/amd64
- Imports
- 5 packages
- Last checked
- 4 days ago –
Tools for package owners.