pub struct Func {
pub name: Symbol,
pub linkage: Linkage,
pub visibility: Visibility,
pub section: Option<Symbol>,
pub align: Option<u32>,
pub attrs: Attrs,
/* private fields */
}Expand description
One function.
Fields§
§name: SymbolThe name it is called by, which is what a direct call to it names.
linkage: LinkageHow the linker sees it. Internal for a static function.
visibility: VisibilityHow the dynamic linker sees it.
section: Option<Symbol>The section to put it in, from __attribute__((section(...))), or None to let the
object writer choose.
align: Option<u32>What its first instruction has to be aligned to, from __attribute__((aligned(...))), or
None for the alignment the target gives every function anyway.
A raise and never a lower, the way the attribute is everywhere: a function asked to be at a multiple of two hundred and fifty six is at one, and one asked for less than the target’s own alignment keeps the target’s.
attrs: AttrsWhat is true of the whole function, which is what a caller reads when it wants to know what a call to it does without looking inside.
Implementations§
Source§impl Func
impl Func
Sourcepub fn new(name: Symbol, signature: Signature) -> Self
pub fn new(name: Symbol, signature: Signature) -> Self
A function with that name and that signature, and nothing in it.
The signature becomes signature zero, which is what Func::signature gives back. The
entry block is not created here, because the caller is about to create it and give it
the parameters, and a half-built entry block is worse than no entry block. So a
function fresh from here is a declaration, and stops being one when it gets a block.
Sourcepub fn signatures(&self) -> impl Iterator<Item = &Signature>
pub fn signatures(&self) -> impl Iterator<Item = &Signature>
Every signature the function holds, its own first and then the ones its calls name.
Sourcepub fn add_signature(&mut self, signature: Signature) -> Sig
pub fn add_signature(&mut self, signature: Signature) -> Sig
Records a signature a call_indirect is made with, and gives back its index.
Sourcepub fn entry(&self) -> Option<Block>
pub fn entry(&self) -> Option<Block>
The entry block, which is the first one in layout order.
None only before one has been created. The verifier is what insists a finished
function has one.
Sourcepub fn is_declaration(&self) -> bool
pub fn is_declaration(&self) -> bool
Whether this only says the function exists somewhere, which is a function with no blocks in it.
extern int puts(const char *); and every other declaration of something defined in
another object is one of these, and it is here rather than left out of the module
because a call needs its signature and its linkage.
Sourcepub fn create_block(&mut self) -> Block
pub fn create_block(&mut self) -> Block
Creates a block with no parameters and no instructions, at the end of the layout.
Sourcepub fn remove_block(&mut self, block: Block)
pub fn remove_block(&mut self, block: Block)
Takes a block out of the layout, along with everything in it.
The block keeps its number, the way a removed instruction keeps its own, because renumbering would move every block after it and invalidate every index anybody was holding. What it stops being is a block of this function: nothing walks it, nothing prints it, and the values defined in it are as gone as the instructions that defined them. Deleting one whose branches something still reaches is how a function ends up branching to nowhere, so the caller is the one that has to know nothing reaches it.
§Panics
Panics if the block is the entry block, which is the one block a function has to have.
Sourcepub fn append_param(&mut self, block: Block, ty: Type) -> Value
pub fn append_param(&mut self, block: Block, ty: Type) -> Value
Adds a parameter of that type to a block, and gives back the value it arrives as.
Every predecessor’s branch has to grow an argument to match, which is
Func::append_arg, and the verifier is what notices if one of them did not.
§Panics
Panics if the block already has four billion parameters, which no block does.
Sourcepub fn retain_params(&mut self, block: Block, keep: impl FnMut(Value) -> bool)
pub fn retain_params(&mut self, block: Block, keep: impl FnMut(Value) -> bool)
Drops the parameters of a block that a predicate turns down, and renumbers the rest.
The predicate is asked about each parameter in the order the block takes them. A parameter that goes has to take the argument in the same position out of every branch to the block, which is the caller’s work rather than this method’s, because only the caller knows which branches there are. This is what removing a redundant block parameter is, and SSA construction is the thing that makes them.
§Panics
Panics if the block has four billion parameters, which no block does.
Sourcepub fn retype(&mut self, value: Value, ty: Type)
pub fn retype(&mut self, value: Value, ty: Type)
Gives a value a different type, leaving where it comes from alone.
There is one caller and it is the back end pass that puts an integer of a width the machine has no register for into the width it does have one for. Nothing in the middle end changes a value’s type, because a value’s type is what the instruction that made it produces and changing one without changing the other is how an IR stops meaning anything. That pass changes both, which is why this is a method and not a field.
§Panics
Panics if the value is not one of this function’s.
Sourcepub fn values(&self) -> impl Iterator<Item = Value> + use<'_>
pub fn values(&self) -> impl Iterator<Item = Value> + use<'_>
Every value the function has, including ones whose defining instruction has gone.
In the order they were created, which is the order a pass that walks all of them wants: a value is defined before it is used, so a walk in this order sees a definition first.
Sourcepub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_>
pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_>
Every instruction in a block, in order.
Sourcepub fn insts_backwards(
&self,
block: Block,
) -> impl Iterator<Item = Inst> + use<'_>
pub fn insts_backwards( &self, block: Block, ) -> impl Iterator<Item = Inst> + use<'_>
Every instruction in a block, last first.
Which is the order a liveness walk needs, and it is here rather than at the caller because the layout links are private and collecting the block into a vector to reverse it is an allocation per block per round of a fixpoint.
Sourcepub fn terminator(&self, block: Block) -> Option<Inst>
pub fn terminator(&self, block: Block) -> Option<Inst>
The last instruction of a block, which is its terminator once it is finished.
Sourcepub fn is_terminator(&self, inst: Inst) -> bool
pub fn is_terminator(&self, inst: Inst) -> bool
Whether control leaves the block at this instruction.
A question for the function rather than for the instruction, because inline assembly is
the one case where the opcode is not enough: asm goto has labels and everything else
does not, and the labels are in the function’s table rather than on the instruction.
Sourcepub fn create_inst(
&mut self,
data: InstData,
results: &[Type],
span: Span,
) -> Inst
pub fn create_inst( &mut self, data: InstData, results: &[Type], span: Span, ) -> Inst
Creates an instruction and its result values, without putting it in a block.
The results are allocated here and are contiguous, which is what lets an instruction hold the first of them and a count rather than a list.
§Panics
Panics if results has more than 255 types, which no instruction in the set does.
Sourcepub fn append_inst(&mut self, block: Block, inst: Inst)
pub fn append_inst(&mut self, block: Block, inst: Inst)
Puts an instruction at the end of a block.
§Panics
Panics if the instruction is already in a block. Moving one is removing it and appending it, and doing it by accident is how a linked list ends up in two pieces.
Sourcepub fn insert_before(&mut self, inst: Inst, before: Inst)
pub fn insert_before(&mut self, inst: Inst, before: Inst)
Puts an instruction immediately before another one, in the block that one is in.
§Panics
Panics if inst is already in a block, or if before is not in one.
Sourcepub fn insert_after(&mut self, inst: Inst, after: Inst)
pub fn insert_after(&mut self, inst: Inst, after: Inst)
Puts an instruction immediately after another one, in the block that one is in.
The mirror of Func::insert_before, and it exists because a pass that has to talk about
a value an instruction produced has nowhere else to put what it is adding. Check insertion
is the caller: check_deriv is handed the pointer the derivation produced, so it goes
after the derivation and no amount of rearranging moves it earlier.
§Panics
Panics if inst is already in a block, if after is not in one, or if after is the
block’s terminator, since nothing may come between a terminator and the branch it is.
Sourcepub fn remove_inst(&mut self, inst: Inst)
pub fn remove_inst(&mut self, inst: Inst)
Takes an instruction out of its block, leaving it and its results in the tables.
The instruction is not deleted, because deleting it would move every instruction after it. A removed instruction is unreachable from any block and is dropped when the whole function is.
§Panics
Panics if the instruction is not in a block.
Sourcepub fn block_of(&self, inst: Inst) -> Option<Block>
pub fn block_of(&self, inst: Inst) -> Option<Block>
The block an instruction is in, or None if it has been removed from one.
Sourcepub fn mem_in(&self, inst: Inst) -> Option<Value>
pub fn mem_in(&self, inst: Inst) -> Option<Value>
The version of memory an instruction reads, when the function carries memory SSA.
Document 09 of spec/optimizer. Memory is a value of type mem, it is the last operand
of every instruction that touches memory, and it is absent in a function that does not
carry it, which is what -O0 and -O1 produce. Absent means unordered with respect to
everything, so a reader that gets None asks the alias analysis directly.
The operand is last rather than first on purpose. Every other operand keeps the position
it had, so a pass that reads the address of a load as args[0] goes on working whether
or not memory has been threaded, and the only code that has to know about the extra
operand is this accessor and the verifier.
Sourcepub fn mem_out(&self, inst: Inst) -> Option<Value>
pub fn mem_out(&self, inst: Inst) -> Option<Value>
The version of memory an instruction produces, when it writes memory and the function carries memory SSA.
Last among the results, for the reason Func::mem_in is last among the operands. A
load never has one, because it reads memory without changing it.
Nothing reads the last version in a function, and that means nothing. A store whose memory result has no reader is not dead, and what decides whether it is dead is dead store elimination, which is document 17’s.
Sourcepub fn carries_mem(&self, inst: Inst) -> bool
pub fn carries_mem(&self, inst: Inst) -> bool
Whether an instruction has been threaded onto the memory chain.
Sourcepub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst
pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst
The same instruction with a version of memory threaded through it.
A result cannot be added to an instruction that already exists, because the results of one are values next to each other and there is no room after them. So threading memory makes a new instruction and the caller puts it where the old one was, forwards the old results to the new ones, which are at the same positions, and deletes the old one. That is what memory SSA construction does in one pass over the function.
The new instruction is not in any block. Its results are what the old one produced, in the same order, and then the new version of memory where the opcode writes memory.
§Panics
Panics if incoming is not memory, if the instruction does not touch memory, or if it is
already on the chain. All three are a construction bug rather than bad input.
Sourcepub fn successors(
&self,
inst: Inst,
) -> impl Iterator<Item = BlockCall> + use<'_>
pub fn successors( &self, inst: Inst, ) -> impl Iterator<Item = BlockCall> + use<'_>
Where an instruction branches to, which is empty when it does not branch.
This is the one place that knows a switch keeps its targets in a side table and
asm goto in another one, so nothing walking the CFG has to.
Sourcepub fn target_list(&self, inst: Inst) -> BlockCallList
pub fn target_list(&self, inst: Inst) -> BlockCallList
Where a terminator keeps its targets, for something that edits them rather than reads them.
Func::successors is what walking the CFG wants. This is what recording an edge
wants, because an edge that will grow an argument later has to be named by its place in
the table rather than by the block it went to.
Sourcepub fn push_values(&mut self, values: &[Value]) -> ValueList
pub fn push_values(&mut self, values: &[Value]) -> ValueList
Records a run of value operands.
Sourcepub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList
pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList
Adds one value to the end of a run, giving back the run it became.
The run grows in place when nothing has been put after it, which is the case while a list is being built. Otherwise it is copied to the end and the old space is left behind, which is what makes adding a parameter to a loop header possible at all. That happens once per value carried around a loop, so the copying is not what costs.
Sourcepub fn rewrite(&mut self, list: ValueList, with: impl FnMut(Value) -> Value)
pub fn rewrite(&mut self, list: ValueList, with: impl FnMut(Value) -> Value)
Replaces the values in a run, which is what substituting one definition for another is.
A run is a run whether it is an instruction’s operands or a branch’s arguments, so this is the whole of the rewriting a substitution has to do.
Sourcepub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList
pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList
Records a run of branch targets.
Sourcepub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall)
pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall)
Replaces one branch target, which is what redirecting an edge is.
Sourcepub fn push_slots(&mut self, slots: &[Slot]) -> SlotList
pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList
Records where each eightbyte of an object travelled.
Sourcepub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo>
pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo>
Records an object read off a variable argument list.
Sourcepub fn push_abis(&mut self, abis: &[Abi]) -> AbiList
pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList
Records what the ABI asks of the arguments a call’s signature does not name.
Sourcepub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo>
pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo>
Records a call’s callee and signature.
Sourcepub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo>
pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo>
Records a switch’s targets and case values.
Sourcepub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo>
pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo>
Records an inline assembly instruction’s template and constraints.
Sourcepub fn counts(&self) -> Counts
pub fn counts(&self) -> Counts
How many values, instructions and blocks there are, for a reader that wants to size something by them.
Sourcepub fn facts(&self, value: Value) -> Facts
pub fn facts(&self, value: Value) -> Facts
What is known about a value, which is nothing at all unless somebody said otherwise.
Section 6.2.3 of spec/safe-memory/06-instrumentation.md. Facts are in a side table and
not in the value, so a function nobody has said anything about carries no facts and is
the same size it was before facts existed.
Sourcepub fn set_facts(&mut self, value: Value, facts: Facts)
pub fn set_facts(&mut self, value: Value, facts: Facts)
Says what is known about a value, replacing whatever was known before.
Setting Facts::NONE takes the value back out of the table, which is what keeps the
table empty in a function that has had facts put on and then taken off again.
Trait Implementations§
Source§impl Index<Idx<SwitchInfo>> for Func
impl Index<Idx<SwitchInfo>> for Func
Source§type Output = SwitchInfo
type Output = SwitchInfo
Source§fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo
fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo
container[index]) operation. Read more