cranelift_assembler_x64_meta/
generate.rs

1//! Contains the code-generation logic to emit for the DSL-defined instructions.
2
3mod features;
4mod format;
5mod inst;
6mod operand;
7
8use crate::dsl;
9use cranelift_srcgen::{Formatter, fmtln};
10
11/// Generate the Rust assembler code; e.g., `enum Inst { ... }`.
12pub fn rust_assembler(f: &mut Formatter, insts: &[dsl::Inst]) {
13    // Generate "all instructions" enum.
14    generate_inst_enum(f, insts);
15    generate_inst_display_impl(f, insts);
16    generate_inst_encode_impl(f, insts);
17    generate_inst_visit_impl(f, insts);
18    generate_inst_features_impl(f, insts);
19
20    // Generate per-instruction structs.
21    f.empty_line();
22    for inst in insts {
23        inst.generate_struct(f);
24        inst.generate_struct_impl(f);
25        inst.generate_display_impl(f);
26        inst.generate_from_impl(f);
27        f.empty_line();
28    }
29
30    // Generate the `Feature` enum.
31    dsl::Feature::generate_enum(f);
32}
33
34/// `enum Inst { ... }`
35fn generate_inst_enum(f: &mut Formatter, insts: &[dsl::Inst]) {
36    fmtln!(f, "#[doc(hidden)]");
37    generate_derive(f);
38    generate_derive_arbitrary_bounds(f);
39    f.add_block("pub enum Inst<R: Registers>", |f| {
40        for inst in insts {
41            let variant_name = inst.name();
42            let struct_name = inst.struct_name_with_generic();
43            fmtln!(f, "{variant_name}({struct_name}),");
44        }
45    });
46}
47
48/// `#[derive(...)]`
49fn generate_derive(f: &mut Formatter) {
50    fmtln!(f, "#[derive(Copy, Clone, Debug)]");
51    fmtln!(
52        f,
53        "#[cfg_attr(any(test, feature = \"fuzz\"), derive(arbitrary::Arbitrary))]"
54    );
55}
56
57/// Adds a custom bound to the `Arbitrary` implementation which ensures that
58/// the associated registers are all `Arbitrary` as well.
59fn generate_derive_arbitrary_bounds(f: &mut Formatter) {
60    fmtln!(
61        f,
62        "#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]"
63    );
64}
65
66/// `impl std::fmt::Display for Inst { ... }`
67fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
68    f.add_block("impl<R: Registers> std::fmt::Display for Inst<R>", |f| {
69        f.add_block(
70            "fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result",
71            |f| {
72                f.add_block("match self", |f| {
73                    for inst in insts {
74                        let variant_name = inst.name();
75                        fmtln!(f, "Self::{variant_name}(i) => i.fmt(f),");
76                    }
77                });
78            },
79        );
80    });
81}
82
83/// `impl Inst { fn encode... }`
84fn generate_inst_encode_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
85    f.add_block("impl<R: Registers> Inst<R>", |f| {
86        f.add_block("pub fn encode(&self, b: &mut impl CodeSink)", |f| {
87            f.add_block("match self", |f| {
88                for inst in insts {
89                    let variant_name = inst.name();
90                    fmtln!(f, "Self::{variant_name}(i) => i.encode(b),");
91                }
92            });
93        });
94    });
95}
96
97/// `impl Inst { fn visit... }`
98fn generate_inst_visit_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
99    fmtln!(f, "impl<R: Registers> Inst<R> {{");
100    f.indent(|f| {
101        fmtln!(
102            f,
103            "pub fn visit(&mut self, v: &mut impl RegisterVisitor<R>) {{"
104        );
105        f.indent(|f| {
106            fmtln!(f, "match self {{");
107            f.indent_push();
108            for inst in insts {
109                let variant_name = inst.name();
110                fmtln!(f, "Self::{variant_name}(i) => i.visit(v),");
111            }
112            f.indent_pop();
113            fmtln!(f, "}}");
114        });
115        fmtln!(f, "}}");
116    });
117    fmtln!(f, "}}");
118}
119
120/// `impl Inst { fn features... }`
121fn generate_inst_features_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
122    f.add_block("impl<R: Registers> Inst<R>", |f| {
123        f.add_block("pub fn features(&self) -> Vec<Feature>", |f| {
124            f.add_block("match self", |f| {
125                for inst in insts {
126                    let variant_name = inst.name();
127                    fmtln!(f, "Self::{variant_name}(i) => i.features(),");
128                }
129            });
130        });
131    });
132}