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