pub struct Function { /* private fields */ }Expand description
A function body in SSA form: a control-flow graph of basic blocks.
Each block has parameters (the SSA values that flow in along its incoming edges,
in place of phi nodes), a sequence of instructions, and one Terminator. Every
value is defined once, by a block parameter or an instruction result, and has
one Type. The entry block’s parameters are the function’s parameters.
A Function lives in a Module, which holds its declaration
(name, Signature, linkage, attributes). It is created and
changed through a Builder (Module::build, Module::edit)
and read through the accessors here.
Instructions of a block form a linked list over a dense arena, so inserting or
removing an instruction is O(1) and handles never move. Removed instructions and
blocks leave tombstones; Builder::compact renumbers densely and
reports the mapping.
§Examples
use ir_lang::{Linkage, Module, Overflow, Signature, Type};
let mut m = Module::new("demo");
let f = m.declare_function("double", &Signature::new(&[Type::I64], &[Type::I64]), Linkage::Export)?;
let mut b = m.build(f)?;
let x = b.param(0)?;
let y = b.add(x, x, Overflow::Wrap)?;
b.ret(&[y])?;
let func = m.function(f).unwrap();
let entry = func.entry();
assert_eq!(func.block_params(entry), &[x]);
assert_eq!(func.insts(entry).count(), 1);
assert_eq!(func.value_type(y), Some(Type::I64));
m.validate()?;Implementations§
Source§impl Function
impl Function
Sourcepub const fn entry(&self) -> Block
pub const fn entry(&self) -> Block
The entry block, where execution begins. Its parameters are the function’s parameters, and no edge may target it.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let b = m.build(f)?;
assert_eq!(b.func().entry().index(), 0);Sourcepub fn block_count(&self) -> usize
pub fn block_count(&self) -> usize
The number of block handles ever created (live and removed): block handles
run over 0..block_count().
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let _ = b.create_block(&[])?;
assert_eq!(b.func().block_count(), 2);Sourcepub fn blocks(&self) -> impl Iterator<Item = Block> + '_
pub fn blocks(&self) -> impl Iterator<Item = Block> + '_
Iterates over the live blocks in handle order (the entry is block 0 for a function from the builder).
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let extra = b.create_block(&[])?;
b.remove_block(extra)?;
assert_eq!(b.func().blocks().count(), 1);Sourcepub fn is_live_block(&self, block: Block) -> bool
pub fn is_live_block(&self, block: Block) -> bool
Whether block exists and has not been removed.
§Examples
use ir_lang::{Block, Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let b = m.build(f)?;
assert!(b.func().is_live_block(Block::from_u32(0)));
assert!(!b.func().is_live_block(Block::from_u32(9)));Sourcepub fn block_params(&self, block: Block) -> &[Value]
pub fn block_params(&self, block: Block) -> &[Value]
The parameters of block, or an empty slice for an unknown block.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let blk = b.create_block(&[Type::Bool, Type::F64])?;
assert_eq!(b.func().block_params(blk).len(), 2);Sourcepub fn insts(&self, block: Block) -> Insts<'_> ⓘ
pub fn insts(&self, block: Block) -> Insts<'_> ⓘ
Iterates over the instructions of block in order (empty for an unknown
block). The terminator is not an instruction; see
terminator.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let _ = b.iconst(Type::I32, 1)?;
let _ = b.iconst(Type::I32, 2)?;
let entry = b.func().entry();
assert_eq!(b.func().insts(entry).count(), 2);Sourcepub fn first_inst(&self, block: Block) -> Option<Inst>
pub fn first_inst(&self, block: Block) -> Option<Inst>
The first instruction of block, if any.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let b = m.build(f)?;
assert_eq!(b.func().first_inst(b.func().entry()), None);Sourcepub fn last_inst(&self, block: Block) -> Option<Inst>
pub fn last_inst(&self, block: Block) -> Option<Inst>
The last instruction of block (before its terminator), if any.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let _ = b.iconst(Type::U8, 1)?;
let entry = b.func().entry();
assert!(b.func().last_inst(entry).is_some());Sourcepub fn next_inst(&self, inst: Inst) -> Option<Inst>
pub fn next_inst(&self, inst: Inst) -> Option<Inst>
The instruction after inst in its block, if any.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let a = b.iconst(Type::U8, 1)?;
let c = b.iconst(Type::U8, 2)?;
let (ia, ic) = (b.func().defining_inst(a).unwrap(), b.func().defining_inst(c).unwrap());
assert_eq!(b.func().next_inst(ia), Some(ic));
assert_eq!(b.func().prev_inst(ic), Some(ia));Sourcepub fn prev_inst(&self, inst: Inst) -> Option<Inst>
pub fn prev_inst(&self, inst: Inst) -> Option<Inst>
The instruction before inst in its block, if any.
See next_inst for an example.
Sourcepub fn inst_count(&self) -> usize
pub fn inst_count(&self) -> usize
The number of instruction handles ever created (live and removed).
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let _ = b.iconst(Type::U8, 1)?;
assert_eq!(b.func().inst_count(), 1);Sourcepub fn inst(&self, inst: Inst) -> Option<&InstData>
pub fn inst(&self, inst: Inst) -> Option<&InstData>
The data of inst (also for a removed instruction), or None for an
unknown handle.
§Examples
use ir_lang::{InstData, Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let v = b.iconst(Type::I8, -1)?;
let inst = b.func().defining_inst(v).unwrap();
assert_eq!(b.func().inst(inst), Some(&InstData::Const { ty: Type::I8, bits: 0xff }));Sourcepub fn inst_block(&self, inst: Inst) -> Option<Block>
pub fn inst_block(&self, inst: Inst) -> Option<Block>
The block containing inst, or None if it was removed or is unknown.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let v = b.iconst(Type::I8, 0)?;
let inst = b.func().defining_inst(v).unwrap();
assert_eq!(b.func().inst_block(inst), Some(b.func().entry()));Sourcepub fn results(&self, inst: Inst) -> ValueRange
pub fn results(&self, inst: Inst) -> ValueRange
The values inst defines (empty for an unknown handle).
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let v = b.iconst(Type::I8, 0)?;
let inst = b.func().defining_inst(v).unwrap();
assert_eq!(b.func().results(inst).first(), Some(v));Sourcepub fn terminator(&self, block: Block) -> Option<&Terminator>
pub fn terminator(&self, block: Block) -> Option<&Terminator>
The terminator of block, or None if it has none yet (or is unknown).
§Examples
use ir_lang::{Linkage, Module, Signature, Terminator};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
b.unreachable()?;
let entry = b.func().entry();
assert_eq!(b.func().terminator(entry), Some(&Terminator::Unreachable));Sourcepub fn value_count(&self) -> usize
pub fn value_count(&self) -> usize
The number of value handles ever created: value handles run over
0..value_count().
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[Type::I32], &[]), Linkage::Local)?;
let b = m.build(f)?;
assert_eq!(b.func().value_count(), 1);Sourcepub fn value_type(&self, value: Value) -> Option<Type>
pub fn value_type(&self, value: Value) -> Option<Type>
The type of value, or None for an unknown handle.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[Type::F32], &[]), Linkage::Local)?;
let b = m.build(f)?;
assert_eq!(b.func().value_type(b.param(0)?), Some(Type::F32));Sourcepub fn value_def(&self, value: Value) -> Option<ValueDef>
pub fn value_def(&self, value: Value) -> Option<ValueDef>
Where value is defined, or None for an unknown handle.
See ValueDef for an example.
Sourcepub fn defining_inst(&self, value: Value) -> Option<Inst>
pub fn defining_inst(&self, value: Value) -> Option<Inst>
The instruction defining value, if it is an instruction result.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[Type::F32], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let p = b.param(0)?;
let c = b.iconst(Type::U8, 3)?;
assert!(b.func().defining_inst(c).is_some());
assert!(b.func().defining_inst(p).is_none());Sourcepub fn resolve(&self, value: Value) -> Value
pub fn resolve(&self, value: Value) -> Value
Follows replace_all_uses forwarding: the value every use of value now
reads. A value that was never replaced resolves to itself.
Operands stored in instructions are not rewritten eagerly by
Builder::replace_all_uses (that keeps it
O(1)), so a pass reading operands should resolve them, or call
Builder::resolve_aliases once first.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let one = b.iconst(Type::I32, 1)?;
let two = b.iconst(Type::I32, 2)?;
b.replace_all_uses(one, two)?;
assert_eq!(b.func().resolve(one), two);
assert_eq!(b.func().resolve(two), two);Sourcepub fn slot_count(&self) -> usize
pub fn slot_count(&self) -> usize
The number of stack slots.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let _ = b.stack_slot(8, 8)?;
assert_eq!(b.func().slot_count(), 1);Sourcepub fn slot(&self, slot: StackSlot) -> Option<SlotData>
pub fn slot(&self, slot: StackSlot) -> Option<SlotData>
The size and alignment of a stack slot.
§Examples
use ir_lang::{Linkage, Module, Signature, SlotData};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let ss = b.stack_slot(24, 8)?;
assert_eq!(b.func().slot(ss), Some(SlotData { size: 24, align: 8 }));Sourcepub fn predecessors(&self) -> Vec<Vec<Block>>
pub fn predecessors(&self) -> Vec<Vec<Block>>
The predecessor blocks of every block, indexed by block handle, listing a predecessor once per edge (a branch with both edges to one block lists it twice). Only live blocks contribute edges.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
let mut b = m.build(f)?;
let exit = b.create_block(&[])?;
b.jump(exit, &[])?;
b.switch_to(exit)?;
b.ret(&[])?;
let preds = b.func().predecessors();
assert_eq!(preds[exit.index()], [b.func().entry()]);