cranelift_codegen_meta/
gen_inst.rs

1//! Generate CLIF instruction data (including opcodes, formats, builders, etc.).
2
3use crate::cdsl::camel_case;
4use crate::cdsl::formats::InstructionFormat;
5use crate::cdsl::instructions::{AllInstructions, Instruction};
6use crate::cdsl::operands::{Operand, OperandKindFields};
7use crate::cdsl::typevar::{TypeSet, TypeVar};
8use crate::unique_table::{UniqueSeqTable, UniqueTable};
9use cranelift_codegen_shared::constant_hash;
10use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
11use std::fmt;
12use std::rc::Rc;
13
14// TypeSet indexes are encoded in 8 bits, with `0xff` reserved.
15const TYPESET_LIMIT: usize = 0xff;
16
17/// Generate an instruction format enumeration.
18fn 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.
63fn 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
105fn 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)`
167fn 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("std::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(("std::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
573fn 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
594fn 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.
783fn 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
811fn 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
825fn 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
834fn 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.
847pub(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.
878fn 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.
992fn 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.
1037fn 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.
1108fn 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.
1323fn 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
1362pub(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}