pub trait Function {
Show 21 methods
fn num_insts(&self) -> usize;
fn num_blocks(&self) -> usize;
fn entry_block(&self) -> Block;
fn block_insns(&self, block: Block) -> InstRange;
fn block_succs(&self, block: Block) -> &[Block];
fn block_preds(&self, block: Block) -> &[Block];
fn block_params(&self, block: Block) -> &[VReg];
fn is_ret(&self, insn: Inst) -> bool;
fn is_branch(&self, insn: Inst) -> bool;
fn branch_blockparams(
&self,
block: Block,
insn: Inst,
succ_idx: usize
) -> &[VReg];
fn is_move(&self, insn: Inst) -> Option<(Operand, Operand)>;
fn inst_operands(&self, insn: Inst) -> &[Operand];
fn inst_clobbers(&self, insn: Inst) -> &[PReg];
fn num_vregs(&self) -> usize;
fn spillslot_size(&self, regclass: RegClass) -> usize;
fn requires_refs_on_stack(&self, _: Inst) -> bool { ... }
fn reftype_vregs(&self) -> &[VReg] { ... }
fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] { ... }
fn is_pinned_vreg(&self, _: VReg) -> Option<PReg> { ... }
fn multi_spillslot_named_by_last_slot(&self) -> bool { ... }
fn allow_multiple_vreg_defs(&self) -> bool { ... }
}
Expand description
A trait defined by the regalloc client to provide access to its machine-instruction / CFG representation.
(This trait’s design is inspired by, and derives heavily from, the trait of the same name in regalloc.rs.)
Required Methods§
sourcefn num_blocks(&self) -> usize
fn num_blocks(&self) -> usize
How many blocks are there?
sourcefn entry_block(&self) -> Block
fn entry_block(&self) -> Block
Get the index of the entry block.
sourcefn block_insns(&self, block: Block) -> InstRange
fn block_insns(&self, block: Block) -> InstRange
Provide the range of instruction indices contained in each block.
sourcefn block_succs(&self, block: Block) -> &[Block]
fn block_succs(&self, block: Block) -> &[Block]
Get CFG successors for a given block.
sourcefn block_preds(&self, block: Block) -> &[Block]
fn block_preds(&self, block: Block) -> &[Block]
Get the CFG predecessors for a given block.
sourcefn block_params(&self, block: Block) -> &[VReg]
fn block_params(&self, block: Block) -> &[VReg]
Get the block parameters for a given block.
sourcefn is_branch(&self, insn: Inst) -> bool
fn is_branch(&self, insn: Inst) -> bool
Determine whether an instruction is the end-of-block branch.
sourcefn branch_blockparams(&self, block: Block, insn: Inst, succ_idx: usize) -> &[VReg]
fn branch_blockparams(&self, block: Block, insn: Inst, succ_idx: usize) -> &[VReg]
If insn
is a branch at the end of block
, returns the
outgoing blockparam arguments for the given successor. The
number of arguments must match the number incoming blockparams
for each respective successor block.
sourcefn is_move(&self, insn: Inst) -> Option<(Operand, Operand)>
fn is_move(&self, insn: Inst) -> Option<(Operand, Operand)>
Determine whether an instruction is a move; if so, return the Operands for (src, dst).
sourcefn inst_operands(&self, insn: Inst) -> &[Operand]
fn inst_operands(&self, insn: Inst) -> &[Operand]
Get the Operands for an instruction.
sourcefn inst_clobbers(&self, insn: Inst) -> &[PReg]
fn inst_clobbers(&self, insn: Inst) -> &[PReg]
Get the clobbers for an instruction; these are the registers that, after the instruction has executed, hold values that are arbitrary, separately from the usual outputs to the instruction. It is invalid to read a register that has been clobbered; the register allocator is free to assume that clobbered registers are filled with garbage and available for reuse. It will avoid storing any value in a clobbered register that must be live across the instruction.
Another way of seeing this is that a clobber is equivalent to an “early def” of a fresh vreg that is not used anywhere else in the program, with a fixed-register constraint that places it in a given PReg chosen by the client prior to regalloc.
Every register written by an instruction must either
correspond to (be assigned to) an Operand of kind Def
or
Mod
, or else must be a “clobber”.
This can be used to, for example, describe ABI-specified registers that are not preserved by a call instruction, or fixed physical registers written by an instruction but not used as a vreg output, or fixed physical registers used as temps within an instruction out of necessity.
sourcefn spillslot_size(&self, regclass: RegClass) -> usize
fn spillslot_size(&self, regclass: RegClass) -> usize
How many logical spill slots does the given regclass require? E.g., on a 64-bit machine, spill slots may nominally be 64-bit words, but a 128-bit vector value will require two slots. The regalloc will always align on this size.
(This trait method’s design and doc text derives from regalloc.rs’ trait of the same name.)
Provided Methods§
sourcefn requires_refs_on_stack(&self, _: Inst) -> bool
fn requires_refs_on_stack(&self, _: Inst) -> bool
Determine whether an instruction requires all reference-typed values to be placed onto the stack. For these instructions, stackmaps will be provided.
This is usually associated with the concept of a “safepoint”, though strictly speaking, a safepoint could also support reference-typed values in registers if there were a way to denote their locations and if this were acceptable to the client. Usually garbage-collector implementations want to see roots on the stack, so we do that for now.
sourcefn reftype_vregs(&self) -> &[VReg]
fn reftype_vregs(&self) -> &[VReg]
Get the VRegs that are pointer/reference types. This has the following effects for each such vreg:
- At all safepoint instructions, the vreg will be in a SpillSlot, not in a register.
- The vreg may not be used as a register operand on safepoint instructions: this is because a vreg can only live in one place at a time. The client should copy the value to an integer-typed vreg and use this to pass a pointer as an input to a safepoint instruction (such as a function call).
- At all safepoint instructions, all live vregs’ locations
will be included in a list in the
Output
below, so that pointer-inspecting/updating functionality (such as a moving garbage collector) may observe and edit their values.
sourcefn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)]
fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)]
Get the VRegs for which we should generate value-location metadata for debugging purposes. This can be used to generate e.g. DWARF with valid prgram-point ranges for each value expression in a way that is more efficient than a post-hoc analysis of the allocator’s output.
Each tuple is (vreg, inclusive_start, exclusive_end,
label). In the Output
there will be (label, inclusive_start,
exclusive_end, alloc)` tuples. The ranges may not exactly
match – specifically, the returned metadata may cover only a
subset of the requested ranges – if the value is not live for
the entire requested ranges.
The instruction indices imply a program point just before the instruction.
Precondition: we require this slice to be sorted by vreg.
sourcefn is_pinned_vreg(&self, _: VReg) -> Option<PReg>
fn is_pinned_vreg(&self, _: VReg) -> Option<PReg>
Is the given vreg pinned to a preg? If so, every use of the vreg is automatically assigned to the preg, and live-ranges of the vreg allocate the preg exclusively (are not spilled elsewhere). The user must take care not to have too many live pinned vregs such that allocation is no longer possible; liverange computation will check that this is the case (that there are enough remaining allocatable pregs of every class to hold all Reg-constrained operands).
Pinned vregs are implicitly live-in to the function: that is, one can use a pinned vreg without having first defined it, and this will take the value that that physical register (to which the vreg is pinned) had at function entry.
sourcefn multi_spillslot_named_by_last_slot(&self) -> bool
fn multi_spillslot_named_by_last_slot(&self) -> bool
When providing a spillslot number for a multi-slot spillslot, do we provide the first or the last? This is usually related to which direction the stack grows and different clients may have different preferences.
sourcefn allow_multiple_vreg_defs(&self) -> bool
fn allow_multiple_vreg_defs(&self) -> bool
Allow a single instruction to define a vreg multiple times. If allowed, the semantics are as if the definition occurs only once, and all defs will get the same alloc. This flexibility is meant to allow the embedder to more easily aggregate operands together in macro/pseudoinstructions, or e.g. add additional clobbered vregs without taking care to deduplicate. This may be particularly useful when referring to physical registers via pinned vregs. It is optional functionality because a strict mode (at most one def per vreg) is also useful for finding bugs in other applications.