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