pub struct Function { /* private fields */ }Expand description
A function in SSA form: a control-flow graph of basic blocks over a single flat store of values.
A function is the unit ir-lang represents and the thing a front-end lowers into.
It has a name, a parameter list, a return type, an entry block, and a set of
blocks; each block is a run of value-producing Insts ended by one
Terminator. Values are named by Value handles and defined exactly once,
either as a block parameter or as an instruction result.
You do not construct a Function field by field — a Builder
produces one. Once you hold it, the accessors here read it back, and
validate checks it is well-formed. A function also prints
as a readable textual IR through its Display
implementation.
§Examples
use ir_lang::{Builder, BinOp, Type};
// fn double(x: int) -> int { x + x }
let mut b = Builder::new("double", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
let sum = b.bin(BinOp::Add, x, x);
b.ret(Some(sum));
let func = b.finish();
assert_eq!(func.name(), "double");
assert_eq!(func.params(), &[Type::Int]);
assert_eq!(func.ret(), Type::Int);
assert!(func.validate().is_ok());Implementations§
Source§impl Function
impl Function
Sourcepub fn name(&self) -> &str
pub fn name(&self) -> &str
Returns the function’s name.
§Examples
use ir_lang::{Builder, Type};
let b = Builder::new("main", &[], Type::Unit);
assert_eq!(b.finish().name(), "main");Sourcepub fn params(&self) -> &[Type]
pub fn params(&self) -> &[Type]
Returns the function’s parameter types, in order. These are also the types of the entry block’s parameters.
§Examples
use ir_lang::{Builder, Type};
let b = Builder::new("f", &[Type::Int, Type::Bool], Type::Unit);
assert_eq!(b.finish().params(), &[Type::Int, Type::Bool]);Sourcepub const fn ret(&self) -> Type
pub const fn ret(&self) -> Type
Returns the function’s return type.
§Examples
use ir_lang::{Builder, Type};
let b = Builder::new("f", &[], Type::Float);
assert_eq!(b.finish().ret(), Type::Float);Sourcepub const fn entry(&self) -> Block
pub const fn entry(&self) -> Block
Returns the entry block — where execution begins. It is always block zero and its parameters are the function’s parameters.
§Examples
use ir_lang::{Builder, Type, Block};
let b = Builder::new("f", &[], Type::Unit);
assert_eq!(b.finish().entry().index(), 0);Sourcepub fn block_count(&self) -> usize
pub fn block_count(&self) -> usize
Returns the number of blocks in the function.
§Examples
use ir_lang::{Builder, Type};
let mut b = Builder::new("f", &[], Type::Unit);
let _ = b.create_block(&[]);
b.ret(None);
assert_eq!(b.finish().block_count(), 2);Sourcepub fn value_count(&self) -> usize
pub fn value_count(&self) -> usize
Returns the number of values defined in the function (block parameters and
instruction results together). Value handles run densely over 0..count.
§Examples
use ir_lang::{Builder, Type};
let mut b = Builder::new("f", &[Type::Int], Type::Int);
let one = b.iconst(1);
b.ret(Some(one));
// one parameter value + one constant value
assert_eq!(b.finish().value_count(), 2);Sourcepub fn blocks(&self) -> impl Iterator<Item = Block>
pub fn blocks(&self) -> impl Iterator<Item = Block>
Iterates over every block handle, entry first, in creation order.
§Examples
use ir_lang::{Builder, Type};
let mut b = Builder::new("f", &[], Type::Unit);
let _ = b.create_block(&[]);
b.ret(None);
let func = b.finish();
assert_eq!(func.blocks().count(), 2);Sourcepub fn block_params(&self, block: Block) -> &[Value]
pub fn block_params(&self, block: Block) -> &[Value]
Returns a block’s parameter values, in order, or an empty slice if the block handle is out of range.
§Examples
use ir_lang::{Builder, Type};
let b = Builder::new("f", &[Type::Int, Type::Int], Type::Unit);
let func = b.finish();
assert_eq!(func.block_params(func.entry()).len(), 2);Sourcepub fn insts(&self, block: Block) -> &[Value]
pub fn insts(&self, block: Block) -> &[Value]
Returns the values defined by a block’s instructions, in program order, or an empty slice if the block handle is out of range.
§Examples
use ir_lang::{Builder, BinOp, Type};
let mut b = Builder::new("f", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
let _ = b.bin(BinOp::Add, x, x);
b.ret(Some(x));
let func = b.finish();
assert_eq!(func.insts(func.entry()).len(), 1);Sourcepub fn terminator(&self, block: Block) -> Option<&Terminator>
pub fn terminator(&self, block: Block) -> Option<&Terminator>
Returns a block’s terminator, or None if the block handle is out of range
or no terminator was set (an unterminated block — which
validate rejects).
§Examples
use ir_lang::{Builder, Type, Terminator};
let mut b = Builder::new("f", &[], Type::Unit);
b.ret(None);
let func = b.finish();
assert!(matches!(func.terminator(func.entry()), Some(Terminator::Return(None))));Sourcepub fn inst(&self, value: Value) -> Option<&Inst>
pub fn inst(&self, value: Value) -> Option<&Inst>
Returns the instruction that defined a value, or None if the value is a
block parameter or the handle is out of range.
§Examples
use ir_lang::{Builder, Inst, Type};
let mut b = Builder::new("f", &[Type::Int], Type::Int);
let param = b.block_params(b.entry())[0];
let five = b.iconst(5);
b.ret(Some(param));
let func = b.finish();
assert!(matches!(func.inst(five), Some(Inst::Iconst(5))));
assert!(func.inst(param).is_none()); // a parameter has no defining instructionSourcepub fn value_type(&self, value: Value) -> Option<Type>
pub fn value_type(&self, value: Value) -> Option<Type>
Returns the type of a value, or None if the handle is out of range.
§Examples
use ir_lang::{Builder, BinOp, Type};
let mut b = Builder::new("f", &[Type::Int], Type::Bool);
let x = b.block_params(b.entry())[0];
let cmp = b.bin(BinOp::Lt, x, x);
b.ret(Some(cmp));
let func = b.finish();
assert_eq!(func.value_type(x), Some(Type::Int));
assert_eq!(func.value_type(cmp), Some(Type::Bool));Sourcepub fn value_block(&self, value: Value) -> Option<Block>
pub fn value_block(&self, value: Value) -> Option<Block>
Returns the block a value is defined in, or None if the handle is out of
range.
§Examples
use ir_lang::{Builder, Type};
let mut b = Builder::new("f", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
b.ret(Some(x));
let func = b.finish();
assert_eq!(func.value_block(x), Some(func.entry()));Sourcepub fn validate(&self) -> Result<(), ValidationError>
pub fn validate(&self) -> Result<(), ValidationError>
Checks that the function is well-formed, returning the first violation found.
A function that validates satisfies the SSA invariants the rest of a
compiler relies on: every block ends in exactly one terminator; every branch
targets a real block with a matching number and type of arguments; every
value is referenced only where its single definition reaches it; operations
are applied to operands of the right type; and the entry block is never a
branch target. The Builder does not check these as it
goes, so run this once construction is complete — and again on the output of
any pass that rewrites the IR.
§Errors
Returns the first ValidationError encountered. Each variant names the
offending block or value; see ValidationError for the meaning of each and
how to fix it.
§Examples
use ir_lang::{Builder, BinOp, Type, ValidationError};
// A well-formed function validates.
let mut b = Builder::new("f", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
let two = b.iconst(2);
let doubled = b.bin(BinOp::Mul, x, two);
b.ret(Some(doubled));
assert!(b.finish().validate().is_ok());
// A block with no terminator does not.
let unfinished = Builder::new("g", &[], Type::Unit).finish();
assert!(matches!(
unfinished.validate(),
Err(ValidationError::MissingTerminator { .. })
));