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_is_available_impl(f, insts);
19    generate_inst_features_impl(f, insts);
20
21    // Generate per-instruction structs.
22    f.empty_line();
23    for inst in insts {
24        inst.generate_struct(f);
25        inst.generate_struct_impl(f);
26        inst.generate_display_impl(f);
27        inst.generate_from_impl(f);
28        f.empty_line();
29    }
30
31    // Generate the `Feature` trait.
32    dsl::Feature::generate_macro(f);
33}
34
35/// `enum Inst { ... }`
36fn generate_inst_enum(f: &mut Formatter, insts: &[dsl::Inst]) {
37    fmtln!(f, "#[doc(hidden)]");
38    generate_derive(f);
39    generate_derive_arbitrary_bounds(f);
40    f.add_block("pub enum Inst<R: Registers>", |f| {
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    });
47}
48
49/// `#[derive(...)]`
50fn generate_derive(f: &mut Formatter) {
51    fmtln!(f, "#[derive(Copy, Clone, Debug)]");
52    fmtln!(
53        f,
54        "#[cfg_attr(any(test, feature = \"fuzz\"), derive(arbitrary::Arbitrary))]"
55    );
56}
57
58/// Adds a custom bound to the `Arbitrary` implementation which ensures that
59/// the associated registers are all `Arbitrary` as well.
60fn generate_derive_arbitrary_bounds(f: &mut Formatter) {
61    fmtln!(
62        f,
63        "#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]"
64    );
65}
66
67/// `impl std::fmt::Display for Inst { ... }`
68fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
69    f.add_block("impl<R: Registers> std::fmt::Display for Inst<R>", |f| {
70        f.add_block(
71            "fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result",
72            |f| {
73                f.add_block("match self", |f| {
74                    for inst in insts {
75                        let variant_name = inst.name();
76                        fmtln!(f, "Self::{variant_name}(i) => i.fmt(f),");
77                    }
78                });
79            },
80        );
81    });
82}
83
84/// `impl Inst { fn encode... }`
85fn generate_inst_encode_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
86    f.add_block("impl<R: Registers> Inst<R>", |f| {
87        f.add_block("pub fn encode(&self, b: &mut impl CodeSink)", |f| {
88            f.add_block("match self", |f| {
89                for inst in insts {
90                    let variant_name = inst.name();
91                    fmtln!(f, "Self::{variant_name}(i) => i.encode(b),");
92                }
93            });
94        });
95    });
96}
97
98/// `impl Inst { fn visit... }`
99fn generate_inst_visit_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
100    fmtln!(f, "impl<R: Registers> Inst<R> {{");
101    f.indent(|f| {
102        fmtln!(
103            f,
104            "pub fn visit(&mut self, v: &mut impl RegisterVisitor<R>) {{"
105        );
106        f.indent(|f| {
107            fmtln!(f, "match self {{");
108            f.indent_push();
109            for inst in insts {
110                let variant_name = inst.name();
111                fmtln!(f, "Self::{variant_name}(i) => i.visit(v),");
112            }
113            f.indent_pop();
114            fmtln!(f, "}}");
115        });
116        fmtln!(f, "}}");
117    });
118    fmtln!(f, "}}");
119}
120
121/// `impl Inst { fn is_available... }`
122fn generate_inst_is_available_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
123    f.add_block("impl<R: Registers> Inst<R>", |f| {
124        f.add_block(
125            "pub fn is_available(&self, f: &impl AvailableFeatures) -> bool",
126            |f| {
127                f.add_block("match self", |f| {
128                    for inst in insts {
129                        let variant_name = inst.name();
130                        fmtln!(f, "Self::{variant_name}(i) => i.is_available(f),");
131                    }
132                });
133            },
134        );
135    });
136}
137
138/// `impl Inst { fn features... }`
139fn generate_inst_features_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
140    f.add_block("impl<R: Registers> Inst<R>", |f| {
141        f.add_block("pub fn features(&self) -> &'static Features", |f| {
142            f.add_block("match self", |f| {
143                for inst in insts {
144                    let variant_name = inst.name();
145                    fmtln!(f, "Self::{variant_name}(i) => i.features(),");
146                }
147            });
148        });
149    });
150}