1 //! Contains the code-generation logic to emit for the DSL-defined instructions.
2 
3 mod features;
4 mod format;
5 mod inst;
6 mod operand;
7 
8 use crate::dsl;
9 use cranelift_srcgen::{Formatter, fmtln};
10 
11 /// Generate the Rust assembler code; e.g., `enum Inst { ... }`.
12 pub 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 { ... }`
36 fn 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(...)]`
50 fn 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.
60 fn 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 { ... }`
68 fn 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... }`
85 fn 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... }`
99 fn 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... }`
122 fn 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... }`
139 fn 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 }
151