Path: blob/main/cranelift/frontend/src/lib.rs
1692 views
//! Cranelift IR builder library.1//!2//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions3//! corresponding to your source program written in another language.4//!5//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and6//! pass it as an argument to a [`FunctionBuilder`].7//!8//! # Mutable variables and Cranelift IR values9//!10//! The most interesting feature of this API is that it provides a single way to deal with all your11//! variable problems. Indeed, the [`FunctionBuilder`] struct has a12//! type `Variable` that should be an index of your source language variables. Then, through13//! calling the functions14//! [`declare_var`](FunctionBuilder::declare_var), [`def_var`](FunctionBuilder::def_var) and15//! [`use_var`](FunctionBuilder::use_var), the [`FunctionBuilder`] will create for you all the16//! Cranelift IR values corresponding to your variables.17//!18//! This API has been designed to help you translate your mutable variables into19//! [`SSA`](https://en.wikipedia.org/wiki/Static_single_assignment_form) form.20//! [`use_var`](FunctionBuilder::use_var) will return the Cranelift IR value21//! that corresponds to your mutable variable at a precise point in the program. However, if you know22//! beforehand that one of your variables is defined only once, for instance if it is the result23//! of an intermediate expression in an expression-based language, then you can translate it24//! directly by the Cranelift IR value returned by the instruction builder. Using the25//! [`use_var`](FunctionBuilder::use_var) API for such an immutable variable26//! would also work but with a slight additional overhead (the SSA algorithm does not know27//! beforehand if a variable is immutable or not).28//!29//! The moral is that you should use these three functions to handle all your mutable variables,30//! even those that are not present in the source code but artifacts of the translation. It is up31//! to you to keep a mapping between the mutable variables of your language and their [`Variable`]32//! index that is used by Cranelift. Caution: as the [`Variable`] is used by Cranelift to index an33//! array containing information about your mutable variables, when you create a new [`Variable`]34//! with `Variable::new(var_index)` you should make sure that `var_index`35//! is provided by a counter incremented by 1 each time you encounter a new mutable variable.36//!37//! # Example38//!39//! Here is a pseudo-program we want to transform into Cranelift IR:40//!41//! ```clif42//! function(x) {43//! x, y, z : i3244//! block0:45//! y = 2;46//! z = x + y;47//! jump block148//! block1:49//! z = z + y;50//! brif y, block3, block251//! block2:52//! z = z - x;53//! return y54//! block3:55//! y = y - x56//! jump block157//! }58//! ```59//!60//! Here is how you build the corresponding Cranelift IR function using [`FunctionBuilderContext`]:61//!62//! ```rust63//! use cranelift_codegen::ir::types::*;64//! use cranelift_codegen::ir::{AbiParam, UserFuncName, Function, InstBuilder, Signature};65//! use cranelift_codegen::isa::CallConv;66//! use cranelift_codegen::settings;67//! use cranelift_codegen::verifier::verify_function;68//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};69//!70//! let mut sig = Signature::new(CallConv::SystemV);71//! sig.returns.push(AbiParam::new(I32));72//! sig.params.push(AbiParam::new(I32));73//! let mut fn_builder_ctx = FunctionBuilderContext::new();74//! let mut func = Function::with_name_signature(UserFuncName::user(0, 0), sig);75//! {76//! let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);77//!78//! let block0 = builder.create_block();79//! let block1 = builder.create_block();80//! let block2 = builder.create_block();81//! let block3 = builder.create_block();82//! let x = builder.declare_var(I32);83//! let y = builder.declare_var(I32);84//! let z = builder.declare_var(I32);85//! builder.append_block_params_for_function_params(block0);86//!87//! builder.switch_to_block(block0);88//! builder.seal_block(block0);89//! {90//! let tmp = builder.block_params(block0)[0]; // the first function parameter91//! builder.def_var(x, tmp);92//! }93//! {94//! let tmp = builder.ins().iconst(I32, 2);95//! builder.def_var(y, tmp);96//! }97//! {98//! let arg1 = builder.use_var(x);99//! let arg2 = builder.use_var(y);100//! let tmp = builder.ins().iadd(arg1, arg2);101//! builder.def_var(z, tmp);102//! }103//! builder.ins().jump(block1, &[]);104//!105//! builder.switch_to_block(block1);106//! {107//! let arg1 = builder.use_var(y);108//! let arg2 = builder.use_var(z);109//! let tmp = builder.ins().iadd(arg1, arg2);110//! builder.def_var(z, tmp);111//! }112//! {113//! let arg = builder.use_var(y);114//! builder.ins().brif(arg, block3, &[], block2, &[]);115//! }116//!117//! builder.switch_to_block(block2);118//! builder.seal_block(block2);119//! {120//! let arg1 = builder.use_var(z);121//! let arg2 = builder.use_var(x);122//! let tmp = builder.ins().isub(arg1, arg2);123//! builder.def_var(z, tmp);124//! }125//! {126//! let arg = builder.use_var(y);127//! builder.ins().return_(&[arg]);128//! }129//!130//! builder.switch_to_block(block3);131//! builder.seal_block(block3);132//!133//! {134//! let arg1 = builder.use_var(y);135//! let arg2 = builder.use_var(x);136//! let tmp = builder.ins().isub(arg1, arg2);137//! builder.def_var(y, tmp);138//! }139//! builder.ins().jump(block1, &[]);140//! builder.seal_block(block1);141//!142//! builder.finalize();143//! }144//!145//! let flags = settings::Flags::new(settings::builder());146//! let res = verify_function(&func, &flags);147//! println!("{}", func.display());148//! if let Err(errors) = res {149//! panic!("{}", errors);150//! }151//! ```152153#![deny(missing_docs)]154#![no_std]155156extern crate alloc;157158#[cfg(feature = "std")]159#[macro_use]160extern crate std;161162#[cfg(not(feature = "std"))]163use hashbrown::{HashMap, HashSet};164#[cfg(feature = "std")]165use std::collections::{HashMap, HashSet};166167pub use crate::frontend::{FuncInstBuilder, FunctionBuilder, FunctionBuilderContext};168pub use crate::switch::Switch;169pub use crate::variable::Variable;170171#[cfg(test)]172macro_rules! assert_eq_output {173( $left:expr, $right:expr $(,)? ) => {{174let left = $left;175let left = left.trim();176177let right = $right;178let right = right.trim();179180assert_eq!(181left,182right,183"assertion failed, output not equal:\n\184\n\185=========== Diff ===========\n\186{}\n\187=========== Left ===========\n\188{left}\n\189=========== Right ===========\n\190{right}\n\191",192similar::TextDiff::from_lines(left, right)193.unified_diff()194.header("left", "right")195)196}};197}198199mod frontend;200mod ssa;201mod switch;202mod variable;203204/// Version number of this crate.205pub const VERSION: &str = env!("CARGO_PKG_VERSION");206207208