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