1 use crate::cdsl::instructions::{InstSpec, Instruction, InstructionPredicate};
2 use crate::cdsl::operands::{OperandKind, OperandKindFields};
3 use crate::cdsl::types::ValueType;
4 use crate::cdsl::typevar::{TypeSetBuilder, TypeVar};
5 
6 use cranelift_entity::{entity_impl, PrimaryMap, SparseMap, SparseMapValue};
7 
8 use std::fmt;
9 use std::iter::IntoIterator;
10 
11 pub(crate) enum Expr {
12     Var(VarIndex),
13     Literal(Literal),
14 }
15 
16 impl Expr {
maybe_literal(&self) -> Option<&Literal>17     pub fn maybe_literal(&self) -> Option<&Literal> {
18         match &self {
19             Expr::Literal(lit) => Some(lit),
20             _ => None,
21         }
22     }
23 
maybe_var(&self) -> Option<VarIndex>24     pub fn maybe_var(&self) -> Option<VarIndex> {
25         if let Expr::Var(var) = &self {
26             Some(*var)
27         } else {
28             None
29         }
30     }
31 
unwrap_var(&self) -> VarIndex32     pub fn unwrap_var(&self) -> VarIndex {
33         self.maybe_var()
34             .expect("tried to unwrap a non-Var content in Expr::unwrap_var")
35     }
36 
to_rust_code(&self, var_pool: &VarPool) -> String37     pub fn to_rust_code(&self, var_pool: &VarPool) -> String {
38         match self {
39             Expr::Var(var_index) => var_pool.get(*var_index).to_rust_code(),
40             Expr::Literal(literal) => literal.to_rust_code(),
41         }
42     }
43 }
44 
45 /// An AST definition associates a set of variables with the values produced by an expression.
46 pub(crate) struct Def {
47     pub apply: Apply,
48     pub defined_vars: Vec<VarIndex>,
49 }
50 
51 impl Def {
to_comment_string(&self, var_pool: &VarPool) -> String52     pub fn to_comment_string(&self, var_pool: &VarPool) -> String {
53         let results = self
54             .defined_vars
55             .iter()
56             .map(|&x| var_pool.get(x).name.as_str())
57             .collect::<Vec<_>>();
58 
59         let results = if results.len() == 1 {
60             results[0].to_string()
61         } else {
62             format!("({})", results.join(", "))
63         };
64 
65         format!("{} := {}", results, self.apply.to_comment_string(var_pool))
66     }
67 }
68 
69 pub(crate) struct DefPool {
70     pool: PrimaryMap<DefIndex, Def>,
71 }
72 
73 impl DefPool {
new() -> Self74     pub fn new() -> Self {
75         Self {
76             pool: PrimaryMap::new(),
77         }
78     }
get(&self, index: DefIndex) -> &Def79     pub fn get(&self, index: DefIndex) -> &Def {
80         self.pool.get(index).unwrap()
81     }
next_index(&self) -> DefIndex82     pub fn next_index(&self) -> DefIndex {
83         self.pool.next_key()
84     }
create_inst(&mut self, apply: Apply, defined_vars: Vec<VarIndex>) -> DefIndex85     pub fn create_inst(&mut self, apply: Apply, defined_vars: Vec<VarIndex>) -> DefIndex {
86         self.pool.push(Def {
87             apply,
88             defined_vars,
89         })
90     }
91 }
92 
93 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
94 pub(crate) struct DefIndex(u32);
95 entity_impl!(DefIndex);
96 
97 /// A definition which would lead to generate a block creation.
98 #[derive(Clone)]
99 pub(crate) struct Block {
100     /// Instruction index after which the block entry is set.
101     pub location: DefIndex,
102     /// Variable holding the new created block.
103     pub name: VarIndex,
104 }
105 
106 pub(crate) struct BlockPool {
107     pool: SparseMap<DefIndex, Block>,
108 }
109 
110 impl SparseMapValue<DefIndex> for Block {
key(&self) -> DefIndex111     fn key(&self) -> DefIndex {
112         self.location
113     }
114 }
115 
116 impl BlockPool {
new() -> Self117     pub fn new() -> Self {
118         Self {
119             pool: SparseMap::new(),
120         }
121     }
get(&self, index: DefIndex) -> Option<&Block>122     pub fn get(&self, index: DefIndex) -> Option<&Block> {
123         self.pool.get(index)
124     }
create_block(&mut self, name: VarIndex, location: DefIndex)125     pub fn create_block(&mut self, name: VarIndex, location: DefIndex) {
126         if self.pool.contains_key(location) {
127             panic!("Attempt to insert 2 blocks after the same instruction")
128         }
129         self.pool.insert(Block { location, name });
130     }
is_empty(&self) -> bool131     pub fn is_empty(&self) -> bool {
132         self.pool.is_empty()
133     }
134 }
135 
136 // Implement IntoIterator such that we can iterate over blocks which are in the block pool.
137 impl<'a> IntoIterator for &'a BlockPool {
138     type Item = <&'a SparseMap<DefIndex, Block> as IntoIterator>::Item;
139     type IntoIter = <&'a SparseMap<DefIndex, Block> as IntoIterator>::IntoIter;
140 
into_iter(self) -> Self::IntoIter141     fn into_iter(self) -> Self::IntoIter {
142         self.pool.into_iter()
143     }
144 }
145 
146 #[derive(Clone, Debug)]
147 pub(crate) enum Literal {
148     /// A value of an enumerated immediate operand.
149     ///
150     /// Some immediate operand kinds like `intcc` and `floatcc` have an enumerated range of values
151     /// corresponding to a Rust enum type. An `Enumerator` object is an AST leaf node representing one
152     /// of the values.
153     Enumerator {
154         rust_type: &'static str,
155         value: &'static str,
156     },
157 
158     /// A bitwise value of an immediate operand, used for bitwise exact floating point constants.
159     Bits { rust_type: &'static str, value: u64 },
160 
161     /// A value of an integer immediate operand.
162     Int(i64),
163 
164     /// A empty list of variable set of arguments.
165     EmptyVarArgs,
166 }
167 
168 impl Literal {
enumerator_for(kind: &OperandKind, value: &'static str) -> Self169     pub fn enumerator_for(kind: &OperandKind, value: &'static str) -> Self {
170         let value = match &kind.fields {
171             OperandKindFields::ImmEnum(values) => values.get(value).unwrap_or_else(|| {
172                 panic!(
173                     "nonexistent value '{}' in enumeration '{}'",
174                     value, kind.rust_type
175                 )
176             }),
177             _ => panic!("enumerator is for enum values"),
178         };
179         Literal::Enumerator {
180             rust_type: kind.rust_type,
181             value,
182         }
183     }
184 
bits(kind: &OperandKind, bits: u64) -> Self185     pub fn bits(kind: &OperandKind, bits: u64) -> Self {
186         match kind.fields {
187             OperandKindFields::ImmValue => {}
188             _ => panic!("bits_of is for immediate scalar types"),
189         }
190         Literal::Bits {
191             rust_type: kind.rust_type,
192             value: bits,
193         }
194     }
195 
constant(kind: &OperandKind, value: i64) -> Self196     pub fn constant(kind: &OperandKind, value: i64) -> Self {
197         match kind.fields {
198             OperandKindFields::ImmValue => {}
199             _ => panic!("constant is for immediate scalar types"),
200         }
201         Literal::Int(value)
202     }
203 
empty_vararg() -> Self204     pub fn empty_vararg() -> Self {
205         Literal::EmptyVarArgs
206     }
207 
to_rust_code(&self) -> String208     pub fn to_rust_code(&self) -> String {
209         match self {
210             Literal::Enumerator { rust_type, value } => format!("{}::{}", rust_type, value),
211             Literal::Bits { rust_type, value } => format!("{}::with_bits({:#x})", rust_type, value),
212             Literal::Int(val) => val.to_string(),
213             Literal::EmptyVarArgs => "&[]".into(),
214         }
215     }
216 }
217 
218 #[derive(Clone, Copy, Debug)]
219 pub(crate) enum PatternPosition {
220     Source,
221     Destination,
222 }
223 
224 /// A free variable.
225 ///
226 /// When variables are used in `XForms` with source and destination patterns, they are classified
227 /// as follows:
228 ///
229 /// Input values: Uses in the source pattern with no preceding def. These may appear as inputs in
230 /// the destination pattern too, but no new inputs can be introduced.
231 ///
232 /// Output values: Variables that are defined in both the source and destination pattern.  These
233 /// values may have uses outside the source pattern, and the destination pattern must compute the
234 /// same value.
235 ///
236 /// Intermediate values: Values that are defined in the source pattern, but not in the destination
237 /// pattern. These may have uses outside the source pattern, so the defining instruction can't be
238 /// deleted immediately.
239 ///
240 /// Temporary values are defined only in the destination pattern.
241 pub(crate) struct Var {
242     pub name: String,
243 
244     /// The `Def` defining this variable in a source pattern.
245     pub src_def: Option<DefIndex>,
246 
247     /// The `Def` defining this variable in a destination pattern.
248     pub dst_def: Option<DefIndex>,
249 
250     /// TypeVar representing the type of this variable.
251     type_var: Option<TypeVar>,
252 
253     /// Is this the original type variable, or has it be redefined with set_typevar?
254     is_original_type_var: bool,
255 }
256 
257 impl Var {
new(name: String) -> Self258     fn new(name: String) -> Self {
259         Self {
260             name,
261             src_def: None,
262             dst_def: None,
263             type_var: None,
264             is_original_type_var: false,
265         }
266     }
267 
268     /// Is this an input value to the src pattern?
is_input(&self) -> bool269     pub fn is_input(&self) -> bool {
270         self.src_def.is_none() && self.dst_def.is_none()
271     }
272 
273     /// Is this an output value, defined in both src and dst patterns?
is_output(&self) -> bool274     pub fn is_output(&self) -> bool {
275         self.src_def.is_some() && self.dst_def.is_some()
276     }
277 
278     /// Is this an intermediate value, defined only in the src pattern?
is_intermediate(&self) -> bool279     pub fn is_intermediate(&self) -> bool {
280         self.src_def.is_some() && self.dst_def.is_none()
281     }
282 
283     /// Is this a temp value, defined only in the dst pattern?
is_temp(&self) -> bool284     pub fn is_temp(&self) -> bool {
285         self.src_def.is_none() && self.dst_def.is_some()
286     }
287 
288     /// Get the def of this variable according to the position.
get_def(&self, position: PatternPosition) -> Option<DefIndex>289     pub fn get_def(&self, position: PatternPosition) -> Option<DefIndex> {
290         match position {
291             PatternPosition::Source => self.src_def,
292             PatternPosition::Destination => self.dst_def,
293         }
294     }
295 
set_def(&mut self, position: PatternPosition, def: DefIndex)296     pub fn set_def(&mut self, position: PatternPosition, def: DefIndex) {
297         assert!(
298             self.get_def(position).is_none(),
299             "redefinition of variable {}",
300             self.name
301         );
302         match position {
303             PatternPosition::Source => {
304                 self.src_def = Some(def);
305             }
306             PatternPosition::Destination => {
307                 self.dst_def = Some(def);
308             }
309         }
310     }
311 
312     /// Get the type variable representing the type of this variable.
get_or_create_typevar(&mut self) -> TypeVar313     pub fn get_or_create_typevar(&mut self) -> TypeVar {
314         match &self.type_var {
315             Some(tv) => tv.clone(),
316             None => {
317                 // Create a new type var in which we allow all types.
318                 let tv = TypeVar::new(
319                     format!("typeof_{}", self.name),
320                     format!("Type of the pattern variable {:?}", self),
321                     TypeSetBuilder::all(),
322                 );
323                 self.type_var = Some(tv.clone());
324                 self.is_original_type_var = true;
325                 tv
326             }
327         }
328     }
get_typevar(&self) -> Option<TypeVar>329     pub fn get_typevar(&self) -> Option<TypeVar> {
330         self.type_var.clone()
331     }
set_typevar(&mut self, tv: TypeVar)332     pub fn set_typevar(&mut self, tv: TypeVar) {
333         self.is_original_type_var = if let Some(previous_tv) = &self.type_var {
334             *previous_tv == tv
335         } else {
336             false
337         };
338         self.type_var = Some(tv);
339     }
340 
341     /// Check if this variable has a free type variable. If not, the type of this variable is
342     /// computed from the type of another variable.
has_free_typevar(&self) -> bool343     pub fn has_free_typevar(&self) -> bool {
344         match &self.type_var {
345             Some(tv) => tv.base.is_none() && self.is_original_type_var,
346             None => false,
347         }
348     }
349 
to_rust_code(&self) -> String350     pub fn to_rust_code(&self) -> String {
351         self.name.clone()
352     }
rust_type(&self) -> String353     fn rust_type(&self) -> String {
354         self.type_var.as_ref().unwrap().to_rust_code()
355     }
356 }
357 
358 impl fmt::Debug for Var {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>359     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
360         fmt.write_fmt(format_args!(
361             "Var({}{}{})",
362             self.name,
363             if self.src_def.is_some() { ", src" } else { "" },
364             if self.dst_def.is_some() { ", dst" } else { "" }
365         ))
366     }
367 }
368 
369 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
370 pub(crate) struct VarIndex(u32);
371 entity_impl!(VarIndex);
372 
373 pub(crate) struct VarPool {
374     pool: PrimaryMap<VarIndex, Var>,
375 }
376 
377 impl VarPool {
new() -> Self378     pub fn new() -> Self {
379         Self {
380             pool: PrimaryMap::new(),
381         }
382     }
get(&self, index: VarIndex) -> &Var383     pub fn get(&self, index: VarIndex) -> &Var {
384         self.pool.get(index).unwrap()
385     }
get_mut(&mut self, index: VarIndex) -> &mut Var386     pub fn get_mut(&mut self, index: VarIndex) -> &mut Var {
387         self.pool.get_mut(index).unwrap()
388     }
create(&mut self, name: impl Into<String>) -> VarIndex389     pub fn create(&mut self, name: impl Into<String>) -> VarIndex {
390         self.pool.push(Var::new(name.into()))
391     }
392 }
393 
394 /// Contains constants created in the AST that must be inserted into the true [ConstantPool] when
395 /// the legalizer code is generated. The constant data is named in the order it is inserted;
396 /// inserting data using [insert] will avoid duplicates.
397 ///
398 /// [ConstantPool]: ../../../cranelift_codegen/ir/constant/struct.ConstantPool.html
399 /// [insert]: ConstPool::insert
400 pub(crate) struct ConstPool {
401     pool: Vec<Vec<u8>>,
402 }
403 
404 impl ConstPool {
405     /// Create an empty constant pool.
new() -> Self406     pub fn new() -> Self {
407         Self { pool: vec![] }
408     }
409 
410     /// Create a name for a constant from its position in the pool.
create_name(position: usize) -> String411     fn create_name(position: usize) -> String {
412         format!("const{}", position)
413     }
414 
415     /// Insert constant data into the pool, returning the name of the variable used to reference it.
416     /// This method will search for data that matches the new data and return the existing constant
417     /// name to avoid duplicates.
insert(&mut self, data: Vec<u8>) -> String418     pub fn insert(&mut self, data: Vec<u8>) -> String {
419         let possible_position = self.pool.iter().position(|d| d == &data);
420         let position = if let Some(found_position) = possible_position {
421             found_position
422         } else {
423             let new_position = self.pool.len();
424             self.pool.push(data);
425             new_position
426         };
427         ConstPool::create_name(position)
428     }
429 
430     /// Iterate over the name/value pairs in the pool.
iter(&self) -> impl Iterator<Item = (String, &Vec<u8>)>431     pub fn iter(&self) -> impl Iterator<Item = (String, &Vec<u8>)> {
432         self.pool
433             .iter()
434             .enumerate()
435             .map(|(i, v)| (ConstPool::create_name(i), v))
436     }
437 }
438 
439 /// Apply an instruction to arguments.
440 ///
441 /// An `Apply` AST expression is created by using function call syntax on instructions. This
442 /// applies to both bound and unbound polymorphic instructions.
443 pub(crate) struct Apply {
444     pub inst: Instruction,
445     pub args: Vec<Expr>,
446     pub value_types: Vec<ValueType>,
447 }
448 
449 impl Apply {
new(target: InstSpec, args: Vec<Expr>) -> Self450     pub fn new(target: InstSpec, args: Vec<Expr>) -> Self {
451         let (inst, value_types) = match target {
452             InstSpec::Inst(inst) => (inst, Vec::new()),
453             InstSpec::Bound(bound_inst) => (bound_inst.inst, bound_inst.value_types),
454         };
455 
456         // Apply should only operate on concrete value types, not "any".
457         let value_types = value_types
458             .into_iter()
459             .map(|vt| vt.expect("shouldn't be Any"))
460             .collect();
461 
462         // Basic check on number of arguments.
463         assert!(
464             inst.operands_in.len() == args.len(),
465             "incorrect number of arguments in instruction {}",
466             inst.name
467         );
468 
469         // Check that the kinds of Literals arguments match the expected operand.
470         for &imm_index in &inst.imm_opnums {
471             let arg = &args[imm_index];
472             if let Some(literal) = arg.maybe_literal() {
473                 let op = &inst.operands_in[imm_index];
474                 match &op.kind.fields {
475                     OperandKindFields::ImmEnum(values) => {
476                         if let Literal::Enumerator { value, .. } = literal {
477                             assert!(
478                                 values.iter().any(|(_key, v)| v == value),
479                                 "Nonexistent enum value '{}' passed to field of kind '{}' -- \
480                                  did you use the right enum?",
481                                 value,
482                                 op.kind.rust_type
483                             );
484                         } else {
485                             panic!(
486                                 "Passed non-enum field value {:?} to field of kind {}",
487                                 literal, op.kind.rust_type
488                             );
489                         }
490                     }
491                     OperandKindFields::ImmValue => match &literal {
492                         Literal::Enumerator { value, .. } => panic!(
493                             "Expected immediate value in immediate field of kind '{}', \
494                              obtained enum value '{}'",
495                             op.kind.rust_type, value
496                         ),
497                         Literal::Bits { .. } | Literal::Int(_) | Literal::EmptyVarArgs => {}
498                     },
499                     _ => {
500                         panic!(
501                             "Literal passed to non-literal field of kind {}",
502                             op.kind.rust_type
503                         );
504                     }
505                 }
506             }
507         }
508 
509         Self {
510             inst,
511             args,
512             value_types,
513         }
514     }
515 
to_comment_string(&self, var_pool: &VarPool) -> String516     fn to_comment_string(&self, var_pool: &VarPool) -> String {
517         let args = self
518             .args
519             .iter()
520             .map(|arg| arg.to_rust_code(var_pool))
521             .collect::<Vec<_>>()
522             .join(", ");
523 
524         let mut inst_and_bound_types = vec![self.inst.name.to_string()];
525         inst_and_bound_types.extend(self.value_types.iter().map(|vt| vt.to_string()));
526         let inst_name = inst_and_bound_types.join(".");
527 
528         format!("{}({})", inst_name, args)
529     }
530 
inst_predicate(&self, var_pool: &VarPool) -> InstructionPredicate531     pub fn inst_predicate(&self, var_pool: &VarPool) -> InstructionPredicate {
532         let mut pred = InstructionPredicate::new();
533         for (format_field, &op_num) in self
534             .inst
535             .format
536             .imm_fields
537             .iter()
538             .zip(self.inst.imm_opnums.iter())
539         {
540             let arg = &self.args[op_num];
541             if arg.maybe_var().is_some() {
542                 // Ignore free variables for now.
543                 continue;
544             }
545             pred = pred.and(InstructionPredicate::new_is_field_equal_ast(
546                 &*self.inst.format,
547                 format_field,
548                 arg.to_rust_code(var_pool),
549             ));
550         }
551 
552         // Add checks for any bound secondary type variables.  We can't check the controlling type
553         // variable this way since it may not appear as the type of an operand.
554         if self.value_types.len() > 1 {
555             let poly = self
556                 .inst
557                 .polymorphic_info
558                 .as_ref()
559                 .expect("must have polymorphic info if it has bounded types");
560             for (bound_type, type_var) in
561                 self.value_types[1..].iter().zip(poly.other_typevars.iter())
562             {
563                 pred = pred.and(InstructionPredicate::new_typevar_check(
564                     &self.inst, type_var, bound_type,
565                 ));
566             }
567         }
568 
569         pred
570     }
571 
572     /// Same as `inst_predicate()`, but also check the controlling type variable.
inst_predicate_with_ctrl_typevar(&self, var_pool: &VarPool) -> InstructionPredicate573     pub fn inst_predicate_with_ctrl_typevar(&self, var_pool: &VarPool) -> InstructionPredicate {
574         let mut pred = self.inst_predicate(var_pool);
575 
576         if !self.value_types.is_empty() {
577             let bound_type = &self.value_types[0];
578             let poly = self.inst.polymorphic_info.as_ref().unwrap();
579             let type_check = if poly.use_typevar_operand {
580                 InstructionPredicate::new_typevar_check(&self.inst, &poly.ctrl_typevar, bound_type)
581             } else {
582                 InstructionPredicate::new_ctrl_typevar_check(&bound_type)
583             };
584             pred = pred.and(type_check);
585         }
586 
587         pred
588     }
589 
rust_builder(&self, defined_vars: &[VarIndex], var_pool: &VarPool) -> String590     pub fn rust_builder(&self, defined_vars: &[VarIndex], var_pool: &VarPool) -> String {
591         let mut args = self
592             .args
593             .iter()
594             .map(|expr| expr.to_rust_code(var_pool))
595             .collect::<Vec<_>>()
596             .join(", ");
597 
598         // Do we need to pass an explicit type argument?
599         if let Some(poly) = &self.inst.polymorphic_info {
600             if !poly.use_typevar_operand {
601                 args = format!("{}, {}", var_pool.get(defined_vars[0]).rust_type(), args);
602             }
603         }
604 
605         format!("{}({})", self.inst.snake_name(), args)
606     }
607 }
608 
609 // Simple helpers for legalize actions construction.
610 
611 pub(crate) enum DummyExpr {
612     Var(DummyVar),
613     Literal(Literal),
614     Constant(DummyConstant),
615     Apply(InstSpec, Vec<DummyExpr>),
616     Block(DummyVar),
617 }
618 
619 #[derive(Clone)]
620 pub(crate) struct DummyVar {
621     pub name: String,
622 }
623 
624 impl Into<DummyExpr> for DummyVar {
into(self) -> DummyExpr625     fn into(self) -> DummyExpr {
626         DummyExpr::Var(self)
627     }
628 }
629 impl Into<DummyExpr> for Literal {
into(self) -> DummyExpr630     fn into(self) -> DummyExpr {
631         DummyExpr::Literal(self)
632     }
633 }
634 
635 #[derive(Clone)]
636 pub(crate) struct DummyConstant(pub(crate) Vec<u8>);
637 
constant(data: Vec<u8>) -> DummyConstant638 pub(crate) fn constant(data: Vec<u8>) -> DummyConstant {
639     DummyConstant(data)
640 }
641 
642 impl Into<DummyExpr> for DummyConstant {
into(self) -> DummyExpr643     fn into(self) -> DummyExpr {
644         DummyExpr::Constant(self)
645     }
646 }
647 
var(name: &str) -> DummyVar648 pub(crate) fn var(name: &str) -> DummyVar {
649     DummyVar {
650         name: name.to_owned(),
651     }
652 }
653 
654 pub(crate) struct DummyDef {
655     pub expr: DummyExpr,
656     pub defined_vars: Vec<DummyVar>,
657 }
658 
659 pub(crate) struct ExprBuilder {
660     expr: DummyExpr,
661 }
662 
663 impl ExprBuilder {
apply(inst: InstSpec, args: Vec<DummyExpr>) -> Self664     pub fn apply(inst: InstSpec, args: Vec<DummyExpr>) -> Self {
665         let expr = DummyExpr::Apply(inst, args);
666         Self { expr }
667     }
668 
assign_to(self, defined_vars: Vec<DummyVar>) -> DummyDef669     pub fn assign_to(self, defined_vars: Vec<DummyVar>) -> DummyDef {
670         DummyDef {
671             expr: self.expr,
672             defined_vars,
673         }
674     }
675 
block(name: DummyVar) -> Self676     pub fn block(name: DummyVar) -> Self {
677         let expr = DummyExpr::Block(name);
678         Self { expr }
679     }
680 }
681 
682 macro_rules! def_rhs {
683     // inst(a, b, c)
684     ($inst:ident($($src:expr),*)) => {
685         ExprBuilder::apply($inst.into(), vec![$($src.clone().into()),*])
686     };
687 
688     // inst.type(a, b, c)
689     ($inst:ident.$type:ident($($src:expr),*)) => {
690         ExprBuilder::apply($inst.bind($type).into(), vec![$($src.clone().into()),*])
691     };
692 }
693 
694 // Helper macro to define legalization recipes.
695 macro_rules! def {
696     // x = ...
697     ($dest:ident = $($tt:tt)*) => {
698         def_rhs!($($tt)*).assign_to(vec![$dest.clone()])
699     };
700 
701     // (x, y, ...) = ...
702     (($($dest:ident),*) = $($tt:tt)*) => {
703         def_rhs!($($tt)*).assign_to(vec![$($dest.clone()),*])
704     };
705 
706     // An instruction with no results.
707     ($($tt:tt)*) => {
708         def_rhs!($($tt)*).assign_to(Vec::new())
709     }
710 }
711 
712 // Helper macro to define legalization recipes.
713 macro_rules! block {
714     // a basic block definition, splitting the current block in 2.
715     ($block: ident) => {
716         ExprBuilder::block($block).assign_to(Vec::new())
717     };
718 }
719 
720 #[cfg(test)]
721 mod tests {
722     use crate::cdsl::ast::ConstPool;
723 
724     #[test]
const_pool_returns_var_names()725     fn const_pool_returns_var_names() {
726         let mut c = ConstPool::new();
727         assert_eq!(c.insert([0, 1, 2].to_vec()), "const0");
728         assert_eq!(c.insert([1, 2, 3].to_vec()), "const1");
729     }
730 
731     #[test]
const_pool_avoids_duplicates()732     fn const_pool_avoids_duplicates() {
733         let data = [0, 1, 2].to_vec();
734         let mut c = ConstPool::new();
735         assert_eq!(c.pool.len(), 0);
736 
737         assert_eq!(c.insert(data.clone()), "const0");
738         assert_eq!(c.pool.len(), 1);
739 
740         assert_eq!(c.insert(data), "const0");
741         assert_eq!(c.pool.len(), 1);
742     }
743 
744     #[test]
const_pool_iterates()745     fn const_pool_iterates() {
746         let mut c = ConstPool::new();
747         c.insert([0, 1, 2].to_vec());
748         c.insert([3, 4, 5].to_vec());
749 
750         let mut iter = c.iter();
751         assert_eq!(iter.next(), Some(("const0".to_owned(), &vec![0, 1, 2])));
752         assert_eq!(iter.next(), Some(("const1".to_owned(), &vec![3, 4, 5])));
753         assert_eq!(iter.next(), None);
754     }
755 }
756