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