1 //! Generate CLIF instruction data (including opcodes, formats, builders, etc.).
2 
3 use crate::cdsl::camel_case;
4 use crate::cdsl::formats::InstructionFormat;
5 use crate::cdsl::instructions::{AllInstructions, Instruction};
6 use crate::cdsl::operands::{Operand, OperandKindFields};
7 use crate::cdsl::typevar::{TypeSet, TypeVar};
8 use crate::unique_table::{UniqueSeqTable, UniqueTable};
9 use cranelift_codegen_shared::constant_hash;
10 use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
11 use std::fmt;
12 use std::rc::Rc;
13 
14 // TypeSet indexes are encoded in 8 bits, with `0xff` reserved.
15 const TYPESET_LIMIT: usize = 0xff;
16 
17 /// Generate an instruction format enumeration.
gen_formats(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter)18 fn gen_formats(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter) {
19     fmt.doc_comment(
20         r#"
21         An instruction format
22 
23         Every opcode has a corresponding instruction format
24         which is represented by both the `InstructionFormat`
25         and the `InstructionData` enums.
26     "#,
27     );
28     fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug)]");
29     fmt.add_block("pub enum InstructionFormat", |fmt| {
30         for format in formats {
31             fmt.doc_comment(format.to_string());
32             fmtln!(fmt, "{},", format.name);
33         }
34     });
35     fmt.empty_line();
36 
37     // Emit a From<InstructionData> which also serves to verify that
38     // InstructionFormat and InstructionData are in sync.
39     fmt.add_block(
40         "impl<'a> From<&'a InstructionData> for InstructionFormat",
41         |fmt| {
42             fmt.add_block("fn from(inst: &'a InstructionData) -> Self", |fmt| {
43                 let mut m = Match::new("*inst");
44                 for format in formats {
45                     m.arm(
46                         format!("InstructionData::{}", format.name),
47                         vec![".."],
48                         format!("Self::{}", format.name),
49                     );
50                 }
51                 fmt.add_match(m);
52             });
53         },
54     );
55     fmt.empty_line();
56 }
57 
58 /// Generate the InstructionData enum.
59 ///
60 /// Every variant must contain an `opcode` field. The size of `InstructionData` should be kept at
61 /// 16 bytes on 64-bit architectures. If more space is needed to represent an instruction, use a
62 /// `ValueList` to store the additional information out of line.
gen_instruction_data(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter)63 fn gen_instruction_data(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter) {
64     fmt.line("#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]");
65     fmt.line(r#"#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]"#);
66     fmt.line("#[allow(missing_docs, reason = \"generated code\")]");
67     fmt.add_block("pub enum InstructionData", |fmt| {
68         for format in formats {
69             fmt.add_block(&format!("{}", format.name), |fmt| {
70                 fmt.line("opcode: Opcode,");
71                 if format.has_value_list {
72                     fmt.line("args: ValueList,");
73                 } else if format.num_value_operands == 1 {
74                     fmt.line("arg: Value,");
75                 } else if format.num_value_operands > 0 {
76                     fmtln!(fmt, "args: [Value; {}],", format.num_value_operands);
77                 }
78 
79                 match format.num_block_operands {
80                     0 => (),
81                     1 => fmt.line("destination: ir::BlockCall,"),
82                     2 => fmtln!(
83                         fmt,
84                         "blocks: [ir::BlockCall; {}],",
85                         format.num_block_operands
86                     ),
87                     n => panic!("Too many block operands in instruction: {n}"),
88                 }
89 
90                 match format.num_raw_block_operands {
91                     0 => (),
92                     1 => fmt.line("block: ir::Block,"),
93                     n => panic!("Too many block operands in instruction: {n}"),
94                 }
95 
96                 for field in &format.imm_fields {
97                     fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type);
98                 }
99             });
100             fmtln!(fmt, ",");
101         }
102     });
103 }
104 
gen_arguments_method(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter, is_mut: bool)105 fn gen_arguments_method(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter, is_mut: bool) {
106     let (method, mut_, rslice, as_slice) = if is_mut {
107         (
108             "arguments_mut",
109             "mut ",
110             "core::slice::from_mut",
111             "as_mut_slice",
112         )
113     } else {
114         ("arguments", "", "core::slice::from_ref", "as_slice")
115     };
116 
117     fmt.add_block(&format!(
118         "pub fn {method}<'a>(&'a {mut_}self, pool: &'a {mut_}ir::ValueListPool) -> &'a {mut_}[Value]"),
119 
120     |fmt| {
121         let mut m = Match::new("*self");
122         for format in formats {
123             let name = format!("Self::{}", format.name);
124 
125             // Formats with a value list put all of their arguments in the list. We don't split
126             // them up, just return it all as variable arguments. (I expect the distinction to go
127             // away).
128             if format.has_value_list {
129                 m.arm(
130                     name,
131                     vec![format!("ref {}args", mut_), "..".to_string()],
132                     format!("args.{as_slice}(pool)"),
133                 );
134                 continue;
135             }
136 
137             // Fixed args.
138             let mut fields = Vec::new();
139             let arg = if format.num_value_operands == 0 {
140                 format!("&{mut_}[]")
141             } else if format.num_value_operands == 1 {
142                 fields.push(format!("ref {mut_}arg"));
143                 format!("{rslice}(arg)")
144             } else {
145                 let arg = format!("args_arity{}", format.num_value_operands);
146                 fields.push(format!("args: ref {mut_}{arg}"));
147                 arg
148             };
149             fields.push("..".into());
150 
151             m.arm(name, fields, arg);
152         }
153         fmt.add_match(m);
154     });
155 }
156 
157 /// Generate the boring parts of the InstructionData implementation.
158 ///
159 /// These methods in `impl InstructionData` can be generated automatically from the instruction
160 /// formats:
161 ///
162 /// - `pub fn opcode(&self) -> Opcode`
163 /// - `pub fn arguments(&self, &pool) -> &[Value]`
164 /// - `pub fn arguments_mut(&mut self, &pool) -> &mut [Value]`
165 /// - `pub fn eq(&self, &other: Self, &pool) -> bool`
166 /// - `pub fn hash<H: Hasher>(&self, state: &mut H, &pool)`
gen_instruction_data_impl(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter)167 fn gen_instruction_data_impl(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter) {
168     fmt.add_block("impl InstructionData", |fmt| {
169         fmt.doc_comment("Get the opcode of this instruction.");
170         fmt.add_block("pub fn opcode(&self) -> Opcode",|fmt| {
171             let mut m = Match::new("*self");
172             for format in formats {
173                 m.arm(format!("Self::{}", format.name), vec!["opcode", ".."],
174                       "opcode".to_string());
175             }
176             fmt.add_match(m);
177         });
178                 fmt.empty_line();
179 
180         fmt.doc_comment("Get the controlling type variable operand.");
181         fmt.add_block("pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> Option<Value>",|fmt| {
182             let mut m = Match::new("*self");
183             for format in formats {
184                 let name = format!("Self::{}", format.name);
185                 if format.typevar_operand.is_none() {
186                     m.arm(name, vec![".."], "None".to_string());
187                 } else if format.has_value_list {
188                     // We keep all arguments in a value list.
189                     m.arm(name, vec!["ref args", ".."], format!("args.get({}, pool)", format.typevar_operand.unwrap()));
190                 } else if format.num_value_operands == 1 {
191                     m.arm(name, vec!["arg", ".."], "Some(arg)".to_string());
192                 } else {
193                     // We have multiple value operands and an array `args`.
194                     // Which `args` index to use?
195                     let args = format!("args_arity{}", format.num_value_operands);
196                     m.arm(name, vec![format!("args: ref {}", args), "..".to_string()],
197                         format!("Some({}[{}])", args, format.typevar_operand.unwrap()));
198                 }
199             }
200             fmt.add_match(m);
201         });
202                 fmt.empty_line();
203 
204         fmt.doc_comment("Get the value arguments to this instruction.");
205         gen_arguments_method(formats, fmt, false);
206         fmt.empty_line();
207 
208         fmt.doc_comment(r#"Get mutable references to the value arguments to this
209                         instruction."#);
210         gen_arguments_method(formats, fmt, true);
211         fmt.empty_line();
212 
213         fmt.doc_comment(r#"
214             Compare two `InstructionData` for equality.
215 
216             This operation requires a reference to a `ValueListPool` to
217             determine if the contents of any `ValueLists` are equal.
218 
219             This operation takes a closure that is allowed to map each
220             argument value to some other value before the instructions
221             are compared. This allows various forms of canonicalization.
222         "#);
223         fmt.add_block("pub fn eq(&self, other: &Self, pool: &ir::ValueListPool) -> bool", |fmt| {
224             fmt.add_block("if ::core::mem::discriminant(self) != ::core::mem::discriminant(other)", |fmt| {
225                 fmt.line("return false;");
226             });
227 
228             fmt.add_block("match (self, other)",|fmt| {
229                 for format in formats {
230                     let name = format!("&Self::{}", format.name);
231                     let mut members = vec!["opcode"];
232 
233                     let args_eq = if format.has_value_list {
234                         members.push("args");
235                         Some("args1.as_slice(pool).iter().zip(args2.as_slice(pool).iter()).all(|(a, b)| a == b)")
236                     } else if format.num_value_operands == 1 {
237                         members.push("arg");
238                         Some("arg1 == arg2")
239                     } else if format.num_value_operands > 0 {
240                         members.push("args");
241                         Some("args1.iter().zip(args2.iter()).all(|(a, b)| a == b)")
242                     } else {
243                         None
244                     };
245 
246                     let blocks_eq = match format.num_block_operands {
247                         0 => None,
248                         1 => {
249                             members.push("destination");
250                             Some("destination1 == destination2")
251                         },
252                         _ => {
253                             members.push("blocks");
254                             Some("blocks1.iter().zip(blocks2.iter()).all(|(a, b)| a.block(pool) == b.block(pool))")
255                         }
256                     };
257 
258                     let raw_blocks_eq = match format.num_raw_block_operands {
259                         0 => None,
260                         1 => {
261                             members.push("block");
262                             Some("block1 == block2")
263                         }
264                         _ => unreachable!("Not a valid format"),
265                     };
266 
267                     for field in &format.imm_fields {
268                         members.push(field.member);
269                     }
270 
271                     let pat1 = members.iter().map(|x| format!("{x}: ref {x}1")).collect::<Vec<_>>().join(", ");
272                     let pat2 = members.iter().map(|x| format!("{x}: ref {x}2")).collect::<Vec<_>>().join(", ");
273                     fmt.add_block(&format!("({name} {{ {pat1} }}, {name} {{ {pat2} }}) => "), |fmt| {
274                         fmt.line("opcode1 == opcode2");
275                         for field in &format.imm_fields {
276                             fmtln!(fmt, "&& {}1 == {}2", field.member, field.member);
277                         }
278                         if let Some(args_eq) = args_eq {
279                             fmtln!(fmt, "&& {}", args_eq);
280                         }
281                         if let Some(blocks_eq) = blocks_eq {
282                             fmtln!(fmt, "&& {}", blocks_eq);
283                         }
284                         if let Some(raw_blocks_eq) = raw_blocks_eq {
285                             fmtln!(fmt, "&& {}", raw_blocks_eq);
286                         }
287                     });
288                 }
289                 fmt.line("_ => unreachable!()");
290             });
291                     });
292                 fmt.empty_line();
293 
294         fmt.doc_comment(r#"
295             Hash an `InstructionData`.
296 
297             This operation requires a reference to a `ValueListPool` to
298             hash the contents of any `ValueLists`.
299 
300             This operation takes a closure that is allowed to map each
301             argument value to some other value before it is hashed. This
302             allows various forms of canonicalization.
303         "#);
304         fmt.add_block("pub fn hash<H: ::core::hash::Hasher>(&self, state: &mut H, pool: &ir::ValueListPool)",|fmt| {
305             fmt.add_block("match *self",|fmt| {
306                 for format in formats {
307                     let name = format!("Self::{}", format.name);
308                     let mut members = vec!["opcode"];
309 
310                     let (args, len) = if format.has_value_list {
311                         members.push("ref args");
312                         (Some("args.as_slice(pool)"), "args.len(pool)")
313                     } else if format.num_value_operands == 1 {
314                         members.push("ref arg");
315                         (Some("core::slice::from_ref(arg)"), "1")
316                     } else if format.num_value_operands > 0 {
317                         members.push("ref args");
318                         (Some("args"), "args.len()")
319                     } else {
320                         (None, "0")
321                     };
322 
323                     let blocks = match format.num_block_operands {
324                         0 => None,
325                         1 => {
326                             members.push("ref destination");
327                             Some(("core::slice::from_ref(destination)", "1"))
328                         }
329                         _ => {
330                             members.push("ref blocks");
331                             Some(("blocks", "blocks.len()"))
332                         }
333                     };
334 
335                     let raw_block = match format.num_raw_block_operands {
336                         0 => None,
337                         1 => {
338                             members.push("block");
339                             Some("block")
340                         }
341                         _ => panic!("Too many raw block operands"),
342                     };
343 
344                     for field in &format.imm_fields {
345                         members.push(field.member);
346                     }
347                     let members = members.join(", ");
348 
349                     fmt.add_block(&format!("{name}{{{members}}} => "), |fmt| {
350                         fmt.line("::core::hash::Hash::hash( &::core::mem::discriminant(self), state);");
351                         fmt.line("::core::hash::Hash::hash(&opcode, state);");
352                         for field in &format.imm_fields {
353                             fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", field.member);
354                         }
355                         fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", len);
356                         if let Some(args) = args {
357                             fmt.add_block(&format!("for &arg in {args}"), |fmt| {
358                                 fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);");
359                             });
360                         }
361 
362                         if let Some((blocks, len)) = blocks {
363                             fmtln!(fmt, "::core::hash::Hash::hash(&{len}, state);");
364                             fmt.add_block(&format!("for &block in {blocks}"), |fmt| {
365                                 fmtln!(fmt, "::core::hash::Hash::hash(&block.block(pool), state);");
366                                 fmt.add_block("for arg in block.args(pool)", |fmt| {
367                                     fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);");
368                                 });
369                             });
370                         }
371 
372                         if let Some(raw_block) = raw_block {
373                             fmtln!(fmt, "::core::hash::Hash::hash(&{raw_block}, state);");
374                         }
375                     });
376                 }
377             });
378                     });
379 
380                 fmt.empty_line();
381 
382         fmt.doc_comment(r#"
383             Deep-clone an `InstructionData`, including any referenced lists.
384 
385             This operation requires a reference to a `ValueListPool` to
386             clone the `ValueLists`.
387         "#);
388         fmt.add_block("pub fn deep_clone(&self, pool: &mut ir::ValueListPool) -> Self",|fmt| {
389             fmt.add_block("match *self",|fmt| {
390                 for format in formats {
391                     let name = format!("Self::{}", format.name);
392                     let mut members = vec!["opcode"];
393 
394                     if format.has_value_list {
395                         members.push("ref args");
396                     } else if format.num_value_operands == 1 {
397                         members.push("arg");
398                     } else if format.num_value_operands > 0 {
399                         members.push("args");
400                     }
401 
402                     match format.num_block_operands {
403                         0 => {}
404                         1 => {
405                             members.push("destination");
406                         }
407                         _ => {
408                             members.push("blocks");
409                         }
410                     };
411 
412                     match format.num_raw_block_operands {
413                         0 => {}
414                         1 => {
415                             members.push("block");
416                         }
417                         _ => panic!("Too many raw-block operands to format"),
418                     }
419 
420                     for field in &format.imm_fields {
421                         members.push(field.member);
422                     }
423                     let members = members.join(", ");
424 
425                     fmt.add_block(&format!("{name}{{{members}}} => "),|fmt| {
426                         fmt.add_block(&format!("Self::{}", format.name), |fmt| {
427                             fmtln!(fmt, "opcode,");
428 
429                             if format.has_value_list {
430                                 fmtln!(fmt, "args: args.deep_clone(pool),");
431                             } else if format.num_value_operands == 1 {
432                                 fmtln!(fmt, "arg,");
433                             } else if format.num_value_operands > 0 {
434                                 fmtln!(fmt, "args,");
435                             }
436 
437                             match format.num_block_operands {
438                                 0 => {}
439                                 1 => {
440                                     fmtln!(fmt, "destination: destination.deep_clone(pool),");
441                                 }
442                                 2 => {
443                                     fmtln!(fmt, "blocks: [blocks[0].deep_clone(pool), blocks[1].deep_clone(pool)],");
444                                 }
445                                 _ => panic!("Too many block targets in instruction"),
446                             }
447 
448                             match format.num_raw_block_operands {
449                                 0 => {}
450                                 1 => {
451                                     fmtln!(fmt, "block,");
452                                 }
453                                 _ => panic!("Too many raw-block operands in instruction"),
454                             }
455 
456                             for field in &format.imm_fields {
457                                 fmtln!(fmt, "{},", field.member);
458                             }
459                         });
460                     });
461                 }
462             });
463         });
464         fmt.doc_comment(r#"
465             Map some functions, described by the given `InstructionMapper`, over each of the
466             entities within this instruction, producing a new `InstructionData`.
467         "#);
468         fmt.add_block("pub fn map(&self, mut mapper: impl crate::ir::instructions::InstructionMapper) -> Self", |fmt| {
469             fmt.add_block("match *self",|fmt| {
470                 for format in formats {
471                     let name = format!("Self::{}", format.name);
472                     let mut members = vec!["opcode"];
473 
474                     if format.has_value_list {
475                         members.push("args");
476                     } else if format.num_value_operands == 1 {
477                         members.push("arg");
478                     } else if format.num_value_operands > 0 {
479                         members.push("args");
480                     }
481 
482                     match format.num_block_operands {
483                         0 => {}
484                         1 => {
485                             members.push("destination");
486                         }
487                         _ => {
488                             members.push("blocks");
489                         }
490                     };
491 
492                     match format.num_raw_block_operands {
493                         0 => {}
494                         1 => {
495                             members.push("block");
496                         }
497                         _ => panic!("Too many raw-block operands"),
498                     }
499 
500                     for field in &format.imm_fields {
501                         members.push(field.member);
502                     }
503                     let members = members.join(", ");
504 
505                     fmt.add_block(&format!("{name}{{{members}}} => "), |fmt| {
506                         fmt.add_block(&format!("Self::{}", format.name), |fmt| {
507                             fmtln!(fmt, "opcode,");
508 
509                             if format.has_value_list {
510                                 fmtln!(fmt, "args: mapper.map_value_list(args),");
511                             } else if format.num_value_operands == 1 {
512                                 fmtln!(fmt, "arg: mapper.map_value(arg),");
513                             } else if format.num_value_operands > 0 {
514                                 let maps = (0..format.num_value_operands)
515                                     .map(|i| format!("mapper.map_value(args[{i}])"))
516                                     .collect::<Box<[_]>>()
517                                     .join(", ");
518                                 fmtln!(fmt, "args: [{maps}],");
519                             }
520 
521                             match format.num_block_operands {
522                                 0 => {}
523                                 1 => {
524                                     fmtln!(fmt, "destination: mapper.map_block_call(destination),");
525                                 }
526                                 2 => {
527                                     fmtln!(fmt, "blocks: [mapper.map_block_call(blocks[0]), mapper.map_block_call(blocks[1])],");
528                                 }
529                                 _ => panic!("Too many block targets in instruction"),
530                             }
531 
532                             match format.num_raw_block_operands {
533                                 0 => {}
534                                 1 => {
535                                     fmtln!(fmt, "block: mapper.map_block(block),");
536                                 }
537                                 _ => panic!("Too many raw block arguments in instruction"),
538                             }
539 
540                             for field in &format.imm_fields {
541                                 let member = field.member;
542                                 match &field.kind.fields {
543                                     OperandKindFields::EntityRef => {
544                                         let mut kind = heck::ToSnakeCase::to_snake_case(
545                                             field
546                                                 .kind
547                                                 .rust_type
548                                                 .split("::")
549                                                 .last()
550                                                 .unwrap_or(field.kind.rust_type),
551                                         );
552                                         if kind == "block" {
553                                             kind.push_str("_call");
554                                         }
555                                         fmtln!(fmt, "{member}: mapper.map_{kind}({member}),");
556                                     }
557                                     OperandKindFields::VariableArgs => {
558                                         fmtln!(fmt, "{member}: mapper.map_value_list({member}),");
559                                     }
560                                     OperandKindFields::ImmValue |
561                                     OperandKindFields::ImmEnum(_) |
562                                     OperandKindFields::TypeVar(_) => fmtln!(fmt, "{member},"),
563                                 }
564                             }
565                         });
566                     });
567                 }
568             });
569         });
570     });
571 }
572 
gen_bool_accessor<T: Fn(&Instruction) -> bool>( all_inst: &AllInstructions, get_attr: T, name: &'static str, doc: &'static str, fmt: &mut Formatter, )573 fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
574     all_inst: &AllInstructions,
575     get_attr: T,
576     name: &'static str,
577     doc: &'static str,
578     fmt: &mut Formatter,
579 ) {
580     fmt.doc_comment(doc);
581     fmt.add_block(&format!("pub fn {name}(self) -> bool"), |fmt| {
582         let mut m = Match::new("self");
583         for inst in all_inst.iter() {
584             if get_attr(inst) {
585                 m.arm_no_fields(format!("Self::{}", inst.camel_name), "true");
586             }
587         }
588         m.arm_no_fields("_", "false");
589         fmt.add_match(m);
590     });
591     fmt.empty_line();
592 }
593 
gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter)594 fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
595     fmt.doc_comment(
596         r#"
597         An instruction opcode.
598 
599         All instructions from all supported ISAs are present.
600     "#,
601     );
602     fmt.line("#[repr(u8)]");
603     fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
604     fmt.line(
605         r#"#[cfg_attr(
606             feature = "enable-serde",
607             derive(serde_derive::Serialize, serde_derive::Deserialize)
608         )]"#,
609     );
610 
611     // We explicitly set the discriminant of the first variant to 1, which allows us to take
612     // advantage of the NonZero optimization, meaning that wrapping enums can use the 0
613     // discriminant instead of increasing the size of the whole type, and so the size of
614     // Option<Opcode> is the same as Opcode's.
615     fmt.add_block("pub enum Opcode", |fmt| {
616         let mut is_first_opcode = true;
617         for inst in all_inst.iter() {
618             fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name));
619 
620             // Document polymorphism.
621             if let Some(poly) = &inst.polymorphic_info {
622                 if poly.use_typevar_operand {
623                     let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()];
624                     fmt.doc_comment(format!(
625                         "Type inferred from `{}`.",
626                         inst.operands_in[op_num].name
627                     ));
628                 }
629             }
630 
631             // Enum variant itself.
632             if is_first_opcode {
633                 fmtln!(fmt, "{} = 1,", inst.camel_name);
634                 is_first_opcode = false;
635             } else {
636                 fmtln!(fmt, "{},", inst.camel_name)
637             }
638         }
639     });
640     fmt.empty_line();
641 
642     fmt.add_block("impl Opcode", |fmt| {
643         gen_bool_accessor(
644             all_inst,
645             |inst| inst.is_terminator,
646             "is_terminator",
647             "True for instructions that terminate the block",
648             fmt,
649         );
650         gen_bool_accessor(
651             all_inst,
652             |inst| inst.is_branch,
653             "is_branch",
654             "True for all branch or jump instructions.",
655             fmt,
656         );
657         gen_bool_accessor(
658             all_inst,
659             |inst| inst.is_call,
660             "is_call",
661             "Is this a call instruction?",
662             fmt,
663         );
664         gen_bool_accessor(
665             all_inst,
666             |inst| inst.is_return,
667             "is_return",
668             "Is this a return instruction?",
669             fmt,
670         );
671         gen_bool_accessor(
672             all_inst,
673             |inst| inst.can_load,
674             "can_load",
675             "Can this instruction read from memory?",
676             fmt,
677         );
678         gen_bool_accessor(
679             all_inst,
680             |inst| inst.can_store,
681             "can_store",
682             "Can this instruction write to memory?",
683             fmt,
684         );
685         gen_bool_accessor(
686             all_inst,
687             |inst| inst.can_trap,
688             "can_trap",
689             "Can this instruction cause a trap?",
690             fmt,
691         );
692         gen_bool_accessor(
693             all_inst,
694             |inst| inst.other_side_effects,
695             "other_side_effects",
696             "Does this instruction have other side effects besides can_* flags?",
697             fmt,
698         );
699         gen_bool_accessor(
700             all_inst,
701             |inst| inst.side_effects_idempotent,
702             "side_effects_idempotent",
703             "Despite having side effects, is this instruction okay to GVN?",
704             fmt,
705         );
706 
707         // Generate an opcode list, for iterating over all known opcodes.
708         fmt.doc_comment("All cranelift opcodes.");
709         fmt.add_block("pub fn all() -> &'static [Opcode]", |fmt| {
710             fmt.line("return &[");
711             for inst in all_inst {
712                 fmt.indent(|fmt| {
713                     fmtln!(fmt, "Opcode::{},", inst.camel_name);
714                 });
715             }
716             fmt.line("];");
717         });
718         fmt.empty_line();
719     });
720     fmt.empty_line();
721 
722     // Generate a private opcode_format table.
723     fmtln!(
724         fmt,
725         "const OPCODE_FORMAT: [InstructionFormat; {}] = [",
726         all_inst.len()
727     );
728     fmt.indent(|fmt| {
729         for inst in all_inst.iter() {
730             fmtln!(
731                 fmt,
732                 "InstructionFormat::{}, // {}",
733                 inst.format.name,
734                 inst.name
735             );
736         }
737     });
738     fmtln!(fmt, "];");
739     fmt.empty_line();
740 
741     // Generate a private opcode_name function.
742     fmt.add_block("fn opcode_name(opc: Opcode) -> &\'static str", |fmt| {
743         let mut m = Match::new("opc");
744         for inst in all_inst.iter() {
745             m.arm_no_fields(
746                 format!("Opcode::{}", inst.camel_name),
747                 format!("\"{}\"", inst.name),
748             );
749         }
750         fmt.add_match(m);
751     });
752     fmt.empty_line();
753 
754     // Generate an opcode hash table for looking up opcodes by name.
755     let hash_table =
756         crate::constant_hash::generate_table(all_inst.iter(), all_inst.len(), |inst| {
757             constant_hash::simple_hash(&inst.name)
758         });
759     fmtln!(
760         fmt,
761         "const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
762         hash_table.len()
763     );
764     fmt.indent(|fmt| {
765         for i in hash_table {
766             match i {
767                 Some(i) => fmtln!(fmt, "Some(Opcode::{}),", i.camel_name),
768                 None => fmtln!(fmt, "None,"),
769             }
770         }
771     });
772     fmtln!(fmt, "];");
773     fmt.empty_line();
774 }
775 
776 /// Get the value type constraint for an SSA value operand, where
777 /// `ctrl_typevar` is the controlling type variable.
778 ///
779 /// Each operand constraint is represented as a string, one of:
780 /// - `Concrete(vt)`, where `vt` is a value type name.
781 /// - `Free(idx)` where `idx` is an index into `type_sets`.
782 /// - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints.
get_constraint<'entries, 'table>( operand: &'entries Operand, ctrl_typevar: Option<&TypeVar>, type_sets: &'table mut UniqueTable<'entries, TypeSet>, ) -> String783 fn get_constraint<'entries, 'table>(
784     operand: &'entries Operand,
785     ctrl_typevar: Option<&TypeVar>,
786     type_sets: &'table mut UniqueTable<'entries, TypeSet>,
787 ) -> String {
788     assert!(operand.is_value());
789     let type_var = operand.type_var().unwrap();
790 
791     if let Some(typ) = type_var.singleton_type() {
792         return format!("Concrete({})", typ.rust_name());
793     }
794 
795     if let Some(free_typevar) = type_var.free_typevar() {
796         if ctrl_typevar.is_some() && free_typevar != *ctrl_typevar.unwrap() {
797             assert!(type_var.base.is_none());
798             return format!("Free({})", type_sets.add(type_var.get_raw_typeset()));
799         }
800     }
801 
802     if let Some(base) = &type_var.base {
803         assert!(base.type_var == *ctrl_typevar.unwrap());
804         return camel_case(base.derived_func.name());
805     }
806 
807     assert!(type_var == ctrl_typevar.unwrap());
808     "Same".into()
809 }
810 
gen_bitset<'a, T: IntoIterator<Item = &'a u16>>( iterable: T, name: &'static str, field_size: u8, fmt: &mut Formatter, )811 fn gen_bitset<'a, T: IntoIterator<Item = &'a u16>>(
812     iterable: T,
813     name: &'static str,
814     field_size: u8,
815     fmt: &mut Formatter,
816 ) {
817     let bits = iterable.into_iter().fold(0, |acc, x| {
818         assert!(x.is_power_of_two());
819         assert!(u32::from(*x) < (1 << u32::from(field_size)));
820         acc | x
821     });
822     fmtln!(fmt, "{}: ScalarBitSet::<u{}>({}),", name, field_size, bits);
823 }
824 
iterable_to_string<I: fmt::Display, T: IntoIterator<Item = I>>(iterable: T) -> String825 fn iterable_to_string<I: fmt::Display, T: IntoIterator<Item = I>>(iterable: T) -> String {
826     let elems = iterable
827         .into_iter()
828         .map(|x| x.to_string())
829         .collect::<Vec<_>>()
830         .join(", ");
831     format!("{{{elems}}}")
832 }
833 
typeset_to_string(ts: &TypeSet) -> String834 fn typeset_to_string(ts: &TypeSet) -> String {
835     let mut result = format!("TypeSet(lanes={}", iterable_to_string(&ts.lanes));
836     if !ts.ints.is_empty() {
837         result += &format!(", ints={}", iterable_to_string(&ts.ints));
838     }
839     if !ts.floats.is_empty() {
840         result += &format!(", floats={}", iterable_to_string(&ts.floats));
841     }
842     result += ")";
843     result
844 }
845 
846 /// Generate the table of ValueTypeSets described by type_sets.
gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter)847 pub(crate) fn gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter) {
848     if type_sets.len() == 0 {
849         return;
850     }
851 
852     fmt.comment("Table of value type sets.");
853     assert!(type_sets.len() <= TYPESET_LIMIT, "Too many type sets!");
854     fmtln!(
855         fmt,
856         "const TYPE_SETS: [ir::instructions::ValueTypeSet; {}] = [",
857         type_sets.len()
858     );
859     fmt.indent(|fmt| {
860         for ts in type_sets.iter() {
861             fmt.add_block("ir::instructions::ValueTypeSet", |fmt| {
862                 fmt.comment(typeset_to_string(ts));
863                 gen_bitset(&ts.lanes, "lanes", 16, fmt);
864                 gen_bitset(&ts.dynamic_lanes, "dynamic_lanes", 16, fmt);
865                 gen_bitset(&ts.ints, "ints", 8, fmt);
866                 gen_bitset(&ts.floats, "floats", 8, fmt);
867             });
868             fmt.line(",");
869         }
870     });
871     fmtln!(fmt, "];");
872 }
873 
874 /// Generate value type constraints for all instructions.
875 /// - Emit a compact constant table of ValueTypeSet objects.
876 /// - Emit a compact constant table of OperandConstraint objects.
877 /// - Emit an opcode-indexed table of instruction constraints.
gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter)878 fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) {
879     // Table of TypeSet instances.
880     let mut type_sets = UniqueTable::new();
881 
882     // Table of operand constraint sequences (as tuples). Each operand
883     // constraint is represented as a string, one of:
884     // - `Concrete(vt)`, where `vt` is a value type name.
885     // - `Free(idx)` where `idx` is an index into `type_sets`.
886     // - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints.
887     let mut operand_seqs = UniqueSeqTable::new();
888 
889     // Preload table with constraints for typical binops.
890     operand_seqs.add(&vec!["Same".to_string(); 3]);
891 
892     fmt.comment("Table of opcode constraints.");
893     fmtln!(
894         fmt,
895         "const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [",
896         all_inst.len()
897     );
898     fmt.indent(|fmt| {
899         for inst in all_inst.iter() {
900             let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
901                 let index = type_sets.add(poly.ctrl_typevar.get_raw_typeset());
902                 (Some(&poly.ctrl_typevar), index)
903             } else {
904                 (None, TYPESET_LIMIT)
905             };
906 
907             // Collect constraints for the value results, not including `variable_args` results
908             // which are always special cased.
909             let mut constraints = Vec::new();
910             for &index in &inst.value_results {
911                 constraints.push(get_constraint(&inst.operands_out[index], ctrl_typevar, &mut type_sets));
912             }
913             for &index in &inst.value_opnums {
914                 constraints.push(get_constraint(&inst.operands_in[index], ctrl_typevar, &mut type_sets));
915             }
916 
917             let constraint_offset = operand_seqs.add(&constraints);
918 
919             let fixed_results = inst.value_results.len();
920             let fixed_values = inst.value_opnums.len();
921 
922             // Can the controlling type variable be inferred from the designated operand?
923             let use_typevar_operand = if let Some(poly) = &inst.polymorphic_info {
924                 poly.use_typevar_operand
925             } else {
926                 false
927             };
928 
929             // Can the controlling type variable be inferred from the result?
930             let use_result = fixed_results > 0 && inst.operands_out[inst.value_results[0]].type_var() == ctrl_typevar;
931 
932             // Are we required to use the designated operand instead of the result?
933             let requires_typevar_operand = use_typevar_operand && !use_result;
934 
935             fmt.comment(
936                 format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}",
937                 inst.camel_name,
938                 fixed_results,
939                 use_typevar_operand,
940                 requires_typevar_operand,
941                 fixed_values)
942             );
943             fmt.comment(format!("Constraints=[{}]", constraints
944                 .iter()
945                 .map(|x| format!("'{x}'"))
946                 .collect::<Vec<_>>()
947                 .join(", ")));
948             if let Some(poly) = &inst.polymorphic_info {
949                 fmt.comment(format!("Polymorphic over {}", typeset_to_string(poly.ctrl_typevar.get_raw_typeset())));
950             }
951 
952             // Compute the bit field encoding, c.f. instructions.rs.
953             assert!(fixed_results < 8 && fixed_values < 8, "Bit field encoding too tight");
954             let mut flags = fixed_results; // 3 bits
955             if use_typevar_operand {
956                 flags |= 1<<3; // 4th bit
957             }
958             if requires_typevar_operand {
959                 flags |= 1<<4; // 5th bit
960             }
961             flags |= fixed_values << 5; // 6th bit and more
962 
963             fmt.add_block("OpcodeConstraints",|fmt| {
964                 fmtln!(fmt, "flags: {:#04x},", flags);
965                 fmtln!(fmt, "typeset_offset: {},", ctrl_typeset);
966                 fmtln!(fmt, "constraint_offset: {},", constraint_offset);
967             });
968             fmt.line(",");
969         }
970     });
971     fmtln!(fmt, "];");
972     fmt.empty_line();
973 
974     gen_typesets_table(&type_sets, fmt);
975     fmt.empty_line();
976 
977     fmt.comment("Table of operand constraint sequences.");
978     fmtln!(
979         fmt,
980         "const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [",
981         operand_seqs.len()
982     );
983     fmt.indent(|fmt| {
984         for constraint in operand_seqs.iter() {
985             fmtln!(fmt, "OperandConstraint::{},", constraint);
986         }
987     });
988     fmtln!(fmt, "];");
989 }
990 
991 /// Emit member initializers for an instruction format.
gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter)992 fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) {
993     // Immediate operands.
994     // We have local variables with the same names as the members.
995     for f in &format.imm_fields {
996         fmtln!(fmt, "{},", f.member);
997     }
998 
999     // Value operands.
1000     if format.has_value_list {
1001         fmt.line("args,");
1002     } else if format.num_value_operands == 1 {
1003         fmt.line("arg: arg0,");
1004     } else if format.num_value_operands > 1 {
1005         let mut args = Vec::new();
1006         for i in 0..format.num_value_operands {
1007             args.push(format!("arg{i}"));
1008         }
1009         fmtln!(fmt, "args: [{}],", args.join(", "));
1010     }
1011 
1012     // Block operands
1013     match format.num_block_operands {
1014         0 => (),
1015         1 => fmt.line("destination: block0"),
1016         n => {
1017             let mut blocks = Vec::new();
1018             for i in 0..n {
1019                 blocks.push(format!("block{i}"));
1020             }
1021             fmtln!(fmt, "blocks: [{}],", blocks.join(", "));
1022         }
1023     }
1024 
1025     // Raw block operands.
1026     match format.num_raw_block_operands {
1027         0 => (),
1028         1 => fmt.line("block: block0,"),
1029         _ => panic!("Too many raw block arguments"),
1030     }
1031 }
1032 
1033 /// Emit a method for creating and inserting an instruction format.
1034 ///
1035 /// All instruction formats take an `opcode` argument and a `ctrl_typevar` argument for deducing
1036 /// the result types.
gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter)1037 fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) {
1038     // Construct method arguments.
1039     let mut args = vec![
1040         "self".to_string(),
1041         "opcode: Opcode".into(),
1042         "ctrl_typevar: Type".into(),
1043     ];
1044 
1045     // Raw block operands.
1046     args.extend((0..format.num_raw_block_operands).map(|i| format!("block{i}: ir::Block")));
1047 
1048     // Normal operand arguments. Start with the immediate operands.
1049     for f in &format.imm_fields {
1050         args.push(format!("{}: {}", f.member, f.kind.rust_type));
1051     }
1052 
1053     // Then the block operands.
1054     args.extend((0..format.num_block_operands).map(|i| format!("block{i}: ir::BlockCall")));
1055 
1056     // Then the value operands.
1057     if format.has_value_list {
1058         // Take all value arguments as a finished value list. The value lists
1059         // are created by the individual instruction constructors.
1060         args.push("args: ir::ValueList".into());
1061     } else {
1062         // Take a fixed number of value operands.
1063         for i in 0..format.num_value_operands {
1064             args.push(format!("arg{i}: Value"));
1065         }
1066     }
1067 
1068     let proto = format!(
1069         "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)",
1070         format.name,
1071         args.join(", ")
1072     );
1073 
1074     let imms_need_masking = format
1075         .imm_fields
1076         .iter()
1077         .any(|f| f.kind.rust_type == "ir::immediates::Imm64");
1078 
1079     fmt.doc_comment(format.to_string());
1080     fmt.line("#[allow(non_snake_case, reason = \"generated code\")]");
1081     fmt.add_block(&format!("fn {proto}"), |fmt| {
1082         // Generate the instruction data.
1083         fmt.add_block(&format!(
1084                 "let{} data = ir::InstructionData::{}",
1085                 if imms_need_masking { " mut" } else { "" },
1086                 format.name
1087             ), |fmt| {
1088             fmt.line("opcode,");
1089             gen_member_inits(format, fmt);
1090         });
1091         fmtln!(fmt, ";");
1092 
1093         if imms_need_masking {
1094             fmtln!(fmt, "data.mask_immediates(ctrl_typevar);");
1095         }
1096 
1097         // Assert that this opcode belongs to this format
1098         fmtln!(fmt, "debug_assert_eq!(opcode.format(), InstructionFormat::from(&data), \"Wrong InstructionFormat for Opcode: {{opcode}}\");");
1099 
1100         fmt.line("self.build(data, ctrl_typevar)");
1101     });
1102 }
1103 
1104 /// Emit a method for generating the instruction `inst`.
1105 ///
1106 /// The method will create and insert an instruction, then return the result values, or the
1107 /// instruction reference itself for instructions that don't have results.
gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter)1108 fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter) {
1109     // Construct method arguments.
1110     let mut args = vec![String::new()];
1111 
1112     let mut args_doc = Vec::new();
1113     let mut rets_doc = Vec::new();
1114 
1115     // The controlling type variable will be inferred from the input values if
1116     // possible. Otherwise, it is the first method argument.
1117     if let Some(poly) = &inst.polymorphic_info {
1118         if !poly.use_typevar_operand {
1119             args.push(format!("{}: crate::ir::Type", poly.ctrl_typevar.name));
1120             args_doc.push(format!(
1121                 "- {} (controlling type variable): {}",
1122                 poly.ctrl_typevar.name, poly.ctrl_typevar.doc
1123             ));
1124         }
1125     }
1126 
1127     let mut tmpl_types = Vec::new();
1128     let mut into_args = Vec::new();
1129     let mut block_args = Vec::new();
1130     let mut lifetime_param = None;
1131     for op in &inst.operands_in {
1132         if op.kind.is_block() {
1133             args.push(format!("{}_label: {}", op.name, "ir::Block"));
1134             args_doc.push(format!(
1135                 "- {}_label: {}",
1136                 op.name, "Destination basic block"
1137             ));
1138 
1139             let lifetime = *lifetime_param.get_or_insert_with(|| {
1140                 tmpl_types.insert(0, "'a".to_string());
1141                 "'a"
1142             });
1143             args.push(format!(
1144                 "{}_args: impl IntoIterator<Item = &{} BlockArg>",
1145                 op.name, lifetime,
1146             ));
1147             args_doc.push(format!("- {}_args: {}", op.name, "Block arguments"));
1148 
1149             block_args.push(op);
1150         } else if op.kind.is_raw_block() {
1151             args.push("block: ir::Block".into());
1152             args_doc.push("- block: raw basic block".into());
1153         } else {
1154             let t = if op.is_immediate() {
1155                 let t = format!("T{}", tmpl_types.len() + 1);
1156                 tmpl_types.push(format!("{}: Into<{}>", t, op.kind.rust_type));
1157                 into_args.push(op.name);
1158                 t
1159             } else {
1160                 op.kind.rust_type.to_string()
1161             };
1162             args.push(format!("{}: {}", op.name, t));
1163             args_doc.push(format!("- {}: {}", op.name, op.doc()));
1164         }
1165     }
1166 
1167     // We need to mutate `self` if this instruction accepts a value list, or will construct
1168     // BlockCall values.
1169     if format.has_value_list || !block_args.is_empty() {
1170         args[0].push_str("mut self");
1171     } else {
1172         args[0].push_str("self");
1173     }
1174 
1175     for op in &inst.operands_out {
1176         rets_doc.push(format!("- {}: {}", op.name, op.doc()));
1177     }
1178 
1179     let rtype = match inst.value_results.len() {
1180         0 => "Inst".into(),
1181         1 => "Value".into(),
1182         _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")),
1183     };
1184 
1185     let tmpl = if !tmpl_types.is_empty() {
1186         format!("<{}>", tmpl_types.join(", "))
1187     } else {
1188         "".into()
1189     };
1190 
1191     let proto = format!(
1192         "{}{}({}) -> {}",
1193         inst.snake_name(),
1194         tmpl,
1195         args.join(", "),
1196         rtype
1197     );
1198 
1199     fmt.doc_comment(&inst.doc);
1200     if !args_doc.is_empty() {
1201         fmt.line("///");
1202         fmt.doc_comment("Inputs:");
1203         fmt.line("///");
1204         for doc_line in args_doc {
1205             fmt.doc_comment(doc_line);
1206         }
1207     }
1208     if !rets_doc.is_empty() {
1209         fmt.line("///");
1210         fmt.doc_comment("Outputs:");
1211         fmt.line("///");
1212         for doc_line in rets_doc {
1213             fmt.doc_comment(doc_line);
1214         }
1215     }
1216 
1217     fmt.line("#[allow(non_snake_case, reason = \"generated code\")]");
1218     fmt.add_block(&format!("fn {proto}"), |fmt| {
1219         // Convert all of the `Into<>` arguments.
1220         for arg in into_args {
1221             fmtln!(fmt, "let {} = {}.into();", arg, arg);
1222         }
1223 
1224         // Convert block references
1225         for op in block_args {
1226             fmtln!(
1227                 fmt,
1228                 "let {0} = self.data_flow_graph_mut().block_call({0}_label, {0}_args);",
1229                 op.name
1230             );
1231         }
1232 
1233         // Arguments for instruction constructor.
1234         let first_arg = format!("Opcode::{}", inst.camel_name);
1235         let mut args = vec![first_arg.as_str()];
1236         if let Some(poly) = &inst.polymorphic_info {
1237             if poly.use_typevar_operand {
1238                 // Infer the controlling type variable from the input operands.
1239                 let op_num = inst.value_opnums[format.typevar_operand.unwrap()];
1240                 fmtln!(
1241                     fmt,
1242                     "let ctrl_typevar = self.data_flow_graph().value_type({});",
1243                     inst.operands_in[op_num].name
1244                 );
1245 
1246                 // The format constructor will resolve the result types from the type var.
1247                 args.push("ctrl_typevar");
1248             } else {
1249                 // This was an explicit method argument.
1250                 args.push(&poly.ctrl_typevar.name);
1251             }
1252         } else {
1253             // No controlling type variable needed.
1254             args.push("types::INVALID");
1255         }
1256 
1257         // Now add all of the immediate operands to the constructor arguments.
1258         for &op_num in &inst.imm_opnums {
1259             args.push(inst.operands_in[op_num].name);
1260         }
1261 
1262         // Finally, the value operands.
1263         if format.has_value_list {
1264             // We need to build a value list with all the arguments.
1265             fmt.line("let mut vlist = ir::ValueList::default();");
1266             args.push("vlist");
1267             fmt.line("{");
1268             fmt.indent(|fmt| {
1269                 fmt.line("let pool = &mut self.data_flow_graph_mut().value_lists;");
1270                 for op in &inst.operands_in {
1271                     if op.is_value() {
1272                         fmtln!(fmt, "vlist.push({}, pool);", op.name);
1273                     } else if op.is_varargs() {
1274                         fmtln!(fmt, "vlist.extend({}.iter().cloned(), pool);", op.name);
1275                     }
1276                 }
1277             });
1278             fmt.line("}");
1279         } else {
1280             // With no value list, we're guaranteed to just have a set of fixed value operands.
1281             for &op_num in &inst.value_opnums {
1282                 args.push(inst.operands_in[op_num].name);
1283             }
1284         }
1285 
1286         // Call to the format constructor,
1287         let fcall = format!("self.{}({})", format.name, args.join(", "));
1288 
1289         fmtln!(fmt, "let (inst, dfg) = {};", fcall);
1290         fmtln!(
1291             fmt,
1292             "crate::trace!(\"inserted {{inst:?}}: {{}}\", dfg.display_inst(inst));"
1293         );
1294 
1295         if inst.value_results.is_empty() {
1296             fmtln!(fmt, "inst");
1297             return;
1298         }
1299 
1300         if inst.value_results.len() == 1 {
1301             fmt.line("dfg.first_result(inst)");
1302         } else {
1303             fmtln!(
1304                 fmt,
1305                 "let results = &dfg.inst_results(inst)[0..{}];",
1306                 inst.value_results.len()
1307             );
1308             fmtln!(
1309                 fmt,
1310                 "({})",
1311                 inst.value_results
1312                     .iter()
1313                     .enumerate()
1314                     .map(|(i, _)| format!("results[{i}]"))
1315                     .collect::<Vec<_>>()
1316                     .join(", ")
1317             );
1318         }
1319     });
1320 }
1321 
1322 /// Generate a Builder trait with methods for all instructions.
gen_builder( instructions: &AllInstructions, formats: &[Rc<InstructionFormat>], fmt: &mut Formatter, )1323 fn gen_builder(
1324     instructions: &AllInstructions,
1325     formats: &[Rc<InstructionFormat>],
1326     fmt: &mut Formatter,
1327 ) {
1328     fmt.doc_comment(
1329         r#"
1330         Convenience methods for building instructions.
1331 
1332         The `InstBuilder` trait has one method per instruction opcode for
1333         conveniently constructing the instruction with minimum arguments.
1334         Polymorphic instructions infer their result types from the input
1335         arguments when possible. In some cases, an explicit `ctrl_typevar`
1336         argument is required.
1337 
1338         The opcode methods return the new instruction's result values, or
1339         the `Inst` itself for instructions that don't have any results.
1340 
1341         There is also a method per instruction format. These methods all
1342         return an `Inst`.
1343 
1344         When an address to a load or store is specified, its integer
1345         size is required to be equal to the platform's pointer width.
1346     "#,
1347     );
1348     fmt.add_block("pub trait InstBuilder<'f>: InstBuilderBase<'f>", |fmt| {
1349         for inst in instructions.iter() {
1350             gen_inst_builder(inst, &inst.format, fmt);
1351             fmt.empty_line();
1352         }
1353         for (i, format) in formats.iter().enumerate() {
1354             gen_format_constructor(format, fmt);
1355             if i + 1 != formats.len() {
1356                 fmt.empty_line();
1357             }
1358         }
1359     });
1360 }
1361 
generate( formats: &[Rc<InstructionFormat>], all_inst: &AllInstructions, opcode_filename: &str, inst_builder_filename: &str, out_dir: &std::path::Path, ) -> Result<(), error::Error>1362 pub(crate) fn generate(
1363     formats: &[Rc<InstructionFormat>],
1364     all_inst: &AllInstructions,
1365     opcode_filename: &str,
1366     inst_builder_filename: &str,
1367     out_dir: &std::path::Path,
1368 ) -> Result<(), error::Error> {
1369     // Opcodes.
1370     let mut fmt = Formatter::new(Language::Rust);
1371     gen_formats(&formats, &mut fmt);
1372     gen_instruction_data(&formats, &mut fmt);
1373     fmt.empty_line();
1374     gen_instruction_data_impl(&formats, &mut fmt);
1375     fmt.empty_line();
1376     gen_opcodes(all_inst, &mut fmt);
1377     fmt.empty_line();
1378     gen_type_constraints(all_inst, &mut fmt);
1379     fmt.write(opcode_filename, out_dir)?;
1380 
1381     // Instruction builder.
1382     let mut fmt = Formatter::new(Language::Rust);
1383     gen_builder(all_inst, &formats, &mut fmt);
1384     fmt.write(inst_builder_filename, out_dir)?;
1385 
1386     Ok(())
1387 }
1388