Skip to main content

Module

Struct Module 

Source
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

Source

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));
Source

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);
Source

pub fn name(&self) -> &str

The module’s name.

§Examples
use ir_lang::Module;

assert_eq!(Module::new("app").name(), "app");
Source

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);
Source

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);
Source

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]);
Source

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);
Source

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);
Source

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)));
Source

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);
Source

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);
Source

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);
Source

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");
Source

pub fn set_attrs( &mut self, func: FuncId, attrs: Attrs, ) -> Result<(), ModuleError>

Sets a function’s attributes.

§Errors

ModuleError::UnknownFunction.

§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));
Source

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));
Source

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]);
Source

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);
Source

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]);
Source

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());
Source

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 });
Source

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));
Source

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"));
Source

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);
Source

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]);
Source

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);
Source

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()?;
Source

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()?;
Source

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());
Source

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)?;
Source

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");

Trait Implementations§

Source§

impl Clone for Module

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Module

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Module

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Prints the module in the textual form. The output depends only on the module and is the same on every platform; parse reads it back.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.