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::{fmtln, Formatter};
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    fmtln!(f, "pub enum Inst<R: Registers> {{");
40    f.indent_push();
41    for inst in insts {
42        let variant_name = inst.name();
43        let struct_name = inst.struct_name_with_generic();
44        fmtln!(f, "{variant_name}({struct_name}),");
45    }
46    f.indent_pop();
47    fmtln!(f, "}}");
48}
49
50/// `#[derive(...)]`
51fn generate_derive(f: &mut Formatter) {
52    fmtln!(f, "#[derive(Clone, Debug)]");
53    fmtln!(f, "#[cfg_attr(any(test, feature = \"fuzz\"), derive(arbitrary::Arbitrary))]");
54}
55
56/// Adds a custom bound to the `Arbitrary` implementation which ensures that
57/// the associated registers are all `Arbitrary` as well.
58fn generate_derive_arbitrary_bounds(f: &mut Formatter) {
59    fmtln!(f,
60        "#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]"
61    );
62}
63
64/// `impl std::fmt::Display for Inst { ... }`
65fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
66    fmtln!(f, "impl<R: Registers> std::fmt::Display for Inst<R> {{");
67    f.indent(|f| {
68        fmtln!(f, "fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{");
69        f.indent(|f| {
70            fmtln!(f, "match self {{");
71            f.indent_push();
72            for inst in insts {
73                let variant_name = inst.name();
74                fmtln!(f, "Self::{variant_name}(i) => write!(f, \"{{i}}\"),");
75            }
76            f.indent_pop();
77            fmtln!(f, "}}");
78        });
79        fmtln!(f, "}}");
80    });
81    fmtln!(f, "}}");
82}
83
84/// `impl Inst { fn encode... }`
85fn generate_inst_encode_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
86    fmtln!(f, "impl<R: Registers> Inst<R> {{");
87    f.indent(|f| {
88        fmtln!(f, "pub fn encode(&self, b: &mut impl CodeSink, o: &impl KnownOffsetTable) {{");
89        f.indent(|f| {
90            fmtln!(f, "match self {{");
91            f.indent_push();
92            for inst in insts {
93                let variant_name = inst.name();
94                fmtln!(f, "Self::{variant_name}(i) => i.encode(b, o),");
95            }
96            f.indent_pop();
97            fmtln!(f, "}}");
98        });
99        fmtln!(f, "}}");
100    });
101    fmtln!(f, "}}");
102}
103
104/// `impl Inst { fn visit... }`
105fn generate_inst_visit_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
106    fmtln!(f, "impl<R: Registers> Inst<R> {{");
107    f.indent(|f| {
108        fmtln!(f, "pub fn visit(&mut self, v: &mut impl RegisterVisitor<R>) {{");
109        f.indent(|f| {
110            fmtln!(f, "match self {{");
111            f.indent_push();
112            for inst in insts {
113                let variant_name = inst.name();
114                fmtln!(f, "Self::{variant_name}(i) => i.visit(v),");
115            }
116            f.indent_pop();
117            fmtln!(f, "}}");
118        });
119        fmtln!(f, "}}");
120    });
121    fmtln!(f, "}}");
122}
123
124/// `impl Inst { fn features... }`
125fn generate_inst_features_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
126    fmtln!(f, "impl<R: Registers> Inst<R> {{");
127    f.indent(|f| {
128        fmtln!(f, "#[must_use]");
129        fmtln!(f, "pub fn features(&self) -> Vec<Feature> {{");
130        f.indent(|f| {
131            fmtln!(f, "match self {{");
132            f.indent_push();
133            for inst in insts {
134                let variant_name = inst.name();
135                fmtln!(f, "Self::{variant_name}(i) => i.features(),");
136            }
137            f.indent_pop();
138            fmtln!(f, "}}");
139        });
140        fmtln!(f, "}}");
141    });
142    fmtln!(f, "}}");
143}