Skip to main content

Func

Struct Func 

Source
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: Symbol

The name it is called by, which is what a direct call to it names.

§linkage: Linkage

How the linker sees it. Internal for a static function.

§visibility: Visibility

How 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: Attrs

What 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

Source

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.

Source

pub fn signature(&self) -> &Signature

Its own signature.

Source

pub fn signatures(&self) -> impl Iterator<Item = &Signature>

Every signature the function holds, its own first and then the ones its calls name.

Source

pub fn add_signature(&mut self, signature: Signature) -> Sig

Records a signature a call_indirect is made with, and gives back its index.

Source

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.

Source

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.

Source

pub fn create_block(&mut self) -> Block

Creates a block with no parameters and no instructions, at the end of the layout.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_>

Every block, in layout order.

Source

pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_>

Every instruction in a block, in order.

Source

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.

Source

pub fn terminator(&self, block: Block) -> Option<Inst>

The last instruction of a block, which is its terminator once it is finished.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn block_of(&self, inst: Inst) -> Option<Block>

The block an instruction is in, or None if it has been removed from one.

Source

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.

Source

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.

Source

pub fn carries_mem(&self, inst: Inst) -> bool

Whether an instruction has been threaded onto the memory chain.

Source

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.

Source

pub fn span(&self, inst: Inst) -> Span

Where an instruction came from in the source.

Source

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.

Source

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.

Source

pub fn push_values(&mut self, values: &[Value]) -> ValueList

Records a run of value operands.

Source

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.

Source

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.

Source

pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList

Records a run of branch targets.

Source

pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall)

Replaces one branch target, which is what redirecting an edge is.

Source

pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList

Records a run of case values.

Source

pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm>

Records a constant.

Source

pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList

Records where each eightbyte of an object travelled.

Source

pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo>

Records an object read off a variable argument list.

Source

pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo>

Records what an access does.

Source

pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList

Records what the ABI asks of the arguments a call’s signature does not name.

Source

pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo>

Records a call’s callee and signature.

Source

pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo>

Records a switch’s targets and case values.

Source

pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo>

Records an inline assembly instruction’s template and constraints.

Source

pub fn counts(&self) -> Counts

How many values, instructions and blocks there are, for a reader that wants to size something by them.

Source

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.

Source

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.

Source

pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_

Every value something is known about, in value order.

Trait Implementations§

Source§

impl Debug for Func

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Index<Idx<AsmInfo>> for Func

Source§

type Output = AsmInfo

The returned type after indexing.
Source§

fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<BlockCall>> for Func

Source§

type Output = BlockCall

The returned type after indexing.
Source§

fn index(&self, at: Idx<BlockCall>) -> &BlockCall

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<BlockData>> for Func

Source§

type Output = BlockData

The returned type after indexing.
Source§

fn index(&self, block: Block) -> &BlockData

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<CallInfo>> for Func

Source§

type Output = CallInfo

The returned type after indexing.
Source§

fn index(&self, at: Idx<CallInfo>) -> &CallInfo

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<Imm>> for Func

Source§

type Output = Imm

The returned type after indexing.
Source§

fn index(&self, at: Idx<Imm>) -> &Imm

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<InstData>> for Func

Source§

type Output = InstData

The returned type after indexing.
Source§

fn index(&self, inst: Inst) -> &InstData

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<MemInfo>> for Func

Source§

type Output = MemInfo

The returned type after indexing.
Source§

fn index(&self, at: Idx<MemInfo>) -> &MemInfo

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<Signature>> for Func

Source§

type Output = Signature

The returned type after indexing.
Source§

fn index(&self, sig: Sig) -> &Signature

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<SwitchInfo>> for Func

Source§

type Output = SwitchInfo

The returned type after indexing.
Source§

fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<VaInfo>> for Func

Source§

type Output = VaInfo

The returned type after indexing.
Source§

fn index(&self, at: Idx<VaInfo>) -> &VaInfo

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<Idx<ValueData>> for Func

Source§

type Output = ValueData

The returned type after indexing.
Source§

fn index(&self, value: Value) -> &ValueData

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<IdxRange<Abi>> for Func

Source§

type Output = [Abi]

The returned type after indexing.
Source§

fn index(&self, list: AbiList) -> &[Abi]

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<IdxRange<BlockCall>> for Func

Source§

type Output = [BlockCall]

The returned type after indexing.
Source§

fn index(&self, list: BlockCallList) -> &[BlockCall]

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<IdxRange<Imm>> for Func

Source§

type Output = [Imm]

The returned type after indexing.
Source§

fn index(&self, list: ImmList) -> &[Imm]

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<IdxRange<Slot>> for Func

Source§

type Output = [Slot]

The returned type after indexing.
Source§

fn index(&self, list: SlotList) -> &[Slot]

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<IdxRange<ValueRef>> for Func

Source§

type Output = [Idx<ValueData>]

The returned type after indexing.
Source§

fn index(&self, list: ValueList) -> &[Value]

Performs the indexing (container[index]) operation. Read more
Source§

impl IndexMut<Idx<InstData>> for Func

Source§

fn index_mut(&mut self, inst: Inst) -> &mut InstData

Performs the mutable indexing (container[index]) operation. Read more

Auto Trait Implementations§

§

impl Freeze for Func

§

impl RefUnwindSafe for Func

§

impl Send for Func

§

impl Sync for Func

§

impl Unpin for Func

§

impl UnsafeUnpin for Func

§

impl UnwindSafe for Func

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.