Skip to main content

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("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                                        if field.kind.rust_type == "ir::MemFlags" =>
562                                    {
563                                        fmtln!(fmt, "{member}: mapper.map_mem_flags({member}),");
564                                    }
565                                    OperandKindFields::ImmValue |
566                                    OperandKindFields::ImmEnum(_) |
567                                    OperandKindFields::TypeVar(_) => fmtln!(fmt, "{member},"),
568                                }
569                            }
570                        });
571                    });
572                }
573            });
574        });
575    });
576}
577
578fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
579    all_inst: &AllInstructions,
580    get_attr: T,
581    name: &'static str,
582    doc: &'static str,
583    fmt: &mut Formatter,
584) {
585    fmt.doc_comment(doc);
586    fmt.add_block(&format!("pub fn {name}(self) -> bool"), |fmt| {
587        let mut m = Match::new("self");
588        for inst in all_inst.iter() {
589            if get_attr(inst) {
590                m.arm_no_fields(format!("Self::{}", inst.camel_name), "true");
591            }
592        }
593        m.arm_no_fields("_", "false");
594        fmt.add_match(m);
595    });
596    fmt.empty_line();
597}
598
599fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
600    fmt.doc_comment(
601        r#"
602        An instruction opcode.
603
604        All instructions from all supported ISAs are present.
605    "#,
606    );
607    fmt.line("#[repr(u8)]");
608    fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
609    fmt.line(
610        r#"#[cfg_attr(
611            feature = "enable-serde",
612            derive(serde_derive::Serialize, serde_derive::Deserialize)
613        )]"#,
614    );
615
616    // We explicitly set the discriminant of the first variant to 1, which allows us to take
617    // advantage of the NonZero optimization, meaning that wrapping enums can use the 0
618    // discriminant instead of increasing the size of the whole type, and so the size of
619    // Option<Opcode> is the same as Opcode's.
620    fmt.add_block("pub enum Opcode", |fmt| {
621        let mut is_first_opcode = true;
622        for inst in all_inst.iter() {
623            fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name));
624
625            // Document polymorphism.
626            if let Some(poly) = &inst.polymorphic_info {
627                if poly.use_typevar_operand {
628                    let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()];
629                    fmt.doc_comment(format!(
630                        "Type inferred from `{}`.",
631                        inst.operands_in[op_num].name
632                    ));
633                }
634            }
635
636            // Enum variant itself.
637            if is_first_opcode {
638                fmtln!(fmt, "{} = 1,", inst.camel_name);
639                is_first_opcode = false;
640            } else {
641                fmtln!(fmt, "{},", inst.camel_name)
642            }
643        }
644    });
645    fmt.empty_line();
646
647    fmt.add_block("impl Opcode", |fmt| {
648        gen_bool_accessor(
649            all_inst,
650            |inst| inst.is_terminator,
651            "is_terminator",
652            "True for instructions that terminate the block",
653            fmt,
654        );
655        gen_bool_accessor(
656            all_inst,
657            |inst| inst.is_branch,
658            "is_branch",
659            "True for all branch or jump instructions.",
660            fmt,
661        );
662        gen_bool_accessor(
663            all_inst,
664            |inst| inst.is_call,
665            "is_call",
666            "Is this a call instruction?",
667            fmt,
668        );
669        gen_bool_accessor(
670            all_inst,
671            |inst| inst.is_return,
672            "is_return",
673            "Is this a return instruction?",
674            fmt,
675        );
676        gen_bool_accessor(
677            all_inst,
678            |inst| inst.can_load,
679            "can_load",
680            "Can this instruction read from memory?",
681            fmt,
682        );
683        gen_bool_accessor(
684            all_inst,
685            |inst| inst.can_store,
686            "can_store",
687            "Can this instruction write to memory?",
688            fmt,
689        );
690        gen_bool_accessor(
691            all_inst,
692            |inst| inst.can_trap,
693            "can_trap",
694            "Can this instruction cause a trap?",
695            fmt,
696        );
697        gen_bool_accessor(
698            all_inst,
699            |inst| inst.other_side_effects,
700            "other_side_effects",
701            "Does this instruction have other side effects besides can_* flags?",
702            fmt,
703        );
704        gen_bool_accessor(
705            all_inst,
706            |inst| inst.side_effects_idempotent,
707            "side_effects_idempotent",
708            "Despite having side effects, is this instruction okay to GVN?",
709            fmt,
710        );
711
712        // Generate an opcode list, for iterating over all known opcodes.
713        fmt.doc_comment("All cranelift opcodes.");
714        fmt.add_block("pub fn all() -> &'static [Opcode]", |fmt| {
715            fmt.line("return &[");
716            for inst in all_inst {
717                fmt.indent(|fmt| {
718                    fmtln!(fmt, "Opcode::{},", inst.camel_name);
719                });
720            }
721            fmt.line("];");
722        });
723        fmt.empty_line();
724    });
725    fmt.empty_line();
726
727    // Generate a private opcode_format table.
728    fmtln!(
729        fmt,
730        "const OPCODE_FORMAT: [InstructionFormat; {}] = [",
731        all_inst.len()
732    );
733    fmt.indent(|fmt| {
734        for inst in all_inst.iter() {
735            fmtln!(
736                fmt,
737                "InstructionFormat::{}, // {}",
738                inst.format.name,
739                inst.name
740            );
741        }
742    });
743    fmtln!(fmt, "];");
744    fmt.empty_line();
745
746    // Generate a private opcode_name function.
747    fmt.add_block("fn opcode_name(opc: Opcode) -> &\'static str", |fmt| {
748        let mut m = Match::new("opc");
749        for inst in all_inst.iter() {
750            m.arm_no_fields(
751                format!("Opcode::{}", inst.camel_name),
752                format!("\"{}\"", inst.name),
753            );
754        }
755        fmt.add_match(m);
756    });
757    fmt.empty_line();
758
759    // Generate an opcode hash table for looking up opcodes by name.
760    let hash_table =
761        crate::constant_hash::generate_table(all_inst.iter(), all_inst.len(), |inst| {
762            constant_hash::simple_hash(&inst.name)
763        });
764    fmtln!(
765        fmt,
766        "const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
767        hash_table.len()
768    );
769    fmt.indent(|fmt| {
770        for i in hash_table {
771            match i {
772                Some(i) => fmtln!(fmt, "Some(Opcode::{}),", i.camel_name),
773                None => fmtln!(fmt, "None,"),
774            }
775        }
776    });
777    fmtln!(fmt, "];");
778    fmt.empty_line();
779}
780
781/// Get the value type constraint for an SSA value operand, where
782/// `ctrl_typevar` is the controlling type variable.
783///
784/// Each operand constraint is represented as a string, one of:
785/// - `Concrete(vt)`, where `vt` is a value type name.
786/// - `Free(idx)` where `idx` is an index into `type_sets`.
787/// - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints.
788fn get_constraint<'entries, 'table>(
789    operand: &'entries Operand,
790    ctrl_typevar: Option<&TypeVar>,
791    type_sets: &'table mut UniqueTable<'entries, TypeSet>,
792) -> String {
793    assert!(operand.is_value());
794    let type_var = operand.type_var().unwrap();
795
796    if let Some(typ) = type_var.singleton_type() {
797        return format!("Concrete({})", typ.rust_name());
798    }
799
800    if let Some(free_typevar) = type_var.free_typevar() {
801        if ctrl_typevar.is_some() && free_typevar != *ctrl_typevar.unwrap() {
802            assert!(type_var.base.is_none());
803            return format!("Free({})", type_sets.add(type_var.get_raw_typeset()));
804        }
805    }
806
807    if let Some(base) = &type_var.base {
808        assert!(base.type_var == *ctrl_typevar.unwrap());
809        return camel_case(base.derived_func.name());
810    }
811
812    assert!(type_var == ctrl_typevar.unwrap());
813    "Same".into()
814}
815
816fn gen_bitset<'a, T: IntoIterator<Item = &'a u16>>(
817    iterable: T,
818    name: &'static str,
819    field_size: u8,
820    fmt: &mut Formatter,
821) {
822    let bits = iterable.into_iter().fold(0, |acc, x| {
823        assert!(x.is_power_of_two());
824        assert!(u32::from(*x) < (1 << u32::from(field_size)));
825        acc | x
826    });
827    fmtln!(fmt, "{}: ScalarBitSet::<u{}>({}),", name, field_size, bits);
828}
829
830fn iterable_to_string<I: fmt::Display, T: IntoIterator<Item = I>>(iterable: T) -> String {
831    let elems = iterable
832        .into_iter()
833        .map(|x| x.to_string())
834        .collect::<Vec<_>>()
835        .join(", ");
836    format!("{{{elems}}}")
837}
838
839fn typeset_to_string(ts: &TypeSet) -> String {
840    let mut result = format!("TypeSet(lanes={}", iterable_to_string(&ts.lanes));
841    if !ts.ints.is_empty() {
842        result += &format!(", ints={}", iterable_to_string(&ts.ints));
843    }
844    if !ts.floats.is_empty() {
845        result += &format!(", floats={}", iterable_to_string(&ts.floats));
846    }
847    result += ")";
848    result
849}
850
851/// Generate the table of ValueTypeSets described by type_sets.
852pub(crate) fn gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter) {
853    if type_sets.len() == 0 {
854        return;
855    }
856
857    fmt.comment("Table of value type sets.");
858    assert!(type_sets.len() <= TYPESET_LIMIT, "Too many type sets!");
859    fmtln!(
860        fmt,
861        "const TYPE_SETS: [ir::instructions::ValueTypeSet; {}] = [",
862        type_sets.len()
863    );
864    fmt.indent(|fmt| {
865        for ts in type_sets.iter() {
866            fmt.add_block("ir::instructions::ValueTypeSet", |fmt| {
867                fmt.comment(typeset_to_string(ts));
868                gen_bitset(&ts.lanes, "lanes", 16, fmt);
869                gen_bitset(&ts.dynamic_lanes, "dynamic_lanes", 16, fmt);
870                gen_bitset(&ts.ints, "ints", 8, fmt);
871                gen_bitset(&ts.floats, "floats", 8, fmt);
872            });
873            fmt.line(",");
874        }
875    });
876    fmtln!(fmt, "];");
877}
878
879/// Generate value type constraints for all instructions.
880/// - Emit a compact constant table of ValueTypeSet objects.
881/// - Emit a compact constant table of OperandConstraint objects.
882/// - Emit an opcode-indexed table of instruction constraints.
883fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) {
884    // Table of TypeSet instances.
885    let mut type_sets = UniqueTable::new();
886
887    // Table of operand constraint sequences (as tuples). Each operand
888    // constraint is represented as a string, one of:
889    // - `Concrete(vt)`, where `vt` is a value type name.
890    // - `Free(idx)` where `idx` is an index into `type_sets`.
891    // - `Same`, `Lane`, `AsTruthy` for controlling typevar-derived constraints.
892    let mut operand_seqs = UniqueSeqTable::new();
893
894    // Preload table with constraints for typical binops.
895    operand_seqs.add(&vec!["Same".to_string(); 3]);
896
897    fmt.comment("Table of opcode constraints.");
898    fmtln!(
899        fmt,
900        "const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [",
901        all_inst.len()
902    );
903    fmt.indent(|fmt| {
904        for inst in all_inst.iter() {
905            let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
906                let index = type_sets.add(poly.ctrl_typevar.get_raw_typeset());
907                (Some(&poly.ctrl_typevar), index)
908            } else {
909                (None, TYPESET_LIMIT)
910            };
911
912            // Collect constraints for the value results, not including `variable_args` results
913            // which are always special cased.
914            let mut constraints = Vec::new();
915            for &index in &inst.value_results {
916                constraints.push(get_constraint(&inst.operands_out[index], ctrl_typevar, &mut type_sets));
917            }
918            for &index in &inst.value_opnums {
919                constraints.push(get_constraint(&inst.operands_in[index], ctrl_typevar, &mut type_sets));
920            }
921
922            let constraint_offset = operand_seqs.add(&constraints);
923
924            let fixed_results = inst.value_results.len();
925            let fixed_values = inst.value_opnums.len();
926
927            // Can the controlling type variable be inferred from the designated operand?
928            let use_typevar_operand = if let Some(poly) = &inst.polymorphic_info {
929                poly.use_typevar_operand
930            } else {
931                false
932            };
933
934            // Can the controlling type variable be inferred from the result?
935            let use_result = fixed_results > 0 && inst.operands_out[inst.value_results[0]].type_var() == ctrl_typevar;
936
937            // Are we required to use the designated operand instead of the result?
938            let requires_typevar_operand = use_typevar_operand && !use_result;
939
940            fmt.comment(
941                format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}",
942                inst.camel_name,
943                fixed_results,
944                use_typevar_operand,
945                requires_typevar_operand,
946                fixed_values)
947            );
948            fmt.comment(format!("Constraints=[{}]", constraints
949                .iter()
950                .map(|x| format!("'{x}'"))
951                .collect::<Vec<_>>()
952                .join(", ")));
953            if let Some(poly) = &inst.polymorphic_info {
954                fmt.comment(format!("Polymorphic over {}", typeset_to_string(poly.ctrl_typevar.get_raw_typeset())));
955            }
956
957            // Compute the bit field encoding, c.f. instructions.rs.
958            assert!(fixed_results < 8 && fixed_values < 8, "Bit field encoding too tight");
959            let mut flags = fixed_results; // 3 bits
960            if use_typevar_operand {
961                flags |= 1<<3; // 4th bit
962            }
963            if requires_typevar_operand {
964                flags |= 1<<4; // 5th bit
965            }
966            flags |= fixed_values << 5; // 6th bit and more
967
968            fmt.add_block("OpcodeConstraints",|fmt| {
969                fmtln!(fmt, "flags: {:#04x},", flags);
970                fmtln!(fmt, "typeset_offset: {},", ctrl_typeset);
971                fmtln!(fmt, "constraint_offset: {},", constraint_offset);
972            });
973            fmt.line(",");
974        }
975    });
976    fmtln!(fmt, "];");
977    fmt.empty_line();
978
979    gen_typesets_table(&type_sets, fmt);
980    fmt.empty_line();
981
982    fmt.comment("Table of operand constraint sequences.");
983    fmtln!(
984        fmt,
985        "const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [",
986        operand_seqs.len()
987    );
988    fmt.indent(|fmt| {
989        for constraint in operand_seqs.iter() {
990            fmtln!(fmt, "OperandConstraint::{},", constraint);
991        }
992    });
993    fmtln!(fmt, "];");
994}
995
996/// Emit member initializers for an instruction format.
997fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) {
998    // Immediate operands.
999    // We have local variables with the same names as the members.
1000    for f in &format.imm_fields {
1001        fmtln!(fmt, "{},", f.member);
1002    }
1003
1004    // Value operands.
1005    if format.has_value_list {
1006        fmt.line("args,");
1007    } else if format.num_value_operands == 1 {
1008        fmt.line("arg: arg0,");
1009    } else if format.num_value_operands > 1 {
1010        let mut args = Vec::new();
1011        for i in 0..format.num_value_operands {
1012            args.push(format!("arg{i}"));
1013        }
1014        fmtln!(fmt, "args: [{}],", args.join(", "));
1015    }
1016
1017    // Block operands
1018    match format.num_block_operands {
1019        0 => (),
1020        1 => fmt.line("destination: block0"),
1021        n => {
1022            let mut blocks = Vec::new();
1023            for i in 0..n {
1024                blocks.push(format!("block{i}"));
1025            }
1026            fmtln!(fmt, "blocks: [{}],", blocks.join(", "));
1027        }
1028    }
1029
1030    // Raw block operands.
1031    match format.num_raw_block_operands {
1032        0 => (),
1033        1 => fmt.line("block: block0,"),
1034        _ => panic!("Too many raw block arguments"),
1035    }
1036}
1037
1038/// Emit a method for creating and inserting an instruction format.
1039///
1040/// All instruction formats take an `opcode` argument and a `ctrl_typevar` argument for deducing
1041/// the result types.
1042fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) {
1043    // Construct method arguments.
1044    let mut args = vec![
1045        "self".to_string(),
1046        "opcode: Opcode".into(),
1047        "ctrl_typevar: Type".into(),
1048    ];
1049
1050    // Raw block operands.
1051    args.extend((0..format.num_raw_block_operands).map(|i| format!("block{i}: ir::Block")));
1052
1053    // Normal operand arguments. Start with the immediate operands.
1054    for f in &format.imm_fields {
1055        args.push(format!("{}: {}", f.member, f.kind.rust_type));
1056    }
1057
1058    // Then the block operands.
1059    args.extend((0..format.num_block_operands).map(|i| format!("block{i}: ir::BlockCall")));
1060
1061    // Then the value operands.
1062    if format.has_value_list {
1063        // Take all value arguments as a finished value list. The value lists
1064        // are created by the individual instruction constructors.
1065        args.push("args: ir::ValueList".into());
1066    } else {
1067        // Take a fixed number of value operands.
1068        for i in 0..format.num_value_operands {
1069            args.push(format!("arg{i}: Value"));
1070        }
1071    }
1072
1073    let proto = format!(
1074        "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)",
1075        format.name,
1076        args.join(", ")
1077    );
1078
1079    let imms_need_masking = format
1080        .imm_fields
1081        .iter()
1082        .any(|f| f.kind.rust_type == "ir::immediates::Imm64");
1083
1084    fmt.doc_comment(format.to_string());
1085    fmt.line("#[allow(non_snake_case, reason = \"generated code\")]");
1086    fmt.add_block(&format!("fn {proto}"), |fmt| {
1087        // Generate the instruction data.
1088        fmt.add_block(&format!(
1089                "let{} data = ir::InstructionData::{}",
1090                if imms_need_masking { " mut" } else { "" },
1091                format.name
1092            ), |fmt| {
1093            fmt.line("opcode,");
1094            gen_member_inits(format, fmt);
1095        });
1096        fmtln!(fmt, ";");
1097
1098        if imms_need_masking {
1099            fmtln!(fmt, "data.mask_immediates(ctrl_typevar);");
1100        }
1101
1102        // Assert that this opcode belongs to this format
1103        fmtln!(fmt, "debug_assert_eq!(opcode.format(), InstructionFormat::from(&data), \"Wrong InstructionFormat for Opcode: {{opcode}}\");");
1104
1105        fmt.line("self.build(data, ctrl_typevar)");
1106    });
1107}
1108
1109/// Emit a method for generating the instruction `inst`.
1110///
1111/// The method will create and insert an instruction, then return the result values, or the
1112/// instruction reference itself for instructions that don't have results.
1113fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter) {
1114    // Construct method arguments.
1115    let mut args = vec![String::new()];
1116
1117    let mut args_doc = Vec::new();
1118    let mut rets_doc = Vec::new();
1119
1120    // The controlling type variable will be inferred from the input values if
1121    // possible. Otherwise, it is the first method argument.
1122    if let Some(poly) = &inst.polymorphic_info {
1123        if !poly.use_typevar_operand {
1124            args.push(format!("{}: crate::ir::Type", poly.ctrl_typevar.name));
1125            args_doc.push(format!(
1126                "- {} (controlling type variable): {}",
1127                poly.ctrl_typevar.name, poly.ctrl_typevar.doc
1128            ));
1129        }
1130    }
1131
1132    let mut tmpl_types = Vec::new();
1133    let mut into_args = Vec::new();
1134    let mut block_args = Vec::new();
1135    let mut lifetime_param = None;
1136    for op in &inst.operands_in {
1137        if op.kind.is_block() {
1138            args.push(format!("{}_label: {}", op.name, "ir::Block"));
1139            args_doc.push(format!(
1140                "- {}_label: {}",
1141                op.name, "Destination basic block"
1142            ));
1143
1144            let lifetime = *lifetime_param.get_or_insert_with(|| {
1145                tmpl_types.insert(0, "'a".to_string());
1146                "'a"
1147            });
1148            args.push(format!(
1149                "{}_args: impl IntoIterator<Item = &{} BlockArg>",
1150                op.name, lifetime,
1151            ));
1152            args_doc.push(format!("- {}_args: {}", op.name, "Block arguments"));
1153
1154            block_args.push(op);
1155        } else if op.kind.is_raw_block() {
1156            args.push("block: ir::Block".into());
1157            args_doc.push("- block: raw basic block".into());
1158        } else {
1159            let t = if op.is_immediate() {
1160                let t = format!("T{}", tmpl_types.len() + 1);
1161                // For memflags, the public API type is MemFlagsData (the data),
1162                // while InstructionData stores MemFlags (the entity index).
1163                let api_type = if op.kind.rust_type == "ir::MemFlags" {
1164                    "ir::MemFlagsData"
1165                } else {
1166                    op.kind.rust_type
1167                };
1168                tmpl_types.push(format!("{t}: Into<{api_type}>"));
1169                into_args.push(op.name);
1170                t
1171            } else {
1172                op.kind.rust_type.to_string()
1173            };
1174            args.push(format!("{}: {}", op.name, t));
1175            args_doc.push(format!("- {}: {}", op.name, op.doc()));
1176        }
1177    }
1178
1179    // We need to mutate `self` if this instruction accepts a value list, will construct
1180    // BlockCall values, or has memflags operands (which need DFG insertion).
1181    let has_memflags = inst
1182        .operands_in
1183        .iter()
1184        .any(|op| op.kind.rust_type == "ir::MemFlags");
1185    if format.has_value_list || !block_args.is_empty() || has_memflags {
1186        args[0].push_str("mut self");
1187    } else {
1188        args[0].push_str("self");
1189    }
1190
1191    for op in &inst.operands_out {
1192        rets_doc.push(format!("- {}: {}", op.name, op.doc()));
1193    }
1194
1195    let rtype = match inst.value_results.len() {
1196        0 => "Inst".into(),
1197        1 => "Value".into(),
1198        _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")),
1199    };
1200
1201    let tmpl = if !tmpl_types.is_empty() {
1202        format!("<{}>", tmpl_types.join(", "))
1203    } else {
1204        "".into()
1205    };
1206
1207    let proto = format!(
1208        "{}{}({}) -> {}",
1209        inst.snake_name(),
1210        tmpl,
1211        args.join(", "),
1212        rtype
1213    );
1214
1215    fmt.doc_comment(&inst.doc);
1216    if !args_doc.is_empty() {
1217        fmt.line("///");
1218        fmt.doc_comment("Inputs:");
1219        fmt.line("///");
1220        for doc_line in args_doc {
1221            fmt.doc_comment(doc_line);
1222        }
1223    }
1224    if !rets_doc.is_empty() {
1225        fmt.line("///");
1226        fmt.doc_comment("Outputs:");
1227        fmt.line("///");
1228        for doc_line in rets_doc {
1229            fmt.doc_comment(doc_line);
1230        }
1231    }
1232
1233    fmt.line("#[allow(non_snake_case, reason = \"generated code\")]");
1234    fmt.add_block(&format!("fn {proto}"), |fmt| {
1235        // Convert all of the `Into<>` arguments.
1236        for arg in into_args {
1237            fmtln!(fmt, "let {} = {}.into();", arg, arg);
1238        }
1239
1240        // Insert memflags data into the DFG to get entity indices.
1241        for op in &inst.operands_in {
1242            if op.kind.rust_type == "ir::MemFlags" && op.is_immediate() {
1243                fmtln!(
1244                    fmt,
1245                    "let {0} = self.data_flow_graph_mut().mem_flags.insert({0}).unwrap();",
1246                    op.name
1247                );
1248            }
1249        }
1250
1251        // Convert block references
1252        for op in block_args {
1253            fmtln!(
1254                fmt,
1255                "let {0} = self.data_flow_graph_mut().block_call({0}_label, {0}_args);",
1256                op.name
1257            );
1258        }
1259
1260        // Arguments for instruction constructor.
1261        let first_arg = format!("Opcode::{}", inst.camel_name);
1262        let mut args = vec![first_arg.as_str()];
1263        if let Some(poly) = &inst.polymorphic_info {
1264            if poly.use_typevar_operand {
1265                // Infer the controlling type variable from the input operands.
1266                let op_num = inst.value_opnums[format.typevar_operand.unwrap()];
1267                fmtln!(
1268                    fmt,
1269                    "let ctrl_typevar = self.data_flow_graph().value_type({});",
1270                    inst.operands_in[op_num].name
1271                );
1272
1273                // The format constructor will resolve the result types from the type var.
1274                args.push("ctrl_typevar");
1275            } else {
1276                // This was an explicit method argument.
1277                args.push(&poly.ctrl_typevar.name);
1278            }
1279        } else {
1280            // No controlling type variable needed.
1281            args.push("types::INVALID");
1282        }
1283
1284        // Now add all of the immediate operands to the constructor arguments.
1285        for &op_num in &inst.imm_opnums {
1286            args.push(inst.operands_in[op_num].name);
1287        }
1288
1289        // Finally, the value operands.
1290        if format.has_value_list {
1291            // We need to build a value list with all the arguments.
1292            fmt.line("let mut vlist = ir::ValueList::default();");
1293            args.push("vlist");
1294            fmt.line("{");
1295            fmt.indent(|fmt| {
1296                fmt.line("let pool = &mut self.data_flow_graph_mut().value_lists;");
1297                for op in &inst.operands_in {
1298                    if op.is_value() {
1299                        fmtln!(fmt, "vlist.push({}, pool);", op.name);
1300                    } else if op.is_varargs() {
1301                        fmtln!(fmt, "vlist.extend({}.iter().cloned(), pool);", op.name);
1302                    }
1303                }
1304            });
1305            fmt.line("}");
1306        } else {
1307            // With no value list, we're guaranteed to just have a set of fixed value operands.
1308            for &op_num in &inst.value_opnums {
1309                args.push(inst.operands_in[op_num].name);
1310            }
1311        }
1312
1313        // Call to the format constructor,
1314        let fcall = format!("self.{}({})", format.name, args.join(", "));
1315
1316        fmtln!(fmt, "let (inst, dfg) = {};", fcall);
1317        fmtln!(
1318            fmt,
1319            "crate::trace!(\"inserted {{inst:?}}: {{}}\", dfg.display_inst(inst));"
1320        );
1321
1322        if inst.value_results.is_empty() {
1323            fmtln!(fmt, "inst");
1324            return;
1325        }
1326
1327        if inst.value_results.len() == 1 {
1328            fmt.line("dfg.first_result(inst)");
1329        } else {
1330            fmtln!(
1331                fmt,
1332                "let results = &dfg.inst_results(inst)[0..{}];",
1333                inst.value_results.len()
1334            );
1335            fmtln!(
1336                fmt,
1337                "({})",
1338                inst.value_results
1339                    .iter()
1340                    .enumerate()
1341                    .map(|(i, _)| format!("results[{i}]"))
1342                    .collect::<Vec<_>>()
1343                    .join(", ")
1344            );
1345        }
1346    });
1347}
1348
1349/// Generate a Builder trait with methods for all instructions.
1350fn gen_builder(
1351    instructions: &AllInstructions,
1352    formats: &[Rc<InstructionFormat>],
1353    fmt: &mut Formatter,
1354) {
1355    fmt.doc_comment(
1356        r#"
1357        Convenience methods for building instructions.
1358
1359        The `InstBuilder` trait has one method per instruction opcode for
1360        conveniently constructing the instruction with minimum arguments.
1361        Polymorphic instructions infer their result types from the input
1362        arguments when possible. In some cases, an explicit `ctrl_typevar`
1363        argument is required.
1364
1365        The opcode methods return the new instruction's result values, or
1366        the `Inst` itself for instructions that don't have any results.
1367
1368        There is also a method per instruction format. These methods all
1369        return an `Inst`.
1370
1371        When an address to a load or store is specified, its integer
1372        size is required to be equal to the platform's pointer width.
1373    "#,
1374    );
1375    fmt.add_block("pub trait InstBuilder<'f>: InstBuilderBase<'f>", |fmt| {
1376        for inst in instructions.iter() {
1377            gen_inst_builder(inst, &inst.format, fmt);
1378            fmt.empty_line();
1379        }
1380        for (i, format) in formats.iter().enumerate() {
1381            gen_format_constructor(format, fmt);
1382            if i + 1 != formats.len() {
1383                fmt.empty_line();
1384            }
1385        }
1386    });
1387}
1388
1389pub(crate) fn generate(
1390    formats: &[Rc<InstructionFormat>],
1391    all_inst: &AllInstructions,
1392    opcode_filename: &str,
1393    inst_builder_filename: &str,
1394    out_dir: &std::path::Path,
1395) -> Result<(), error::Error> {
1396    // Opcodes.
1397    let mut fmt = Formatter::new(Language::Rust);
1398    gen_formats(&formats, &mut fmt);
1399    gen_instruction_data(&formats, &mut fmt);
1400    fmt.empty_line();
1401    gen_instruction_data_impl(&formats, &mut fmt);
1402    fmt.empty_line();
1403    gen_opcodes(all_inst, &mut fmt);
1404    fmt.empty_line();
1405    gen_type_constraints(all_inst, &mut fmt);
1406    fmt.write(opcode_filename, out_dir)?;
1407
1408    // Instruction builder.
1409    let mut fmt = Formatter::new(Language::Rust);
1410    gen_builder(all_inst, &formats, &mut fmt);
1411    fmt.write(inst_builder_filename, out_dir)?;
1412
1413    Ok(())
1414}