1use crate::ir;
7use crate::ir::immediates::Imm64;
8use crate::ir::instructions::InstructionFormat;
9use crate::ir::types;
10use crate::ir::{BlockArg, Inst, Layout, Opcode, Type, Value};
11use crate::ir::{DataFlowGraph, InstructionData};
12
13pub trait InstBuilderBase<'f>: Sized {
22 fn data_flow_graph(&self) -> &DataFlowGraph;
25 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
28
29 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph);
34
35 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst;
42
43 fn build_imm_const(
58 &mut self,
59 controlling_type: Type,
60 imm: Imm64,
61 base_opcode: Opcode,
62 ) -> Value {
63 if controlling_type == types::I128 {
64 let mut data = InstructionData::UnaryImm {
65 opcode: Opcode::Iconst,
66 imm,
67 };
68 data.mask_immediates(types::I64);
69 let lo = self.build_aux_inst(data, types::I64);
70 let lo = self.data_flow_graph().first_result(lo);
71
72 let opcode = if matches!(
75 base_opcode,
76 Opcode::Iadd | Opcode::Imul | Opcode::Sdiv | Opcode::Srem | Opcode::Icmp
77 ) {
78 Opcode::Sextend
79 } else {
80 Opcode::Uextend
81 };
82 let ext_inst =
83 self.build_aux_inst(InstructionData::Unary { opcode, arg: lo }, types::I128);
84 self.data_flow_graph().first_result(ext_inst)
85 } else {
86 let lane_type = controlling_type.lane_type();
87 let mut data = InstructionData::UnaryImm {
88 opcode: Opcode::Iconst,
89 imm,
90 };
91 data.mask_immediates(lane_type);
92 let inst = self.build_aux_inst(data, lane_type);
93 self.data_flow_graph().first_result(inst)
94 }
95 }
96}
97
98include!(concat!(env!("OUT_DIR"), "/inst_builder.rs"));
103
104impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {}
106
107pub trait InstInserterBase<'f>: Sized {
115 fn data_flow_graph(&self) -> &DataFlowGraph;
117
118 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
120
121 fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph;
123
124 fn insert_aux_inst(&mut self, inst: Inst);
130}
131
132use core::marker::PhantomData;
133
134pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> {
140 inserter: IIB,
141 unused: PhantomData<&'f u32>,
142}
143
144impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> {
145 pub fn new(inserter: IIB) -> Self {
148 Self {
149 inserter,
150 unused: PhantomData,
151 }
152 }
153
154 pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array>
162 where
163 Array: AsRef<[Option<Value>]>,
164 {
165 InsertReuseBuilder {
166 inserter: self.inserter,
167 reuse,
168 unused: PhantomData,
169 }
170 }
171
172 pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> {
180 self.with_results([Some(v)])
183 }
184}
185
186impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> {
187 fn data_flow_graph(&self) -> &DataFlowGraph {
188 self.inserter.data_flow_graph()
189 }
190
191 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
192 self.inserter.data_flow_graph_mut()
193 }
194
195 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
196 let dfg = self.inserter.data_flow_graph_mut();
197 let inst = dfg.make_inst(data);
198 dfg.make_inst_results(inst, ctrl_typevar);
199 (inst, self.inserter.insert_built_inst(inst))
200 }
201
202 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
203 let dfg = self.inserter.data_flow_graph_mut();
204 let inst = dfg.make_inst(data);
205 dfg.make_inst_results(inst, ctrl_typevar);
206 self.inserter.insert_aux_inst(inst);
207 inst
208 }
209}
210
211pub struct InsertReuseBuilder<'f, IIB, Array>
213where
214 IIB: InstInserterBase<'f>,
215 Array: AsRef<[Option<Value>]>,
216{
217 inserter: IIB,
218 reuse: Array,
219 unused: PhantomData<&'f u32>,
220}
221
222impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array>
223where
224 IIB: InstInserterBase<'f>,
225 Array: AsRef<[Option<Value>]>,
226{
227 fn data_flow_graph(&self) -> &DataFlowGraph {
228 self.inserter.data_flow_graph()
229 }
230
231 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
232 self.inserter.data_flow_graph_mut()
233 }
234
235 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
236 let dfg = self.inserter.data_flow_graph_mut();
237 let inst = dfg.make_inst(data);
238 let reuse = self.reuse.as_ref().iter().cloned();
239 dfg.make_inst_results_reusing(inst, ctrl_typevar, reuse);
240 (inst, self.inserter.insert_built_inst(inst))
241 }
242
243 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
244 let inst;
247 {
248 let dfg = self.inserter.data_flow_graph_mut();
249 inst = dfg.make_inst(data);
250 dfg.make_inst_results(inst, ctrl_typevar);
251 }
252 self.inserter.insert_aux_inst(inst);
253 inst
254 }
255}
256
257pub struct ReplaceBuilder<'f> {
266 dfg: &'f mut DataFlowGraph,
267 layout: &'f mut Layout,
268 inst: Inst,
269}
270
271impl<'f> ReplaceBuilder<'f> {
272 pub fn new(dfg: &'f mut DataFlowGraph, layout: &'f mut Layout, inst: Inst) -> Self {
274 Self { dfg, layout, inst }
275 }
276}
277
278impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
279 fn data_flow_graph(&self) -> &DataFlowGraph {
280 self.dfg
281 }
282
283 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
284 self.dfg
285 }
286
287 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
288 self.dfg.insts[self.inst] = data;
290
291 if !self.dfg.has_results(self.inst) {
292 self.dfg.make_inst_results(self.inst, ctrl_typevar);
295 }
296
297 (self.inst, self.dfg)
298 }
299
300 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
301 let inst = self.dfg.make_inst(data);
304 self.dfg.make_inst_results(inst, ctrl_typevar);
305 self.layout.insert_inst(inst, self.inst);
306 inst
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use crate::cursor::{Cursor, FuncCursor};
313 use crate::ir::condcodes::*;
314 use crate::ir::types::*;
315 use crate::ir::{Function, InstBuilder, Opcode, ValueDef};
316
317 #[test]
318 fn types() {
319 let mut func = Function::new();
320 let block0 = func.dfg.make_block();
321 let arg0 = func.dfg.append_block_param(block0, I32);
322 let mut pos = FuncCursor::new(&mut func);
323 pos.insert_block(block0);
324
325 let v0 = pos.ins().iconst(I32, 3);
327 assert_eq!(pos.func.dfg.value_type(v0), I32);
328
329 let v1 = pos.ins().iadd(arg0, v0);
331 assert_eq!(pos.func.dfg.value_type(v1), I32);
332
333 let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0);
335 assert_eq!(pos.func.dfg.value_type(cmp), I8);
336 }
337
338 #[test]
339 fn reuse_results() {
340 let mut func = Function::new();
341 let block0 = func.dfg.make_block();
342 let arg0 = func.dfg.append_block_param(block0, I32);
343 let mut pos = FuncCursor::new(&mut func);
344 pos.insert_block(block0);
345
346 let v0 = pos.ins().iadd_imm(arg0, 17);
347 assert_eq!(pos.func.dfg.value_type(v0), I32);
348 let iadd = pos.prev_inst().unwrap();
349 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0));
350
351 pos.func.dfg.clear_results(iadd);
353 let v0b = pos.ins().with_result(v0).iconst(I32, 3);
354 assert_eq!(v0, v0b);
355 assert_eq!(pos.current_inst(), Some(iadd));
356 let iconst = pos.prev_inst().unwrap();
357 assert!(iadd != iconst);
358 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0));
359 }
360
361 #[test]
362 fn replace_with_imm_method() {
363 let mut func = Function::new();
367 let block0 = func.dfg.make_block();
368 let arg0 = func.dfg.append_block_param(block0, I32);
369 {
370 let mut pos = FuncCursor::new(&mut func);
371 pos.insert_block(block0);
372 pos.ins().icmp(IntCC::Equal, arg0, arg0);
374 }
375
376 let inst = func.layout.last_inst(block0).unwrap();
377 assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
378
379 let result = func.replace(inst).icmp_imm(IntCC::Equal, arg0, 42);
380
381 assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
384 assert_eq!(func.dfg.value_type(result), I8);
385
386 let iconst = func.layout.prev_inst(inst).unwrap();
388 assert_eq!(func.dfg.insts[iconst].opcode(), Opcode::Iconst);
389 let iconst_result = func.dfg.first_result(iconst);
390 assert_eq!(func.dfg.value_type(iconst_result), I32);
391 assert_eq!(func.dfg.inst_args(inst), &[arg0, iconst_result]);
392 }
393
394 #[test]
395 #[should_panic]
396 #[cfg(debug_assertions)]
397 fn panics_when_inserting_wrong_opcode() {
398 use crate::ir::{Opcode, TrapCode};
399
400 let mut func = Function::new();
401 let block0 = func.dfg.make_block();
402 let mut pos = FuncCursor::new(&mut func);
403 pos.insert_block(block0);
404
405 pos.ins()
407 .Trap(Opcode::Return, I32, TrapCode::BAD_CONVERSION_TO_INTEGER);
408 }
409}