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 check also gates the value table itself — handle ranges,
definition sites, and recorded result types — so it is a complete check for a
function assembled by hand or deserialized through serde, not only one the
Builder produced. The builder does not check any of this
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 { .. })
));