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