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(&mut self, controlling_type: Type, imm: Imm64, signed: bool) -> Value {
54 if controlling_type == types::I128 {
55 let mut data = InstructionData::UnaryImm {
56 opcode: Opcode::Iconst,
57 imm,
58 };
59 data.mask_immediates(types::I64);
60 let lo = self.build_aux_inst(data, types::I64);
61 let lo = self.data_flow_graph().first_result(lo);
62
63 let opcode = if signed {
64 Opcode::Sextend
65 } else {
66 Opcode::Uextend
67 };
68 let ext_inst =
69 self.build_aux_inst(InstructionData::Unary { opcode, arg: lo }, types::I128);
70 self.data_flow_graph().first_result(ext_inst)
71 } else {
72 let lane_type = controlling_type.lane_type();
73 let mut data = InstructionData::UnaryImm {
74 opcode: Opcode::Iconst,
75 imm,
76 };
77 data.mask_immediates(lane_type);
78 let inst = self.build_aux_inst(data, lane_type);
79 self.data_flow_graph().first_result(inst)
80 }
81 }
82}
83
84include!(concat!(env!("OUT_DIR"), "/inst_builder.rs"));
89
90impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {}
92
93pub trait InstInserterBase<'f>: Sized {
101 fn data_flow_graph(&self) -> &DataFlowGraph;
103
104 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
106
107 fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph;
109
110 fn insert_aux_inst(&mut self, inst: Inst);
116}
117
118use core::marker::PhantomData;
119
120pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> {
126 inserter: IIB,
127 unused: PhantomData<&'f u32>,
128}
129
130impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> {
131 pub fn new(inserter: IIB) -> Self {
134 Self {
135 inserter,
136 unused: PhantomData,
137 }
138 }
139
140 pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array>
148 where
149 Array: AsRef<[Option<Value>]>,
150 {
151 InsertReuseBuilder {
152 inserter: self.inserter,
153 reuse,
154 unused: PhantomData,
155 }
156 }
157
158 pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> {
166 self.with_results([Some(v)])
169 }
170}
171
172impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> {
173 fn data_flow_graph(&self) -> &DataFlowGraph {
174 self.inserter.data_flow_graph()
175 }
176
177 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
178 self.inserter.data_flow_graph_mut()
179 }
180
181 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
182 let dfg = self.inserter.data_flow_graph_mut();
183 let inst = dfg.make_inst(data);
184 dfg.make_inst_results(inst, ctrl_typevar);
185 (inst, self.inserter.insert_built_inst(inst))
186 }
187
188 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
189 let dfg = self.inserter.data_flow_graph_mut();
190 let inst = dfg.make_inst(data);
191 dfg.make_inst_results(inst, ctrl_typevar);
192 self.inserter.insert_aux_inst(inst);
193 inst
194 }
195}
196
197pub struct InsertReuseBuilder<'f, IIB, Array>
199where
200 IIB: InstInserterBase<'f>,
201 Array: AsRef<[Option<Value>]>,
202{
203 inserter: IIB,
204 reuse: Array,
205 unused: PhantomData<&'f u32>,
206}
207
208impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array>
209where
210 IIB: InstInserterBase<'f>,
211 Array: AsRef<[Option<Value>]>,
212{
213 fn data_flow_graph(&self) -> &DataFlowGraph {
214 self.inserter.data_flow_graph()
215 }
216
217 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
218 self.inserter.data_flow_graph_mut()
219 }
220
221 fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
222 let dfg = self.inserter.data_flow_graph_mut();
223 let inst = dfg.make_inst(data);
224 let reuse = self.reuse.as_ref().iter().cloned();
225 dfg.make_inst_results_reusing(inst, ctrl_typevar, reuse);
226 (inst, self.inserter.insert_built_inst(inst))
227 }
228
229 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
230 let inst;
233 {
234 let dfg = self.inserter.data_flow_graph_mut();
235 inst = dfg.make_inst(data);
236 dfg.make_inst_results(inst, ctrl_typevar);
237 }
238 self.inserter.insert_aux_inst(inst);
239 inst
240 }
241}
242
243pub struct ReplaceBuilder<'f> {
252 dfg: &'f mut DataFlowGraph,
253 layout: &'f mut Layout,
254 inst: Inst,
255}
256
257impl<'f> ReplaceBuilder<'f> {
258 pub fn new(dfg: &'f mut DataFlowGraph, layout: &'f mut Layout, inst: Inst) -> Self {
260 Self { dfg, layout, inst }
261 }
262}
263
264impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
265 fn data_flow_graph(&self) -> &DataFlowGraph {
266 self.dfg
267 }
268
269 fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
270 self.dfg
271 }
272
273 fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
274 self.dfg.insts[self.inst] = data;
276
277 if !self.dfg.has_results(self.inst) {
278 self.dfg.make_inst_results(self.inst, ctrl_typevar);
281 }
282
283 (self.inst, self.dfg)
284 }
285
286 fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
287 let inst = self.dfg.make_inst(data);
290 self.dfg.make_inst_results(inst, ctrl_typevar);
291 self.layout.insert_inst(inst, self.inst);
292 inst
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use crate::cursor::{Cursor, FuncCursor};
299 use crate::ir::condcodes::*;
300 use crate::ir::types::*;
301 use crate::ir::{Function, InstBuilder, Opcode, ValueDef};
302
303 #[test]
304 fn types() {
305 let mut func = Function::new();
306 let block0 = func.dfg.make_block();
307 let arg0 = func.dfg.append_block_param(block0, I32);
308 let mut pos = FuncCursor::new(&mut func);
309 pos.insert_block(block0);
310
311 let v0 = pos.ins().iconst(I32, 3);
313 assert_eq!(pos.func.dfg.value_type(v0), I32);
314
315 let v1 = pos.ins().iadd(arg0, v0);
317 assert_eq!(pos.func.dfg.value_type(v1), I32);
318
319 let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0);
321 assert_eq!(pos.func.dfg.value_type(cmp), I8);
322 }
323
324 #[test]
325 fn reuse_results() {
326 let mut func = Function::new();
327 let block0 = func.dfg.make_block();
328 let arg0 = func.dfg.append_block_param(block0, I32);
329 let mut pos = FuncCursor::new(&mut func);
330 pos.insert_block(block0);
331
332 let v0 = pos.ins().iadd_imm_s(arg0, 17);
333 assert_eq!(pos.func.dfg.value_type(v0), I32);
334 let iadd = pos.prev_inst().unwrap();
335 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0));
336
337 pos.func.dfg.clear_results(iadd);
339 let v0b = pos.ins().with_result(v0).iconst(I32, 3);
340 assert_eq!(v0, v0b);
341 assert_eq!(pos.current_inst(), Some(iadd));
342 let iconst = pos.prev_inst().unwrap();
343 assert!(iadd != iconst);
344 assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0));
345 }
346
347 #[test]
348 fn replace_with_imm_method() {
349 let mut func = Function::new();
353 let block0 = func.dfg.make_block();
354 let arg0 = func.dfg.append_block_param(block0, I32);
355 {
356 let mut pos = FuncCursor::new(&mut func);
357 pos.insert_block(block0);
358 pos.ins().icmp(IntCC::Equal, arg0, arg0);
360 }
361
362 let inst = func.layout.last_inst(block0).unwrap();
363 assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
364
365 let result = func.replace(inst).icmp_imm_s(IntCC::Equal, arg0, 42);
366
367 assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
370 assert_eq!(func.dfg.value_type(result), I8);
371
372 let iconst = func.layout.prev_inst(inst).unwrap();
374 assert_eq!(func.dfg.insts[iconst].opcode(), Opcode::Iconst);
375 let iconst_result = func.dfg.first_result(iconst);
376 assert_eq!(func.dfg.value_type(iconst_result), I32);
377 assert_eq!(func.dfg.inst_args(inst), &[arg0, iconst_result]);
378 }
379
380 #[test]
381 fn imm_s_and_imm_u_extend_i128() {
382 let mut func = Function::new();
387 let block0 = func.dfg.make_block();
388 let arg = func.dfg.append_block_param(block0, I128);
389 let mut pos = FuncCursor::new(&mut func);
390 pos.insert_block(block0);
391
392 fn ext_opcode(pos: &FuncCursor, iadd: crate::ir::Inst) -> Opcode {
394 let imm = pos.func.dfg.inst_args(iadd)[1];
395 let ext = pos.func.dfg.value_def(imm).unwrap_inst();
396 pos.func.dfg.insts[ext].opcode()
397 }
398
399 pos.ins().iadd_imm_s(arg, -1);
400 let iadd = pos.prev_inst().unwrap();
401 assert_eq!(ext_opcode(&pos, iadd), Opcode::Sextend);
402
403 pos.ins().iadd_imm_u(arg, -1);
404 let iadd = pos.prev_inst().unwrap();
405 assert_eq!(ext_opcode(&pos, iadd), Opcode::Uextend);
406
407 #[allow(deprecated, reason = "exercising the deprecated `_imm` shim")]
408 pos.ins().iadd_imm(arg, -1);
409 let iadd = pos.prev_inst().unwrap();
410 assert_eq!(ext_opcode(&pos, iadd), Opcode::Sextend);
411 }
412
413 #[test]
414 #[should_panic]
415 #[cfg(debug_assertions)]
416 fn panics_when_inserting_wrong_opcode() {
417 use crate::ir::{Opcode, TrapCode};
418
419 let mut func = Function::new();
420 let block0 = func.dfg.make_block();
421 let mut pos = FuncCursor::new(&mut func);
422 pos.insert_block(block0);
423
424 pos.ins()
426 .Trap(Opcode::Return, I32, TrapCode::BAD_CONVERSION_TO_INTEGER);
427 }
428}