pub struct Module { /* private fields */ }Expand description
A compilation unit of IR: function declarations and bodies, globals, interned signatures, and aggregate types.
Declarations come first (so calls and addresses can name any function or global);
bodies are then built with build and changed with
edit. validate checks the whole module, the
Display implementation prints it in the textual form, and
parse reads that form back.
§Examples
use ir_lang::{CmpOp, Linkage, Module, Signature, Type};
// fn max(a: i64, b: i64) -> i64 { if a < b { b } else { a } }
let mut m = Module::new("demo");
let f = m.declare_function("max", &Signature::new(&[Type::I64, Type::I64], &[Type::I64]), Linkage::Export)?;
let mut b = m.build(f)?;
let (a, c) = (b.param(0)?, b.param(1)?);
let lt = b.compare(CmpOp::Lt, a, c)?;
let exit = b.create_block(&[Type::I64])?;
b.branch(lt, exit, &[c], exit, &[a])?;
b.switch_to(exit)?;
let r = b.block_param(exit, 0)?;
b.ret(&[r])?;
m.validate()?;
let text = m.to_string();
assert!(text.contains("br v2, b1(v1), b1(v0)"));
assert_eq!(ir_lang::parse(&text)?.to_string(), text);Implementations§
Source§impl Module
impl Module
Sourcepub fn new(name: &str) -> Module
pub fn new(name: &str) -> Module
An empty module with 64-bit addresses.
§Examples
use ir_lang::{Module, PointerWidth};
let m = Module::new("app");
assert_eq!((m.name(), m.pointer_width()), ("app", PointerWidth::P64));Sourcepub fn with_pointer_width(name: &str, ptr: PointerWidth) -> Module
pub fn with_pointer_width(name: &str, ptr: PointerWidth) -> Module
An empty module with the given address width.
§Examples
use ir_lang::{Module, PointerWidth, Type};
let m = Module::with_pointer_width("wasm", PointerWidth::P32);
assert_eq!(m.layout(Type::Ptr.into()).unwrap().size(), 4);Sourcepub fn pointer_width(&self) -> PointerWidth
pub fn pointer_width(&self) -> PointerWidth
The address width.
§Examples
use ir_lang::{Module, PointerWidth};
assert_eq!(Module::with_pointer_width("w", PointerWidth::P32).pointer_width(), PointerWidth::P32);Sourcepub fn intern_signature(
&mut self,
sig: &Signature,
) -> Result<SigId, ModuleError>
pub fn intern_signature( &mut self, sig: &Signature, ) -> Result<SigId, ModuleError>
Interns a signature, returning the existing handle for an equal one.
§Errors
ModuleError::CapacityExceeded if the table is full.
§Examples
use ir_lang::{Module, Signature, Type};
let mut m = Module::new("m");
let a = m.intern_signature(&Signature::new(&[Type::I32], &[]))?;
let b = m.intern_signature(&Signature::new(&[Type::I32], &[]))?;
assert_eq!(a, b);Sourcepub fn signature(&self, sig: SigId) -> Option<&Signature>
pub fn signature(&self, sig: SigId) -> Option<&Signature>
The signature behind a handle.
§Examples
use ir_lang::{Module, Signature, Type};
let mut m = Module::new("m");
let s = m.intern_signature(&Signature::new(&[], &[Type::Bool]))?;
assert_eq!(m.signature(s).unwrap().returns, [Type::Bool]);Sourcepub fn signature_count(&self) -> usize
pub fn signature_count(&self) -> usize
The number of interned signatures.
§Examples
use ir_lang::{Module, Signature};
let mut m = Module::new("m");
m.intern_signature(&Signature::new(&[], &[]))?;
m.intern_signature(&Signature::new(&[], &[]))?;
assert_eq!(m.signature_count(), 1);Sourcepub fn declare_aggregate(
&mut self,
agg: Aggregate,
) -> Result<AggId, ModuleError>
pub fn declare_aggregate( &mut self, agg: Aggregate, ) -> Result<AggId, ModuleError>
Declares an aggregate type and computes its layout.
§Errors
ModuleError::UnknownAggregate if it names an aggregate not declared
before it; ModuleError::AggregateTooLarge if its size exceeds
MAX_AGGREGATE_SIZE; ModuleError::CapacityExceeded.
§Examples
use ir_lang::{Aggregate, Module, Type};
let mut m = Module::new("m");
let v3 = m.declare_aggregate(Aggregate::array(Type::F32.into(), 3))?;
assert_eq!(m.layout(v3.into()).unwrap().size(), 12);Sourcepub fn aggregate(&self, agg: AggId) -> Option<&Aggregate>
pub fn aggregate(&self, agg: AggId) -> Option<&Aggregate>
The aggregate behind a handle.
§Examples
use ir_lang::{Aggregate, Module, Type};
let mut m = Module::new("m");
let a = m.declare_aggregate(Aggregate::array(Type::U8.into(), 3))?;
assert_eq!(m.aggregate(a), Some(&Aggregate::array(Type::U8.into(), 3)));Sourcepub fn aggregate_count(&self) -> usize
pub fn aggregate_count(&self) -> usize
The number of declared aggregates.
§Examples
use ir_lang::{Aggregate, Module, Type};
let mut m = Module::new("m");
m.declare_aggregate(Aggregate::structure(&[Type::U8.into()]))?;
assert_eq!(m.aggregate_count(), 1);Sourcepub fn layout(&self, ty: MemType) -> Option<Layout>
pub fn layout(&self, ty: MemType) -> Option<Layout>
The size and alignment of a memory type, or None for an unknown
aggregate.
§Examples
use ir_lang::{Module, Type};
let m = Module::new("m");
assert_eq!(m.layout(Type::Bool.into()).unwrap().size(), 1);Sourcepub fn field_offset(&self, agg: AggId, field: u32) -> Option<u64>
pub fn field_offset(&self, agg: AggId, field: u32) -> Option<u64>
The byte offset of a struct field, or None if agg is not a struct or has
no such field.
§Examples
use ir_lang::{Aggregate, Module, Type};
let mut m = Module::new("m");
let s = m.declare_aggregate(Aggregate::packed(&[Type::U8.into(), Type::U32.into()]))?;
assert_eq!(m.field_offset(s, 1), Some(1));
assert_eq!(m.field_offset(s, 2), None);Sourcepub fn declare_function(
&mut self,
name: &str,
sig: &Signature,
linkage: Linkage,
) -> Result<FuncId, ModuleError>
pub fn declare_function( &mut self, name: &str, sig: &Signature, linkage: Linkage, ) -> Result<FuncId, ModuleError>
Declares a function. Its signature is interned. A Local or Export
function needs a body (build) before the module validates;
an Import must not have one.
§Errors
ModuleError::EmptyName, ModuleError::DuplicateName,
ModuleError::CapacityExceeded.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("main", &Signature::new(&[], &[Type::I32]), Linkage::Export)?;
assert_eq!(m.func_decl(f).unwrap().name(), "main");Sourcepub fn set_attrs(
&mut self,
func: FuncId,
attrs: Attrs,
) -> Result<(), ModuleError>
pub fn set_attrs( &mut self, func: FuncId, attrs: Attrs, ) -> Result<(), ModuleError>
Sets a function’s attributes.
§Errors
§Examples
use ir_lang::{Attrs, Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("abort", &Signature::new(&[], &[]), Linkage::Import)?;
m.set_attrs(f, Attrs::NORETURN | Attrs::NOUNWIND)?;
assert!(m.func_decl(f).unwrap().attrs().contains(Attrs::NORETURN));Sourcepub fn func_decl(&self, func: FuncId) -> Option<&FuncDecl>
pub fn func_decl(&self, func: FuncId) -> Option<&FuncDecl>
A function’s declaration.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
assert_eq!(m.func_decl(f).map(|d| d.linkage()), Some(Linkage::Local));Sourcepub fn func_signature(&self, func: FuncId) -> Option<&Signature>
pub fn func_signature(&self, func: FuncId) -> Option<&Signature>
A function’s signature.
§Examples
use ir_lang::{Linkage, Module, Signature, Type};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[Type::U8], &[]), Linkage::Import)?;
assert_eq!(m.func_signature(f).unwrap().params, [Type::U8]);Sourcepub fn function_count(&self) -> usize
pub fn function_count(&self) -> usize
The number of declared functions.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
assert_eq!(m.function_count(), 1);Sourcepub fn functions(&self) -> impl ExactSizeIterator<Item = FuncId>
pub fn functions(&self) -> impl ExactSizeIterator<Item = FuncId>
Iterates over every declared function, in handle order.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
assert_eq!(m.functions().collect::<Vec<_>>(), [f]);Sourcepub fn function(&self, func: FuncId) -> Option<&Function>
pub fn function(&self, func: FuncId) -> Option<&Function>
A function’s body, if it has one.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
assert!(m.function(f).is_none());
let mut b = m.build(f)?;
b.ret(&[])?;
assert!(m.function(f).is_some());Sourcepub fn declare_global(
&mut self,
name: &str,
global: Global,
) -> Result<GlobalId, ModuleError>
pub fn declare_global( &mut self, name: &str, global: Global, ) -> Result<GlobalId, ModuleError>
Declares a global.
§Errors
ModuleError::EmptyName, ModuleError::DuplicateName,
ModuleError::BadAlignment, ModuleError::InitSizeMismatch,
ModuleError::RelocOutOfRange, ModuleError::ImportWithData,
ModuleError::CapacityExceeded. Relocation targets are checked by
validate, so a global may point at symbols declared
after it (or at itself).
§Examples
use ir_lang::{Global, Module, ModuleError};
let mut m = Module::new("m");
let err = m.declare_global("bad", Global::zeroed(8, 3)).unwrap_err();
assert_eq!(err, ModuleError::BadAlignment { align: 3 });Sourcepub fn global(&self, global: GlobalId) -> Option<&Global>
pub fn global(&self, global: GlobalId) -> Option<&Global>
A global’s definition.
§Examples
use ir_lang::{Global, Module};
let mut m = Module::new("m");
let g = m.declare_global("g", Global::zeroed(16, 8))?;
assert_eq!(m.global(g).map(|g| g.size), Some(16));Sourcepub fn global_name(&self, global: GlobalId) -> Option<&str>
pub fn global_name(&self, global: GlobalId) -> Option<&str>
A global’s name.
§Examples
use ir_lang::{Global, Module};
let mut m = Module::new("m");
let g = m.declare_global("table", Global::zeroed(8, 8))?;
assert_eq!(m.global_name(g), Some("table"));Sourcepub fn global_count(&self) -> usize
pub fn global_count(&self) -> usize
The number of declared globals.
§Examples
use ir_lang::{Global, Module};
let mut m = Module::new("m");
m.declare_global("g", Global::zeroed(1, 1))?;
assert_eq!(m.global_count(), 1);Sourcepub fn globals(&self) -> impl ExactSizeIterator<Item = GlobalId>
pub fn globals(&self) -> impl ExactSizeIterator<Item = GlobalId>
Iterates over every declared global, in handle order.
§Examples
use ir_lang::{Global, Module};
let mut m = Module::new("m");
let g = m.declare_global("g", Global::zeroed(1, 1))?;
assert_eq!(m.globals().collect::<Vec<_>>(), [g]);Sourcepub fn lookup(&self, name: &str) -> Option<SymbolRef>
pub fn lookup(&self, name: &str) -> Option<SymbolRef>
Looks a function or global up by name.
§Examples
use ir_lang::{Global, Module, SymbolRef};
let mut m = Module::new("m");
let g = m.declare_global("g", Global::zeroed(1, 1))?;
assert_eq!(m.lookup("g"), Some(SymbolRef::Global(g)));
assert_eq!(m.lookup("h"), None);Sourcepub fn build(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError>
pub fn build(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError>
Creates the body of a declared function and returns a Builder
positioned at the end of its entry block. The entry block’s parameters are
the signature’s parameters.
§Errors
ModuleError::UnknownFunction, ModuleError::CannotDefineImport,
ModuleError::AlreadyDefined.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
let mut b = m.build(f)?;
b.ret(&[])?;
assert!(m.build(f).is_err());
m.validate()?;Sourcepub fn edit(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError>
pub fn edit(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError>
Returns a Builder over an existing body, positioned at the end of the
entry block, for rewriting.
§Errors
ModuleError::UnknownFunction, ModuleError::NotDefined.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
let _ = m.build(f)?;
let mut b = m.edit(f)?;
b.ret(&[])?;
m.validate()?;Sourcepub fn validate(&self) -> Result<(), ValidationError>
pub fn validate(&self) -> Result<(), ValidationError>
Checks the whole module: declarations, then every function body.
Validation is total: it either accepts the module, guaranteeing every rule
of specs/IR.md holds, or returns the first violation. It never panics and
runs in time linear in the size of the module (plus the size of the live
ranges of GC references, for the safepoint rule).
§Errors
The first ValidationError found.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
assert!(m.validate().is_err()); // no body yet
let mut b = m.build(f)?;
b.ret(&[])?;
assert!(m.validate().is_ok());Sourcepub fn validate_function(&self, func: FuncId) -> Result<(), ValidationError>
pub fn validate_function(&self, func: FuncId) -> Result<(), ValidationError>
Checks one function body (and the declarations it uses).
§Errors
The first ValidationError found in that function;
ValidationErrorKind::UnknownFunction
or MissingBody if there is no
such body.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
let mut b = m.build(f)?;
b.ret(&[])?;
m.validate_function(f)?;Sourcepub fn display_function(&self, func: FuncId) -> impl Display + '_
pub fn display_function(&self, func: FuncId) -> impl Display + '_
Prints one function in the textual form.
§Examples
use ir_lang::{Linkage, Module, Signature};
let mut m = Module::new("m");
let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
let mut b = m.build(f)?;
b.ret(&[])?;
assert_eq!(m.display_function(f).to_string(), "func @f s0 export {\nb0:\n ret\n}\n");