1747ad3c4Slazypassion //! Cranelift instruction builder. 2747ad3c4Slazypassion //! 3747ad3c4Slazypassion //! A `Builder` provides a convenient interface for inserting instructions into a Cranelift 4747ad3c4Slazypassion //! function. Many of its methods are generated from the meta language instruction definitions. 5747ad3c4Slazypassion 6747ad3c4Slazypassion use crate::ir; 7d620705aSAfonso Bordado use crate::ir::instructions::InstructionFormat; 8747ad3c4Slazypassion use crate::ir::types; 9*94ec88eaSChris Fallin use crate::ir::{BlockArg, Inst, Opcode, Type, Value}; 10747ad3c4Slazypassion use crate::ir::{DataFlowGraph, InstructionData}; 11747ad3c4Slazypassion 12747ad3c4Slazypassion /// Base trait for instruction builders. 13747ad3c4Slazypassion /// 14747ad3c4Slazypassion /// The `InstBuilderBase` trait provides the basic functionality required by the methods of the 15747ad3c4Slazypassion /// generated `InstBuilder` trait. These methods should not normally be used directly. Use the 16747ad3c4Slazypassion /// methods in the `InstBuilder` trait instead. 17747ad3c4Slazypassion /// 18747ad3c4Slazypassion /// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder` 19747ad3c4Slazypassion /// trait. 20747ad3c4Slazypassion pub trait InstBuilderBase<'f>: Sized { 21747ad3c4Slazypassion /// Get an immutable reference to the data flow graph that will hold the constructed 22747ad3c4Slazypassion /// instructions. data_flow_graph(&self) -> &DataFlowGraph23747ad3c4Slazypassion fn data_flow_graph(&self) -> &DataFlowGraph; 24747ad3c4Slazypassion /// Get a mutable reference to the data flow graph that will hold the constructed 25747ad3c4Slazypassion /// instructions. data_flow_graph_mut(&mut self) -> &mut DataFlowGraph26747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; 27747ad3c4Slazypassion 28747ad3c4Slazypassion /// Insert an instruction and return a reference to it, consuming the builder. 29747ad3c4Slazypassion /// 30747ad3c4Slazypassion /// The result types may depend on a controlling type variable. For non-polymorphic 31747ad3c4Slazypassion /// instructions with multiple results, pass `INVALID` for the `ctrl_typevar` argument. build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph)32747ad3c4Slazypassion fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph); 33747ad3c4Slazypassion } 34747ad3c4Slazypassion 35563525b0SBenjamin Bouvier // Include trait code generated by `cranelift-codegen/meta/src/gen_inst.rs`. 36747ad3c4Slazypassion // 37747ad3c4Slazypassion // This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per 38747ad3c4Slazypassion // instruction format and per opcode. 39747ad3c4Slazypassion include!(concat!(env!("OUT_DIR"), "/inst_builder.rs")); 40747ad3c4Slazypassion 41747ad3c4Slazypassion /// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. 42747ad3c4Slazypassion impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {} 43747ad3c4Slazypassion 44747ad3c4Slazypassion /// Base trait for instruction inserters. 45747ad3c4Slazypassion /// 46747ad3c4Slazypassion /// This is an alternative base trait for an instruction builder to implement. 47747ad3c4Slazypassion /// 48747ad3c4Slazypassion /// An instruction inserter can be adapted into an instruction builder by wrapping it in an 49747ad3c4Slazypassion /// `InsertBuilder`. This provides some common functionality for instruction builders that insert 50747ad3c4Slazypassion /// new instructions, as opposed to the `ReplaceBuilder` which overwrites existing instructions. 51747ad3c4Slazypassion pub trait InstInserterBase<'f>: Sized { 52747ad3c4Slazypassion /// Get an immutable reference to the data flow graph. data_flow_graph(&self) -> &DataFlowGraph53747ad3c4Slazypassion fn data_flow_graph(&self) -> &DataFlowGraph; 54747ad3c4Slazypassion 55747ad3c4Slazypassion /// Get a mutable reference to the data flow graph. data_flow_graph_mut(&mut self) -> &mut DataFlowGraph56747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; 57747ad3c4Slazypassion 58747ad3c4Slazypassion /// Insert a new instruction which belongs to the DFG. insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph59bae4ec64SBenjamin Bouvier fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph; 60747ad3c4Slazypassion } 61747ad3c4Slazypassion 62747ad3c4Slazypassion use core::marker::PhantomData; 63747ad3c4Slazypassion 64747ad3c4Slazypassion /// Builder that inserts an instruction at the current position. 65747ad3c4Slazypassion /// 66747ad3c4Slazypassion /// An `InsertBuilder` is a wrapper for an `InstInserterBase` that turns it into an instruction 67747ad3c4Slazypassion /// builder with some additional facilities for creating instructions that reuse existing values as 68747ad3c4Slazypassion /// their results. 69747ad3c4Slazypassion pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> { 70747ad3c4Slazypassion inserter: IIB, 71747ad3c4Slazypassion unused: PhantomData<&'f u32>, 72747ad3c4Slazypassion } 73747ad3c4Slazypassion 74747ad3c4Slazypassion impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> { 75747ad3c4Slazypassion /// Create a new builder which inserts instructions at `pos`. 76747ad3c4Slazypassion /// The `dfg` and `pos.layout` references should be from the same `Function`. new(inserter: IIB) -> Self77747ad3c4Slazypassion pub fn new(inserter: IIB) -> Self { 78747ad3c4Slazypassion Self { 79747ad3c4Slazypassion inserter, 80747ad3c4Slazypassion unused: PhantomData, 81747ad3c4Slazypassion } 82747ad3c4Slazypassion } 83747ad3c4Slazypassion 84747ad3c4Slazypassion /// Reuse result values in `reuse`. 85747ad3c4Slazypassion /// 86747ad3c4Slazypassion /// Convert this builder into one that will reuse the provided result values instead of 87747ad3c4Slazypassion /// allocating new ones. The provided values for reuse must not be attached to anything. Any 88747ad3c4Slazypassion /// missing result values will be allocated as normal. 89747ad3c4Slazypassion /// 90747ad3c4Slazypassion /// The `reuse` argument is expected to be an array of `Option<Value>`. with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array> where Array: AsRef<[Option<Value>]>,91747ad3c4Slazypassion pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array> 92747ad3c4Slazypassion where 93747ad3c4Slazypassion Array: AsRef<[Option<Value>]>, 94747ad3c4Slazypassion { 95747ad3c4Slazypassion InsertReuseBuilder { 96747ad3c4Slazypassion inserter: self.inserter, 97747ad3c4Slazypassion reuse, 98747ad3c4Slazypassion unused: PhantomData, 99747ad3c4Slazypassion } 100747ad3c4Slazypassion } 101747ad3c4Slazypassion 102747ad3c4Slazypassion /// Reuse a single result value. 103747ad3c4Slazypassion /// 104747ad3c4Slazypassion /// Convert this into a builder that will reuse `v` as the single result value. The reused 105747ad3c4Slazypassion /// result value `v` must not be attached to anything. 106747ad3c4Slazypassion /// 107747ad3c4Slazypassion /// This method should only be used when building an instruction with exactly one result. Use 108747ad3c4Slazypassion /// `with_results()` for the more general case. with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]>109747ad3c4Slazypassion pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> { 110747ad3c4Slazypassion // TODO: Specialize this to return a different builder that just attaches `v` instead of 111747ad3c4Slazypassion // calling `make_inst_results_reusing()`. 112747ad3c4Slazypassion self.with_results([Some(v)]) 113747ad3c4Slazypassion } 114747ad3c4Slazypassion } 115747ad3c4Slazypassion 116747ad3c4Slazypassion impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> { data_flow_graph(&self) -> &DataFlowGraph117747ad3c4Slazypassion fn data_flow_graph(&self) -> &DataFlowGraph { 118747ad3c4Slazypassion self.inserter.data_flow_graph() 119747ad3c4Slazypassion } 120747ad3c4Slazypassion data_flow_graph_mut(&mut self) -> &mut DataFlowGraph121747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 122747ad3c4Slazypassion self.inserter.data_flow_graph_mut() 123747ad3c4Slazypassion } 124747ad3c4Slazypassion build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph)125747ad3c4Slazypassion fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 126747ad3c4Slazypassion let inst; 127747ad3c4Slazypassion { 128747ad3c4Slazypassion let dfg = self.inserter.data_flow_graph_mut(); 129747ad3c4Slazypassion inst = dfg.make_inst(data); 130747ad3c4Slazypassion dfg.make_inst_results(inst, ctrl_typevar); 131747ad3c4Slazypassion } 132bae4ec64SBenjamin Bouvier (inst, self.inserter.insert_built_inst(inst)) 133747ad3c4Slazypassion } 134747ad3c4Slazypassion } 135747ad3c4Slazypassion 136747ad3c4Slazypassion /// Builder that inserts a new instruction like `InsertBuilder`, but reusing result values. 137747ad3c4Slazypassion pub struct InsertReuseBuilder<'f, IIB, Array> 138747ad3c4Slazypassion where 139747ad3c4Slazypassion IIB: InstInserterBase<'f>, 140747ad3c4Slazypassion Array: AsRef<[Option<Value>]>, 141747ad3c4Slazypassion { 142747ad3c4Slazypassion inserter: IIB, 143747ad3c4Slazypassion reuse: Array, 144747ad3c4Slazypassion unused: PhantomData<&'f u32>, 145747ad3c4Slazypassion } 146747ad3c4Slazypassion 147747ad3c4Slazypassion impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array> 148747ad3c4Slazypassion where 149747ad3c4Slazypassion IIB: InstInserterBase<'f>, 150747ad3c4Slazypassion Array: AsRef<[Option<Value>]>, 151747ad3c4Slazypassion { data_flow_graph(&self) -> &DataFlowGraph152747ad3c4Slazypassion fn data_flow_graph(&self) -> &DataFlowGraph { 153747ad3c4Slazypassion self.inserter.data_flow_graph() 154747ad3c4Slazypassion } 155747ad3c4Slazypassion data_flow_graph_mut(&mut self) -> &mut DataFlowGraph156747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 157747ad3c4Slazypassion self.inserter.data_flow_graph_mut() 158747ad3c4Slazypassion } 159747ad3c4Slazypassion build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph)160747ad3c4Slazypassion fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 161747ad3c4Slazypassion let inst; 162747ad3c4Slazypassion { 163747ad3c4Slazypassion let dfg = self.inserter.data_flow_graph_mut(); 164747ad3c4Slazypassion inst = dfg.make_inst(data); 165747ad3c4Slazypassion // Make an `Iterator<Item = Option<Value>>`. 166747ad3c4Slazypassion let ru = self.reuse.as_ref().iter().cloned(); 167747ad3c4Slazypassion dfg.make_inst_results_reusing(inst, ctrl_typevar, ru); 168747ad3c4Slazypassion } 169bae4ec64SBenjamin Bouvier (inst, self.inserter.insert_built_inst(inst)) 170747ad3c4Slazypassion } 171747ad3c4Slazypassion } 172747ad3c4Slazypassion 173747ad3c4Slazypassion /// Instruction builder that replaces an existing instruction. 174747ad3c4Slazypassion /// 175747ad3c4Slazypassion /// The inserted instruction will have the same `Inst` number as the old one. 176747ad3c4Slazypassion /// 177747ad3c4Slazypassion /// If the old instruction still has result values attached, it is assumed that the new instruction 178747ad3c4Slazypassion /// produces the same number and types of results. The old result values are preserved. If the 179747ad3c4Slazypassion /// replacement instruction format does not support multiple results, the builder panics. It is a 180747ad3c4Slazypassion /// bug to leave result values dangling. 181747ad3c4Slazypassion pub struct ReplaceBuilder<'f> { 182747ad3c4Slazypassion dfg: &'f mut DataFlowGraph, 183747ad3c4Slazypassion inst: Inst, 184747ad3c4Slazypassion } 185747ad3c4Slazypassion 186747ad3c4Slazypassion impl<'f> ReplaceBuilder<'f> { 187747ad3c4Slazypassion /// Create a `ReplaceBuilder` that will overwrite `inst`. new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self188747ad3c4Slazypassion pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self { 189747ad3c4Slazypassion Self { dfg, inst } 190747ad3c4Slazypassion } 191747ad3c4Slazypassion } 192747ad3c4Slazypassion 193747ad3c4Slazypassion impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> { data_flow_graph(&self) -> &DataFlowGraph194747ad3c4Slazypassion fn data_flow_graph(&self) -> &DataFlowGraph { 195747ad3c4Slazypassion self.dfg 196747ad3c4Slazypassion } 197747ad3c4Slazypassion data_flow_graph_mut(&mut self) -> &mut DataFlowGraph198747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 199747ad3c4Slazypassion self.dfg 200747ad3c4Slazypassion } 201747ad3c4Slazypassion build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph)202747ad3c4Slazypassion fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 203747ad3c4Slazypassion // Splat the new instruction on top of the old one. 20425bf8e0eSTrevor Elliott self.dfg.insts[self.inst] = data; 205747ad3c4Slazypassion 206747ad3c4Slazypassion if !self.dfg.has_results(self.inst) { 207747ad3c4Slazypassion // The old result values were either detached or non-existent. 208747ad3c4Slazypassion // Construct new ones. 209747ad3c4Slazypassion self.dfg.make_inst_results(self.inst, ctrl_typevar); 210747ad3c4Slazypassion } 211747ad3c4Slazypassion 212747ad3c4Slazypassion (self.inst, self.dfg) 213747ad3c4Slazypassion } 214747ad3c4Slazypassion } 215747ad3c4Slazypassion 216747ad3c4Slazypassion #[cfg(test)] 217747ad3c4Slazypassion mod tests { 218747ad3c4Slazypassion use crate::cursor::{Cursor, FuncCursor}; 219747ad3c4Slazypassion use crate::ir::condcodes::*; 220747ad3c4Slazypassion use crate::ir::types::*; 2218eccc63cSAlex Crichton use crate::ir::{Function, InstBuilder, ValueDef}; 222747ad3c4Slazypassion 223747ad3c4Slazypassion #[test] types()224747ad3c4Slazypassion fn types() { 225747ad3c4Slazypassion let mut func = Function::new(); 226832666c4SRyan Hunt let block0 = func.dfg.make_block(); 227832666c4SRyan Hunt let arg0 = func.dfg.append_block_param(block0, I32); 228747ad3c4Slazypassion let mut pos = FuncCursor::new(&mut func); 229832666c4SRyan Hunt pos.insert_block(block0); 230747ad3c4Slazypassion 231747ad3c4Slazypassion // Explicit types. 232747ad3c4Slazypassion let v0 = pos.ins().iconst(I32, 3); 233747ad3c4Slazypassion assert_eq!(pos.func.dfg.value_type(v0), I32); 234747ad3c4Slazypassion 235747ad3c4Slazypassion // Inferred from inputs. 236747ad3c4Slazypassion let v1 = pos.ins().iadd(arg0, v0); 237747ad3c4Slazypassion assert_eq!(pos.func.dfg.value_type(v1), I32); 238747ad3c4Slazypassion 239747ad3c4Slazypassion // Formula. 240747ad3c4Slazypassion let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0); 24132a7593cSTrevor Elliott assert_eq!(pos.func.dfg.value_type(cmp), I8); 242747ad3c4Slazypassion } 243747ad3c4Slazypassion 244747ad3c4Slazypassion #[test] reuse_results()245747ad3c4Slazypassion fn reuse_results() { 246747ad3c4Slazypassion let mut func = Function::new(); 247832666c4SRyan Hunt let block0 = func.dfg.make_block(); 248832666c4SRyan Hunt let arg0 = func.dfg.append_block_param(block0, I32); 249747ad3c4Slazypassion let mut pos = FuncCursor::new(&mut func); 250832666c4SRyan Hunt pos.insert_block(block0); 251747ad3c4Slazypassion 252747ad3c4Slazypassion let v0 = pos.ins().iadd_imm(arg0, 17); 253747ad3c4Slazypassion assert_eq!(pos.func.dfg.value_type(v0), I32); 254747ad3c4Slazypassion let iadd = pos.prev_inst().unwrap(); 255747ad3c4Slazypassion assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0)); 256747ad3c4Slazypassion 257747ad3c4Slazypassion // Detach v0 and reuse it for a different instruction. 258747ad3c4Slazypassion pos.func.dfg.clear_results(iadd); 259747ad3c4Slazypassion let v0b = pos.ins().with_result(v0).iconst(I32, 3); 260747ad3c4Slazypassion assert_eq!(v0, v0b); 261747ad3c4Slazypassion assert_eq!(pos.current_inst(), Some(iadd)); 262747ad3c4Slazypassion let iconst = pos.prev_inst().unwrap(); 263747ad3c4Slazypassion assert!(iadd != iconst); 264747ad3c4Slazypassion assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0)); 265747ad3c4Slazypassion } 266d620705aSAfonso Bordado 267d620705aSAfonso Bordado #[test] 268d620705aSAfonso Bordado #[should_panic] 2698eccc63cSAlex Crichton #[cfg(debug_assertions)] panics_when_inserting_wrong_opcode()270d620705aSAfonso Bordado fn panics_when_inserting_wrong_opcode() { 2718eccc63cSAlex Crichton use crate::ir::{Opcode, TrapCode}; 2728eccc63cSAlex Crichton 273d620705aSAfonso Bordado let mut func = Function::new(); 274d620705aSAfonso Bordado let block0 = func.dfg.make_block(); 275d620705aSAfonso Bordado let mut pos = FuncCursor::new(&mut func); 276d620705aSAfonso Bordado pos.insert_block(block0); 277d620705aSAfonso Bordado 278d620705aSAfonso Bordado // We are trying to create a Opcode::Return with the InstData::Trap, which is obviously wrong 279d620705aSAfonso Bordado pos.ins() 2809fc41baeSAlex Crichton .Trap(Opcode::Return, I32, TrapCode::BAD_CONVERSION_TO_INTEGER); 281d620705aSAfonso Bordado } 282747ad3c4Slazypassion } 283