Expand description
§ir_lang
An intermediate representation and the lowering interface a compiler builds it through.
ir-lang gives a front-end a place to put a program once it has been parsed and
type-checked, in the flat, explicit form that optimization passes rewrite and
backends read. A Function is a control-flow graph of basic blocks; each block
is a straight-line run of value-producing instructions ended by one
Terminator; every value is named by a small Value handle and defined
exactly once, in SSA form. Values cross control-flow joins as block parameters
rather than through phi nodes, which keeps the representation flat and the
validation simple.
§Lowering
There is no AST type here to lower from — a language brings its own syntax
tree. Lowering is instead expressed through the Builder: a front-end walks
its tree and, for each construct, calls a builder method that emits the matching
IR and hands back the Value it defines. This is the same shape as Cranelift’s
FunctionBuilder or LLVM’s IRBuilder. When the function is built, check it with
Function::validate.
§Example
Lower and validate fn abs(x: int) -> int { if x < 0 { -x } else { x } }:
use ir_lang::{Builder, BinOp, Type, UnOp};
let mut b = Builder::new("abs", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
// The merge point takes the result as a parameter.
let join = b.create_block(&[Type::Int]);
let neg_blk = b.create_block(&[]);
let pos_blk = b.create_block(&[]);
let zero = b.iconst(0);
let is_neg = b.bin(BinOp::Lt, x, zero);
b.branch(is_neg, neg_blk, &[], pos_blk, &[]);
b.switch_to(neg_blk);
let negated = b.un(UnOp::Neg, x);
b.jump(join, &[negated]);
b.switch_to(pos_blk);
b.jump(join, &[x]);
b.switch_to(join);
let result = b.block_params(join)[0];
b.ret(Some(result));
let func = b.finish();
func.validate().expect("the lowered function is well-formed");
assert_eq!(func.name(), "abs");§Features
std(default) — the standard library; without it the crate is#![no_std]and needs onlyalloc.serde— derivesserde::Serialize/Deserializefor the IR types so a function can be cached, inspected, or moved between tools.
§Stability
The public surface is frozen and stable as of 1.0.0: it follows Semantic
Versioning, with no breaking changes before 2.0. The full surface and the
SemVer promise are catalogued in
docs/API.md.
Structs§
- Block
- A handle to a basic block inside a
Function. - Builder
- Constructs a
Functionone instruction at a time. - Function
- A function in SSA form: a control-flow graph of basic blocks over a single flat store of values.
- Value
- A handle to an SSA value inside a
Function.
Enums§
- BinOp
- A binary operation.
- Inst
- A value-producing instruction.
- Terminator
- The single instruction that ends a basic block and transfers control.
- Type
- The type of a value in the IR.
- UnOp
- A unary operation.
- Validation
Error - A reason a
Functionis not well-formed.