1 //! Cranelift instruction builder. 2 //! 3 //! A `Builder` provides a convenient interface for inserting instructions into a Cranelift 4 //! function. Many of its methods are generated from the meta language instruction definitions. 5 6 use crate::ir; 7 use crate::ir::types; 8 use crate::ir::{DataFlowGraph, InstructionData}; 9 use crate::ir::{Inst, Opcode, Type, Value}; 10 11 /// Base trait for instruction builders. 12 /// 13 /// The `InstBuilderBase` trait provides the basic functionality required by the methods of the 14 /// generated `InstBuilder` trait. These methods should not normally be used directly. Use the 15 /// methods in the `InstBuilder` trait instead. 16 /// 17 /// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder` 18 /// trait. 19 pub trait InstBuilderBase<'f>: Sized { 20 /// Get an immutable reference to the data flow graph that will hold the constructed 21 /// instructions. 22 fn data_flow_graph(&self) -> &DataFlowGraph; 23 /// Get a mutable reference to the data flow graph that will hold the constructed 24 /// instructions. 25 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; 26 27 /// Insert an instruction and return a reference to it, consuming the builder. 28 /// 29 /// The result types may depend on a controlling type variable. For non-polymorphic 30 /// instructions with multiple results, pass `INVALID` for the `ctrl_typevar` argument. 31 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph); 32 } 33 34 // Include trait code generated by `cranelift-codegen/meta/src/gen_inst.rs`. 35 // 36 // This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per 37 // instruction format and per opcode. 38 include!(concat!(env!("OUT_DIR"), "/inst_builder.rs")); 39 40 /// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. 41 impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {} 42 43 /// Base trait for instruction inserters. 44 /// 45 /// This is an alternative base trait for an instruction builder to implement. 46 /// 47 /// An instruction inserter can be adapted into an instruction builder by wrapping it in an 48 /// `InsertBuilder`. This provides some common functionality for instruction builders that insert 49 /// new instructions, as opposed to the `ReplaceBuilder` which overwrites existing instructions. 50 pub trait InstInserterBase<'f>: Sized { 51 /// Get an immutable reference to the data flow graph. 52 fn data_flow_graph(&self) -> &DataFlowGraph; 53 54 /// Get a mutable reference to the data flow graph. 55 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; 56 57 /// Insert a new instruction which belongs to the DFG. 58 fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph; 59 } 60 61 use core::marker::PhantomData; 62 63 /// Builder that inserts an instruction at the current position. 64 /// 65 /// An `InsertBuilder` is a wrapper for an `InstInserterBase` that turns it into an instruction 66 /// builder with some additional facilities for creating instructions that reuse existing values as 67 /// their results. 68 pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> { 69 inserter: IIB, 70 unused: PhantomData<&'f u32>, 71 } 72 73 impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> { 74 /// Create a new builder which inserts instructions at `pos`. 75 /// The `dfg` and `pos.layout` references should be from the same `Function`. 76 pub fn new(inserter: IIB) -> Self { 77 Self { 78 inserter, 79 unused: PhantomData, 80 } 81 } 82 83 /// Reuse result values in `reuse`. 84 /// 85 /// Convert this builder into one that will reuse the provided result values instead of 86 /// allocating new ones. The provided values for reuse must not be attached to anything. Any 87 /// missing result values will be allocated as normal. 88 /// 89 /// The `reuse` argument is expected to be an array of `Option<Value>`. 90 pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array> 91 where 92 Array: AsRef<[Option<Value>]>, 93 { 94 InsertReuseBuilder { 95 inserter: self.inserter, 96 reuse, 97 unused: PhantomData, 98 } 99 } 100 101 /// Reuse a single result value. 102 /// 103 /// Convert this into a builder that will reuse `v` as the single result value. The reused 104 /// result value `v` must not be attached to anything. 105 /// 106 /// This method should only be used when building an instruction with exactly one result. Use 107 /// `with_results()` for the more general case. 108 pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> { 109 // TODO: Specialize this to return a different builder that just attaches `v` instead of 110 // calling `make_inst_results_reusing()`. 111 self.with_results([Some(v)]) 112 } 113 } 114 115 impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> { 116 fn data_flow_graph(&self) -> &DataFlowGraph { 117 self.inserter.data_flow_graph() 118 } 119 120 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 121 self.inserter.data_flow_graph_mut() 122 } 123 124 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 125 let inst; 126 { 127 let dfg = self.inserter.data_flow_graph_mut(); 128 inst = dfg.make_inst(data); 129 dfg.make_inst_results(inst, ctrl_typevar); 130 } 131 (inst, self.inserter.insert_built_inst(inst)) 132 } 133 } 134 135 /// Builder that inserts a new instruction like `InsertBuilder`, but reusing result values. 136 pub struct InsertReuseBuilder<'f, IIB, Array> 137 where 138 IIB: InstInserterBase<'f>, 139 Array: AsRef<[Option<Value>]>, 140 { 141 inserter: IIB, 142 reuse: Array, 143 unused: PhantomData<&'f u32>, 144 } 145 146 impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array> 147 where 148 IIB: InstInserterBase<'f>, 149 Array: AsRef<[Option<Value>]>, 150 { 151 fn data_flow_graph(&self) -> &DataFlowGraph { 152 self.inserter.data_flow_graph() 153 } 154 155 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 156 self.inserter.data_flow_graph_mut() 157 } 158 159 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 160 let inst; 161 { 162 let dfg = self.inserter.data_flow_graph_mut(); 163 inst = dfg.make_inst(data); 164 // Make an `Iterator<Item = Option<Value>>`. 165 let ru = self.reuse.as_ref().iter().cloned(); 166 dfg.make_inst_results_reusing(inst, ctrl_typevar, ru); 167 } 168 (inst, self.inserter.insert_built_inst(inst)) 169 } 170 } 171 172 /// Instruction builder that replaces an existing instruction. 173 /// 174 /// The inserted instruction will have the same `Inst` number as the old one. 175 /// 176 /// If the old instruction still has result values attached, it is assumed that the new instruction 177 /// produces the same number and types of results. The old result values are preserved. If the 178 /// replacement instruction format does not support multiple results, the builder panics. It is a 179 /// bug to leave result values dangling. 180 pub struct ReplaceBuilder<'f> { 181 dfg: &'f mut DataFlowGraph, 182 inst: Inst, 183 } 184 185 impl<'f> ReplaceBuilder<'f> { 186 /// Create a `ReplaceBuilder` that will overwrite `inst`. 187 pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self { 188 Self { dfg, inst } 189 } 190 } 191 192 impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> { 193 fn data_flow_graph(&self) -> &DataFlowGraph { 194 self.dfg 195 } 196 197 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { 198 self.dfg 199 } 200 201 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { 202 // Splat the new instruction on top of the old one. 203 self.dfg[self.inst] = data; 204 205 if !self.dfg.has_results(self.inst) { 206 // The old result values were either detached or non-existent. 207 // Construct new ones. 208 self.dfg.make_inst_results(self.inst, ctrl_typevar); 209 } 210 211 (self.inst, self.dfg) 212 } 213 } 214 215 #[cfg(test)] 216 mod tests { 217 use crate::cursor::{Cursor, FuncCursor}; 218 use crate::ir::condcodes::*; 219 use crate::ir::types::*; 220 use crate::ir::{Function, InstBuilder, ValueDef}; 221 222 #[test] 223 fn types() { 224 let mut func = Function::new(); 225 let block0 = func.dfg.make_block(); 226 let arg0 = func.dfg.append_block_param(block0, I32); 227 let mut pos = FuncCursor::new(&mut func); 228 pos.insert_block(block0); 229 230 // Explicit types. 231 let v0 = pos.ins().iconst(I32, 3); 232 assert_eq!(pos.func.dfg.value_type(v0), I32); 233 234 // Inferred from inputs. 235 let v1 = pos.ins().iadd(arg0, v0); 236 assert_eq!(pos.func.dfg.value_type(v1), I32); 237 238 // Formula. 239 let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0); 240 assert_eq!(pos.func.dfg.value_type(cmp), B1); 241 } 242 243 #[test] 244 fn reuse_results() { 245 let mut func = Function::new(); 246 let block0 = func.dfg.make_block(); 247 let arg0 = func.dfg.append_block_param(block0, I32); 248 let mut pos = FuncCursor::new(&mut func); 249 pos.insert_block(block0); 250 251 let v0 = pos.ins().iadd_imm(arg0, 17); 252 assert_eq!(pos.func.dfg.value_type(v0), I32); 253 let iadd = pos.prev_inst().unwrap(); 254 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0)); 255 256 // Detach v0 and reuse it for a different instruction. 257 pos.func.dfg.clear_results(iadd); 258 let v0b = pos.ins().with_result(v0).iconst(I32, 3); 259 assert_eq!(v0, v0b); 260 assert_eq!(pos.current_inst(), Some(iadd)); 261 let iconst = pos.prev_inst().unwrap(); 262 assert!(iadd != iconst); 263 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0)); 264 } 265 } 266