1use std::fmt;
3
4use cranelift_codegen_shared::constant_hash;
5use cranelift_entity::EntityRef;
6
7use crate::cdsl::camel_case;
8use crate::cdsl::formats::InstructionFormat;
9use crate::cdsl::instructions::{AllInstructions, Instruction};
10use crate::cdsl::operands::Operand;
11use crate::cdsl::typevar::{TypeSet, TypeVar};
12
13use crate::error;
14use crate::srcgen::{Formatter, Match};
15use crate::unique_table::{UniqueSeqTable, UniqueTable};
16
17const TYPESET_LIMIT: usize = 0xff;
19
20fn gen_formats(formats: &[&InstructionFormat], fmt: &mut Formatter) {
22    fmt.doc_comment(
23        r#"
24        An instruction format
25
26        Every opcode has a corresponding instruction format
27        which is represented by both the `InstructionFormat`
28        and the `InstructionData` enums.
29    "#,
30    );
31    fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug)]");
32    fmt.line("pub enum InstructionFormat {");
33    fmt.indent(|fmt| {
34        for format in formats {
35            fmt.doc_comment(format.to_string());
36            fmtln!(fmt, "{},", format.name);
37        }
38    });
39    fmt.line("}");
40    fmt.empty_line();
41
42    fmt.line("impl<'a> From<&'a InstructionData> for InstructionFormat {");
45    fmt.indent(|fmt| {
46        fmt.line("fn from(inst: &'a InstructionData) -> Self {");
47        fmt.indent(|fmt| {
48            let mut m = Match::new("*inst");
49            for format in formats {
50                m.arm(
51                    format!("InstructionData::{}", format.name),
52                    vec![".."],
53                    format!("Self::{}", format.name),
54                );
55            }
56            fmt.add_match(m);
57        });
58        fmt.line("}");
59    });
60    fmt.line("}");
61    fmt.empty_line();
62}
63
64fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) {
70    fmt.line("#[derive(Clone, Debug)]");
71    fmt.line("#[allow(missing_docs)]");
72    fmt.line("pub enum InstructionData {");
73    fmt.indent(|fmt| {
74        for format in formats {
75            fmtln!(fmt, "{} {{", format.name);
76            fmt.indent(|fmt| {
77                fmt.line("opcode: Opcode,");
78                if format.typevar_operand.is_some() {
79                    if format.has_value_list {
80                        fmt.line("args: ValueList,");
81                    } else if format.num_value_operands == 1 {
82                        fmt.line("arg: Value,");
83                    } else {
84                        fmtln!(fmt, "args: [Value; {}],", format.num_value_operands);
85                    }
86                }
87                for field in &format.imm_fields {
88                    fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type);
89                }
90            });
91            fmtln!(fmt, "},");
92        }
93    });
94    fmt.line("}");
95}
96
97fn gen_arguments_method(formats: &[&InstructionFormat], fmt: &mut Formatter, is_mut: bool) {
98    let (method, mut_, rslice, as_slice) = if is_mut {
99        (
100            "arguments_mut",
101            "mut ",
102            "core::slice::from_mut",
103            "as_mut_slice",
104        )
105    } else {
106        ("arguments", "", "core::slice::from_ref", "as_slice")
107    };
108
109    fmtln!(
110        fmt,
111        "pub fn {}<'a>(&'a {}self, pool: &'a {}ir::ValueListPool) -> &{}[Value] {{",
112        method,
113        mut_,
114        mut_,
115        mut_
116    );
117    fmt.indent(|fmt| {
118        let mut m = Match::new("*self");
119        for format in formats {
120            let name = format!("Self::{}", format.name);
121
122            if format.has_value_list {
126                m.arm(
127                    name,
128                    vec![format!("ref {}args", mut_), "..".to_string()],
129                    format!("args.{}(pool)", as_slice),
130                );
131                continue;
132            }
133
134            let mut fields = Vec::new();
136            let arg = if format.num_value_operands == 0 {
137                format!("&{}[]", mut_)
138            } else if format.num_value_operands == 1 {
139                fields.push(format!("ref {}arg", mut_));
140                format!("{}(arg)", rslice)
141            } else {
142                let arg = format!("args_arity{}", format.num_value_operands);
143                fields.push(format!("args: ref {}{}", mut_, arg));
144                arg
145            };
146            fields.push("..".into());
147
148            m.arm(name, fields, arg);
149        }
150        fmt.add_match(m);
151    });
152    fmtln!(fmt, "}");
153}
154
155fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter) {
168    fmt.line("impl InstructionData {");
169    fmt.indent(|fmt| {
170        fmt.doc_comment("Get the opcode of this instruction.");
171        fmt.line("pub fn opcode(&self) -> Opcode {");
172        fmt.indent(|fmt| {
173            let mut m = Match::new("*self");
174            for format in formats {
175                m.arm(format!("Self::{}", format.name), vec!["opcode", ".."],
176                      "opcode".to_string());
177            }
178            fmt.add_match(m);
179        });
180        fmt.line("}");
181        fmt.empty_line();
182
183        fmt.doc_comment("Get the controlling type variable operand.");
184        fmt.line("pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> Option<Value> {");
185        fmt.indent(|fmt| {
186            let mut m = Match::new("*self");
187            for format in formats {
188                let name = format!("Self::{}", format.name);
189                if format.typevar_operand.is_none() {
190                    m.arm(name, vec![".."], "None".to_string());
191                } else if format.has_value_list {
192                    m.arm(name, vec!["ref args", ".."], format!("args.get({}, pool)", format.typevar_operand.unwrap()));
194                } else if format.num_value_operands == 1 {
195                    m.arm(name, vec!["arg", ".."], "Some(arg)".to_string());
196                } else {
197                    let args = format!("args_arity{}", format.num_value_operands);
200                    m.arm(name, vec![format!("args: ref {}", args), "..".to_string()],
201                        format!("Some({}[{}])", args, format.typevar_operand.unwrap()));
202                }
203            }
204            fmt.add_match(m);
205        });
206        fmt.line("}");
207        fmt.empty_line();
208
209        fmt.doc_comment("Get the value arguments to this instruction.");
210        gen_arguments_method(formats, fmt, false);
211        fmt.empty_line();
212
213        fmt.doc_comment(r#"Get mutable references to the value arguments to this
214                        instruction."#);
215        gen_arguments_method(formats, fmt, true);
216        fmt.empty_line();
217
218        fmt.doc_comment(r#"
219            Take out the value list with all the value arguments and return
220            it.
221
222            This leaves the value list in the instruction empty. Use
223            `put_value_list` to put the value list back.
224        "#);
225        fmt.line("pub fn take_value_list(&mut self) -> Option<ir::ValueList> {");
226        fmt.indent(|fmt| {
227            let mut m = Match::new("*self");
228
229            for format in formats {
230                if format.has_value_list {
231                    m.arm(format!("Self::{}", format.name),
232                    vec!["ref mut args", ".."],
233                    "Some(args.take())".to_string());
234                }
235            }
236
237            m.arm_no_fields("_", "None");
238
239            fmt.add_match(m);
240        });
241        fmt.line("}");
242        fmt.empty_line();
243
244        fmt.doc_comment(r#"
245            Put back a value list.
246
247            After removing a value list with `take_value_list()`, use this
248            method to put it back. It is required that this instruction has
249            a format that accepts a value list, and that the existing value
250            list is empty. This avoids leaking list pool memory.
251        "#);
252        fmt.line("pub fn put_value_list(&mut self, vlist: ir::ValueList) {");
253        fmt.indent(|fmt| {
254            fmt.line("let args = match *self {");
255            fmt.indent(|fmt| {
256                for format in formats {
257                    if format.has_value_list {
258                        fmtln!(fmt, "Self::{} {{ ref mut args, .. }} => args,", format.name);
259                    }
260                }
261                fmt.line("_ => panic!(\"No value list: {:?}\", self),");
262            });
263            fmt.line("};");
264            fmt.line("debug_assert!(args.is_empty(), \"Value list already in use\");");
265            fmt.line("*args = vlist;");
266        });
267        fmt.line("}");
268        fmt.empty_line();
269
270        fmt.doc_comment(r#"
271            Compare two `InstructionData` for equality.
272
273            This operation requires a reference to a `ValueListPool` to
274            determine if the contents of any `ValueLists` are equal.
275        "#);
276        fmt.line("pub fn eq(&self, other: &Self, pool: &ir::ValueListPool) -> bool {");
277        fmt.indent(|fmt| {
278            fmt.line("if ::core::mem::discriminant(self) != ::core::mem::discriminant(other) {");
279            fmt.indent(|fmt| {
280                fmt.line("return false;");
281            });
282            fmt.line("}");
283
284            fmt.line("match (self, other) {");
285            fmt.indent(|fmt| {
286                for format in formats {
287                    let name = format!("&Self::{}", format.name);
288                    let mut members = vec!["opcode"];
289
290                    let args_eq = if format.typevar_operand.is_none() {
291                        None
292                    } else if format.has_value_list {
293                        members.push("args");
294                        Some("args1.as_slice(pool) == args2.as_slice(pool)")
295                    } else if format.num_value_operands == 1 {
296                        members.push("arg");
297                        Some("arg1 == arg2")
298                    } else {
299                        members.push("args");
300                        Some("args1 == args2")
301                    };
302
303                    for field in &format.imm_fields {
304                        members.push(field.member);
305                    }
306
307                    let pat1 = members.iter().map(|x| format!("{}: ref {}1", x, x)).collect::<Vec<_>>().join(", ");
308                    let pat2 = members.iter().map(|x| format!("{}: ref {}2", x, x)).collect::<Vec<_>>().join(", ");
309                    fmtln!(fmt, "({} {{ {} }}, {} {{ {} }}) => {{", name, pat1, name, pat2);
310                    fmt.indent(|fmt| {
311                        fmt.line("opcode1 == opcode2");
312                        for field in &format.imm_fields {
313                            fmtln!(fmt, "&& {}1 == {}2", field.member, field.member);
314                        }
315                        if let Some(args_eq) = args_eq {
316                            fmtln!(fmt, "&& {}", args_eq);
317                        }
318                    });
319                    fmtln!(fmt, "}");
320                }
321                fmt.line("_ => unreachable!()");
322            });
323            fmt.line("}");
324        });
325        fmt.line("}");
326        fmt.empty_line();
327
328        fmt.doc_comment(r#"
329            Hash an `InstructionData`.
330
331            This operation requires a reference to a `ValueListPool` to
332            hash the contents of any `ValueLists`.
333        "#);
334        fmt.line("pub fn hash<H: ::core::hash::Hasher>(&self, state: &mut H, pool: &ir::ValueListPool) {");
335        fmt.indent(|fmt| {
336            fmt.line("match *self {");
337            fmt.indent(|fmt| {
338                for format in formats {
339                    let name = format!("Self::{}", format.name);
340                    let mut members = vec!["opcode"];
341
342                    let args = if format.typevar_operand.is_none() {
343                        "&()"
344                    } else if format.has_value_list {
345                        members.push("ref args");
346                        "args.as_slice(pool)"
347                    } else if format.num_value_operands == 1 {
348                        members.push("ref arg");
349                        "arg"
350                    } else {
351                        members.push("ref args");
352                        "args"
353                    };
354
355                    for field in &format.imm_fields {
356                        members.push(field.member);
357                    }
358                    let members = members.join(", ");
359
360                    fmtln!(fmt, "{}{{{}}} => {{", name, members ); fmt.indent(|fmt| {
362                        fmt.line("::core::hash::Hash::hash( &::core::mem::discriminant(self), state);");
363                        fmt.line("::core::hash::Hash::hash(&opcode, state);");
364                        for field in &format.imm_fields {
365                            fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", field.member);
366                        }
367                        fmtln!(fmt, "::core::hash::Hash::hash({}, state);", args);
368                    });
369                    fmtln!(fmt, "}");
370                }
371            });
372            fmt.line("}");
373        });
374        fmt.line("}");
375    });
376    fmt.line("}");
377}
378
379fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
380    all_inst: &AllInstructions,
381    get_attr: T,
382    name: &'static str,
383    doc: &'static str,
384    fmt: &mut Formatter,
385) {
386    fmt.doc_comment(doc);
387    fmtln!(fmt, "pub fn {}(self) -> bool {{", name);
388    fmt.indent(|fmt| {
389        let mut m = Match::new("self");
390        for inst in all_inst.values() {
391            if get_attr(inst) {
392                m.arm_no_fields(format!("Self::{}", inst.camel_name), "true");
393            }
394        }
395        m.arm_no_fields("_", "false");
396        fmt.add_match(m);
397    });
398    fmtln!(fmt, "}");
399    fmt.empty_line();
400}
401
402fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
403    fmt.doc_comment(
404        r#"
405        An instruction opcode.
406
407        All instructions from all supported ISAs are present.
408    "#,
409    );
410    fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
411
412    fmt.line("pub enum Opcode {");
417    fmt.indent(|fmt| {
418        let mut is_first_opcode = true;
419        for inst in all_inst.values() {
420            fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name));
421
422            if let Some(poly) = &inst.polymorphic_info {
424                if poly.use_typevar_operand {
425                    let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()];
426                    fmt.doc_comment(format!(
427                        "Type inferred from `{}`.",
428                        inst.operands_in[op_num].name
429                    ));
430                }
431            }
432
433            if is_first_opcode {
435                assert!(inst.opcode_number.index() == 0);
436                fmtln!(fmt, "{} = 1,", inst.camel_name);
438                is_first_opcode = false;
439            } else {
440                fmtln!(fmt, "{},", inst.camel_name)
441            }
442        }
443    });
444    fmt.line("}");
445    fmt.empty_line();
446
447    fmt.line("impl Opcode {");
448    fmt.indent(|fmt| {
449        gen_bool_accessor(
450            all_inst,
451            |inst| inst.is_terminator,
452            "is_terminator",
453            "True for instructions that terminate the EBB",
454            fmt,
455        );
456        gen_bool_accessor(
457            all_inst,
458            |inst| inst.is_branch,
459            "is_branch",
460            "True for all branch or jump instructions.",
461            fmt,
462        );
463        gen_bool_accessor(
464            all_inst,
465            |inst| inst.is_indirect_branch,
466            "is_indirect_branch",
467            "True for all indirect branch or jump instructions.",
468            fmt,
469        );
470        gen_bool_accessor(
471            all_inst,
472            |inst| inst.is_call,
473            "is_call",
474            "Is this a call instruction?",
475            fmt,
476        );
477        gen_bool_accessor(
478            all_inst,
479            |inst| inst.is_return,
480            "is_return",
481            "Is this a return instruction?",
482            fmt,
483        );
484        gen_bool_accessor(
485            all_inst,
486            |inst| inst.is_ghost,
487            "is_ghost",
488            "Is this a ghost instruction?",
489            fmt,
490        );
491        gen_bool_accessor(
492            all_inst,
493            |inst| inst.can_load,
494            "can_load",
495            "Can this instruction read from memory?",
496            fmt,
497        );
498        gen_bool_accessor(
499            all_inst,
500            |inst| inst.can_store,
501            "can_store",
502            "Can this instruction write to memory?",
503            fmt,
504        );
505        gen_bool_accessor(
506            all_inst,
507            |inst| inst.can_trap,
508            "can_trap",
509            "Can this instruction cause a trap?",
510            fmt,
511        );
512        gen_bool_accessor(
513            all_inst,
514            |inst| inst.other_side_effects,
515            "other_side_effects",
516            "Does this instruction have other side effects besides can_* flags?",
517            fmt,
518        );
519        gen_bool_accessor(
520            all_inst,
521            |inst| inst.writes_cpu_flags,
522            "writes_cpu_flags",
523            "Does this instruction write to CPU flags?",
524            fmt,
525        );
526    });
527    fmt.line("}");
528    fmt.empty_line();
529
530    fmtln!(
532        fmt,
533        "const OPCODE_FORMAT: [InstructionFormat; {}] = [",
534        all_inst.len()
535    );
536    fmt.indent(|fmt| {
537        for inst in all_inst.values() {
538            fmtln!(
539                fmt,
540                "InstructionFormat::{}, // {}",
541                inst.format.name,
542                inst.name
543            );
544        }
545    });
546    fmtln!(fmt, "];");
547    fmt.empty_line();
548
549    fmt.line("fn opcode_name(opc: Opcode) -> &\'static str {");
551    fmt.indent(|fmt| {
552        let mut m = Match::new("opc");
553        for inst in all_inst.values() {
554            m.arm_no_fields(
555                format!("Opcode::{}", inst.camel_name),
556                format!("\"{}\"", inst.name),
557            );
558        }
559        fmt.add_match(m);
560    });
561    fmt.line("}");
562    fmt.empty_line();
563
564    let hash_table = constant_hash::generate_table(all_inst.values(), all_inst.len(), |inst| {
566        constant_hash::simple_hash(&inst.name)
567    });
568    fmtln!(
569        fmt,
570        "const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
571        hash_table.len()
572    );
573    fmt.indent(|fmt| {
574        for i in hash_table {
575            match i {
576                Some(i) => fmtln!(fmt, "Some(Opcode::{}),", i.camel_name),
577                None => fmtln!(fmt, "None,"),
578            }
579        }
580    });
581    fmtln!(fmt, "];");
582    fmt.empty_line();
583}
584
585fn get_constraint<'entries, 'table>(
593    operand: &'entries Operand,
594    ctrl_typevar: Option<&TypeVar>,
595    type_sets: &'table mut UniqueTable<'entries, TypeSet>,
596) -> String {
597    assert!(operand.is_value());
598    let type_var = operand.type_var().unwrap();
599
600    if let Some(typ) = type_var.singleton_type() {
601        return format!("Concrete({})", typ.rust_name());
602    }
603
604    if let Some(free_typevar) = type_var.free_typevar() {
605        if ctrl_typevar.is_some() && free_typevar != *ctrl_typevar.unwrap() {
606            assert!(type_var.base.is_none());
607            return format!("Free({})", type_sets.add(&type_var.get_raw_typeset()));
608        }
609    }
610
611    if let Some(base) = &type_var.base {
612        assert!(base.type_var == *ctrl_typevar.unwrap());
613        return camel_case(base.derived_func.name());
614    }
615
616    assert!(type_var == ctrl_typevar.unwrap());
617    "Same".into()
618}
619
620fn gen_bitset<'a, T: IntoIterator<Item = &'a u16>>(
621    iterable: T,
622    name: &'static str,
623    field_size: u8,
624    fmt: &mut Formatter,
625) {
626    let bits = iterable.into_iter().fold(0, |acc, x| {
627        assert!(x.is_power_of_two());
628        assert!(u32::from(*x) < (1 << u32::from(field_size)));
629        acc | x
630    });
631    fmtln!(fmt, "{}: BitSet::<u{}>({}),", name, field_size, bits);
632}
633
634fn iterable_to_string<I: fmt::Display, T: IntoIterator<Item = I>>(iterable: T) -> String {
635    let elems = iterable
636        .into_iter()
637        .map(|x| x.to_string())
638        .collect::<Vec<_>>()
639        .join(", ");
640    format!("{{{}}}", elems)
641}
642
643fn typeset_to_string(ts: &TypeSet) -> String {
644    let mut result = format!("TypeSet(lanes={}", iterable_to_string(&ts.lanes));
645    if !ts.ints.is_empty() {
646        result += &format!(", ints={}", iterable_to_string(&ts.ints));
647    }
648    if !ts.floats.is_empty() {
649        result += &format!(", floats={}", iterable_to_string(&ts.floats));
650    }
651    if !ts.bools.is_empty() {
652        result += &format!(", bools={}", iterable_to_string(&ts.bools));
653    }
654    if !ts.specials.is_empty() {
655        result += &format!(", specials=[{}]", iterable_to_string(&ts.specials));
656    }
657    if !ts.refs.is_empty() {
658        result += &format!(", refs={}", iterable_to_string(&ts.refs));
659    }
660    result += ")";
661    result
662}
663
664pub(crate) fn gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter) {
666    if type_sets.len() == 0 {
667        return;
668    }
669
670    fmt.comment("Table of value type sets.");
671    assert!(type_sets.len() <= TYPESET_LIMIT, "Too many type sets!");
672    fmtln!(
673        fmt,
674        "const TYPE_SETS: [ir::instructions::ValueTypeSet; {}] = [",
675        type_sets.len()
676    );
677    fmt.indent(|fmt| {
678        for ts in type_sets.iter() {
679            fmt.line("ir::instructions::ValueTypeSet {");
680            fmt.indent(|fmt| {
681                fmt.comment(typeset_to_string(ts));
682                gen_bitset(&ts.lanes, "lanes", 16, fmt);
683                gen_bitset(&ts.ints, "ints", 8, fmt);
684                gen_bitset(&ts.floats, "floats", 8, fmt);
685                gen_bitset(&ts.bools, "bools", 8, fmt);
686                gen_bitset(&ts.refs, "refs", 8, fmt);
687            });
688            fmt.line("},");
689        }
690    });
691    fmtln!(fmt, "];");
692}
693
694fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) {
699    let mut type_sets = UniqueTable::new();
701
702    let mut operand_seqs = UniqueSeqTable::new();
708
709    #[allow(clippy::useless_vec)]
711    operand_seqs.add(&vec!["Same".to_string(); 3]);
712
713    fmt.comment("Table of opcode constraints.");
714    fmtln!(
715        fmt,
716        "const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [",
717        all_inst.len()
718    );
719    fmt.indent(|fmt| {
720        for inst in all_inst.values() {
721            let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
722                let index = type_sets.add(&*poly.ctrl_typevar.get_raw_typeset());
723                (Some(&poly.ctrl_typevar), index)
724            } else {
725                (None, TYPESET_LIMIT)
726            };
727
728            let mut constraints = Vec::new();
731            for &index in &inst.value_results {
732                constraints.push(get_constraint(&inst.operands_out[index], ctrl_typevar, &mut type_sets));
733            }
734            for &index in &inst.value_opnums {
735                constraints.push(get_constraint(&inst.operands_in[index], ctrl_typevar, &mut type_sets));
736            }
737
738            let constraint_offset = operand_seqs.add(&constraints);
739
740            let fixed_results = inst.value_results.len();
741            let fixed_values = inst.value_opnums.len();
742
743            let use_typevar_operand = if let Some(poly) = &inst.polymorphic_info {
745                poly.use_typevar_operand
746            } else {
747                false
748            };
749
750            let use_result = fixed_results > 0 && inst.operands_out[inst.value_results[0]].type_var() == ctrl_typevar;
752
753            let requires_typevar_operand = use_typevar_operand && !use_result;
755
756            fmt.comment(
757                format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}",
758                inst.camel_name,
759                fixed_results,
760                use_typevar_operand,
761                requires_typevar_operand,
762                fixed_values)
763            );
764            fmt.comment(format!("Constraints=[{}]", constraints
765                .iter()
766                .map(|x| format!("'{}'", x))
767                .collect::<Vec<_>>()
768                .join(", ")));
769            if let Some(poly) = &inst.polymorphic_info {
770                fmt.comment(format!("Polymorphic over {}", typeset_to_string(&poly.ctrl_typevar.get_raw_typeset())));
771            }
772
773            assert!(fixed_results < 8 && fixed_values < 8, "Bit field encoding too tight");
775            let mut flags = fixed_results; if use_typevar_operand {
777                flags |= 1<<3; }
779            if requires_typevar_operand {
780                flags |= 1<<4; }
782            flags |= fixed_values << 5; fmt.line("OpcodeConstraints {");
785            fmt.indent(|fmt| {
786                fmtln!(fmt, "flags: {:#04x},", flags);
787                fmtln!(fmt, "typeset_offset: {},", ctrl_typeset);
788                fmtln!(fmt, "constraint_offset: {},", constraint_offset);
789            });
790            fmt.line("},");
791        }
792    });
793    fmtln!(fmt, "];");
794    fmt.empty_line();
795
796    gen_typesets_table(&type_sets, fmt);
797    fmt.empty_line();
798
799    fmt.comment("Table of operand constraint sequences.");
800    fmtln!(
801        fmt,
802        "const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [",
803        operand_seqs.len()
804    );
805    fmt.indent(|fmt| {
806        for constraint in operand_seqs.iter() {
807            fmtln!(fmt, "OperandConstraint::{},", constraint);
808        }
809    });
810    fmtln!(fmt, "];");
811}
812
813fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) {
815    for f in &format.imm_fields {
818        fmtln!(fmt, "{},", f.member);
819    }
820
821    if format.has_value_list {
823        fmt.line("args,");
824    } else if format.num_value_operands == 1 {
825        fmt.line("arg: arg0,");
826    } else if format.num_value_operands > 1 {
827        let mut args = Vec::new();
828        for i in 0..format.num_value_operands {
829            args.push(format!("arg{}", i));
830        }
831        fmtln!(fmt, "args: [{}],", args.join(", "));
832    }
833}
834
835fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) {
840    let mut args = vec![
842        "self".to_string(),
843        "opcode: Opcode".into(),
844        "ctrl_typevar: Type".into(),
845    ];
846
847    for f in &format.imm_fields {
849        args.push(format!("{}: {}", f.member, f.kind.rust_type));
850    }
851
852    if format.has_value_list {
854        args.push("args: ir::ValueList".into());
857    } else {
858        for i in 0..format.num_value_operands {
860            args.push(format!("arg{}: Value", i));
861        }
862    }
863
864    let proto = format!(
865        "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)",
866        format.name,
867        args.join(", ")
868    );
869
870    fmt.doc_comment(format.to_string());
871    fmt.line("#[allow(non_snake_case)]");
872    fmtln!(fmt, "fn {} {{", proto);
873    fmt.indent(|fmt| {
874        fmtln!(fmt, "let data = ir::InstructionData::{} {{", format.name);
876        fmt.indent(|fmt| {
877            fmt.line("opcode,");
878            gen_member_inits(format, fmt);
879        });
880        fmtln!(fmt, "};");
881        fmt.line("self.build(data, ctrl_typevar)");
882    });
883    fmtln!(fmt, "}");
884}
885
886fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter) {
891    let mut args = vec![if format.has_value_list {
893        "mut self"
894    } else {
895        "self"
896    }
897    .to_string()];
898
899    let mut args_doc = Vec::new();
900    let mut rets_doc = Vec::new();
901
902    if let Some(poly) = &inst.polymorphic_info {
905        if !poly.use_typevar_operand {
906            args.push(format!("{}: crate::ir::Type", poly.ctrl_typevar.name));
907            args_doc.push(format!(
908                "- {} (controlling type variable): {}",
909                poly.ctrl_typevar.name, poly.ctrl_typevar.doc
910            ));
911        }
912    }
913
914    let mut tmpl_types = Vec::new();
915    let mut into_args = Vec::new();
916    for op in &inst.operands_in {
917        let t = if op.is_immediate() {
918            let t = format!("T{}", tmpl_types.len() + 1);
919            tmpl_types.push(format!("{}: Into<{}>", t, op.kind.rust_type));
920            into_args.push(op.name);
921            t
922        } else {
923            op.kind.rust_type.to_string()
924        };
925        args.push(format!("{}: {}", op.name, t));
926        args_doc.push(format!(
927            "- {}: {}",
928            op.name,
929            op.doc()
930                .expect("every instruction's input operand must be documented")
931        ));
932    }
933
934    for op in &inst.operands_out {
935        rets_doc.push(format!(
936            "- {}: {}",
937            op.name,
938            op.doc()
939                .expect("every instruction's output operand must be documented")
940        ));
941    }
942
943    let rtype = match inst.value_results.len() {
944        0 => "Inst".into(),
945        1 => "Value".into(),
946        _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")),
947    };
948
949    let tmpl = if !tmpl_types.is_empty() {
950        format!("<{}>", tmpl_types.join(", "))
951    } else {
952        "".into()
953    };
954
955    let proto = format!(
956        "{}{}({}) -> {}",
957        inst.snake_name(),
958        tmpl,
959        args.join(", "),
960        rtype
961    );
962
963    fmt.doc_comment(&inst.doc);
964    if !args_doc.is_empty() {
965        fmt.line("///");
966        fmt.doc_comment("Inputs:");
967        fmt.line("///");
968        for doc_line in args_doc {
969            fmt.doc_comment(doc_line);
970        }
971    }
972    if !rets_doc.is_empty() {
973        fmt.line("///");
974        fmt.doc_comment("Outputs:");
975        fmt.line("///");
976        for doc_line in rets_doc {
977            fmt.doc_comment(doc_line);
978        }
979    }
980
981    fmt.line("#[allow(non_snake_case)]");
982    fmtln!(fmt, "fn {} {{", proto);
983    fmt.indent(|fmt| {
984        for arg in &into_args {
986            fmtln!(fmt, "let {} = {}.into();", arg, arg);
987        }
988
989        let first_arg = format!("Opcode::{}", inst.camel_name);
991        let mut args = vec![first_arg.as_str()];
992        if let Some(poly) = &inst.polymorphic_info {
993            if poly.use_typevar_operand {
994                let op_num = inst.value_opnums[format.typevar_operand.unwrap()];
996                fmtln!(
997                    fmt,
998                    "let ctrl_typevar = self.data_flow_graph().value_type({});",
999                    inst.operands_in[op_num].name
1000                );
1001
1002                args.push("ctrl_typevar");
1004            } else {
1005                args.push(&poly.ctrl_typevar.name);
1007            }
1008        } else {
1009            args.push("types::INVALID");
1011        }
1012
1013        for &op_num in &inst.imm_opnums {
1015            args.push(inst.operands_in[op_num].name);
1016        }
1017
1018        if format.has_value_list {
1020            fmt.line("let mut vlist = ir::ValueList::default();");
1022            args.push("vlist");
1023            fmt.line("{");
1024            fmt.indent(|fmt| {
1025                fmt.line("let pool = &mut self.data_flow_graph_mut().value_lists;");
1026                for op in &inst.operands_in {
1027                    if op.is_value() {
1028                        fmtln!(fmt, "vlist.push({}, pool);", op.name);
1029                    } else if op.is_varargs() {
1030                        fmtln!(fmt, "vlist.extend({}.iter().cloned(), pool);", op.name);
1031                    }
1032                }
1033            });
1034            fmt.line("}");
1035        } else {
1036            for &op_num in &inst.value_opnums {
1038                args.push(inst.operands_in[op_num].name);
1039            }
1040        }
1041
1042        let fcall = format!("self.{}({})", format.name, args.join(", "));
1044
1045        if inst.value_results.is_empty() {
1046            fmtln!(fmt, "{}.0", fcall);
1047            return;
1048        }
1049
1050        fmtln!(fmt, "let (inst, dfg) = {};", fcall);
1051        if inst.value_results.len() == 1 {
1052            fmt.line("dfg.first_result(inst)");
1053        } else {
1054            fmtln!(
1055                fmt,
1056                "let results = &dfg.inst_results(inst)[0..{}];",
1057                inst.value_results.len()
1058            );
1059            fmtln!(
1060                fmt,
1061                "({})",
1062                inst.value_results
1063                    .iter()
1064                    .enumerate()
1065                    .map(|(i, _)| format!("results[{}]", i))
1066                    .collect::<Vec<_>>()
1067                    .join(", ")
1068            );
1069        }
1070    });
1071    fmtln!(fmt, "}")
1072}
1073
1074fn gen_builder(
1076    instructions: &AllInstructions,
1077    formats: &[&InstructionFormat],
1078    fmt: &mut Formatter,
1079) {
1080    fmt.doc_comment(
1081        r#"
1082        Convenience methods for building instructions.
1083
1084        The `InstBuilder` trait has one method per instruction opcode for
1085        conveniently constructing the instruction with minimum arguments.
1086        Polymorphic instructions infer their result types from the input
1087        arguments when possible. In some cases, an explicit `ctrl_typevar`
1088        argument is required.
1089
1090        The opcode methods return the new instruction's result values, or
1091        the `Inst` itself for instructions that don't have any results.
1092
1093        There is also a method per instruction format. These methods all
1094        return an `Inst`.
1095    "#,
1096    );
1097    fmt.line("pub trait InstBuilder<'f>: InstBuilderBase<'f> {");
1098    fmt.indent(|fmt| {
1099        for inst in instructions.values() {
1100            gen_inst_builder(inst, &*inst.format, fmt);
1101            fmt.empty_line();
1102        }
1103        for (i, format) in formats.iter().enumerate() {
1104            gen_format_constructor(format, fmt);
1105            if i + 1 != formats.len() {
1106                fmt.empty_line();
1107            }
1108        }
1109    });
1110    fmt.line("}");
1111}
1112
1113pub(crate) fn generate(
1114    formats: Vec<&InstructionFormat>,
1115    all_inst: &AllInstructions,
1116    opcode_filename: &str,
1117    inst_builder_filename: &str,
1118    out_dir: &str,
1119) -> Result<(), error::Error> {
1120    let mut fmt = Formatter::new();
1122    gen_formats(&formats, &mut fmt);
1123    gen_instruction_data(&formats, &mut fmt);
1124    fmt.empty_line();
1125    gen_instruction_data_impl(&formats, &mut fmt);
1126    fmt.empty_line();
1127    gen_opcodes(all_inst, &mut fmt);
1128    gen_type_constraints(all_inst, &mut fmt);
1129    fmt.update_file(opcode_filename, out_dir)?;
1130
1131    let mut fmt = Formatter::new();
1133    gen_builder(all_inst, &formats, &mut fmt);
1134    fmt.update_file(inst_builder_filename, out_dir)?;
1135
1136    Ok(())
1137}