1 use super::{Formatter, fmtln, generate_derive, generate_derive_arbitrary_bounds};
2 use crate::dsl;
3 
4 impl dsl::Inst {
5     /// `struct <inst> { <op>: Reg, <op>: Reg, ... }`
generate_struct(&self, f: &mut Formatter)6     pub fn generate_struct(&self, f: &mut Formatter) {
7         let struct_name = self.struct_name_with_generic();
8         let where_clause = if self.requires_generic() {
9             "where R: Registers"
10         } else {
11             ""
12         };
13 
14         fmtln!(f, "/// `{self}`");
15         generate_derive(f);
16         if self.requires_generic() {
17             generate_derive_arbitrary_bounds(f);
18         }
19         f.add_block(&format!("pub struct {struct_name} {where_clause}"), |f| {
20             for k in &self.format.operands {
21                 let loc = k.location;
22                 let ty = k.generate_type();
23                 fmtln!(f, "pub {loc}: {ty},");
24             }
25 
26             if self.has_trap {
27                 fmtln!(f, "pub trap: TrapCode,");
28             }
29         });
30     }
31 
requires_generic(&self) -> bool32     fn requires_generic(&self) -> bool {
33         self.format.uses_register()
34     }
35 
36     /// `<struct_name><R>`
struct_name_with_generic(&self) -> String37     pub(crate) fn struct_name_with_generic(&self) -> String {
38         let struct_name = self.name();
39         if self.requires_generic() {
40             format!("{struct_name}<R>")
41         } else {
42             struct_name
43         }
44     }
45 
46     /// `impl...`
generate_impl_block_start(&self) -> &str47     fn generate_impl_block_start(&self) -> &str {
48         if self.requires_generic() {
49             "impl<R: Registers>"
50         } else {
51             "impl"
52         }
53     }
54 
55     /// `impl <inst> { ... }`
generate_struct_impl(&self, f: &mut Formatter)56     pub fn generate_struct_impl(&self, f: &mut Formatter) {
57         let impl_block = self.generate_impl_block_start();
58         let struct_name = self.struct_name_with_generic();
59         f.add_block(&format!("{impl_block} {struct_name}"), |f| {
60             self.generate_new_function(f);
61             f.empty_line();
62             self.generate_mnemonic_function(f);
63             f.empty_line();
64             self.generate_encode_function(f);
65             f.empty_line();
66             self.generate_visit_function(f);
67             f.empty_line();
68             self.generate_is_available_function(f);
69             f.empty_line();
70             self.generate_features_function(f);
71             f.empty_line();
72             self.generate_num_registers_function(f);
73         });
74     }
75 
76     // `fn new(<params>) -> Self { ... }`
generate_new_function(&self, f: &mut Formatter)77     pub fn generate_new_function(&self, f: &mut Formatter) {
78         let params = comma_join(
79             self.format
80                 .operands
81                 .iter()
82                 .map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type()))
83                 .chain(if self.has_trap {
84                     Some("trap: impl Into<TrapCode>".to_string())
85                 } else {
86                     None
87                 }),
88         );
89         fmtln!(f, "#[must_use]");
90         f.add_block(&format!("pub fn new({params}) -> Self"), |f| {
91             f.add_block("Self", |f| {
92                 for o in &self.format.operands {
93                     let loc = o.location;
94                     fmtln!(f, "{loc}: {loc}.into(),");
95                 }
96                 if self.has_trap {
97                     fmtln!(f, "trap: trap.into(),");
98                 }
99             });
100         });
101     }
102 
103     /// `fn mnemonic(&self) -> &'static str { ... }`
generate_mnemonic_function(&self, f: &mut Formatter)104     pub fn generate_mnemonic_function(&self, f: &mut Formatter) {
105         use dsl::Customization::*;
106 
107         fmtln!(f, "#[must_use]");
108         fmtln!(f, "#[inline]");
109         f.add_block(
110             &format!("pub fn mnemonic(&self) -> alloc::borrow::Cow<'static, str>"),
111             |f| {
112                 if self.custom.contains(Mnemonic) {
113                     fmtln!(f, "crate::custom::mnemonic::{}(self)", self.name());
114                 } else {
115                     fmtln!(f, "alloc::borrow::Cow::Borrowed(\"{}\")", self.mnemonic);
116                 }
117             },
118         );
119     }
120 
121     /// `fn encode(&self, ...) { ... }`
generate_encode_function(&self, f: &mut Formatter)122     fn generate_encode_function(&self, f: &mut Formatter) {
123         use dsl::Customization::*;
124 
125         f.add_block(
126             &format!("pub fn encode(&self, buf: &mut impl CodeSink)"),
127             |f| {
128                 if self.custom.contains(Encode) {
129                     fmtln!(f, "crate::custom::encode::{}(self, buf);", self.name());
130                 } else {
131                     self.generate_possible_trap(f);
132                     match &self.encoding {
133                         dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),
134                         dsl::Encoding::Vex(vex) => self.format.generate_vex_encoding(f, vex),
135                         dsl::Encoding::Evex(evex) => self.format.generate_evex_encoding(f, evex),
136                     }
137                 }
138             },
139         );
140     }
141 
142     // `buf.add_trap(...)`
generate_possible_trap(&self, f: &mut Formatter)143     fn generate_possible_trap(&self, f: &mut Formatter) {
144         if self.has_trap {
145             f.comment("Emit trap.");
146             fmtln!(f, "buf.add_trap(self.trap);");
147         } else if let Some(op) = self.format.uses_memory() {
148             use dsl::OperandKind::*;
149             f.comment("Emit trap.");
150             match op.kind() {
151                 Mem(_) => {
152                     f.add_block(
153                         &format!("if let Some(trap_code) = self.{op}.trap_code()"),
154                         |f| {
155                             fmtln!(f, "buf.add_trap(trap_code);");
156                         },
157                     );
158                 }
159                 RegMem(_) => {
160                     let ty = op.reg_class().unwrap();
161                     f.add_block(&format!("if let {ty}Mem::Mem({op}) = &self.{op}"), |f| {
162                         f.add_block(&format!("if let Some(trap_code) = {op}.trap_code()"), |f| {
163                             fmtln!(f, "buf.add_trap(trap_code);");
164                         });
165                     });
166                 }
167                 _ => unreachable!(),
168             }
169         }
170     }
171 
172     /// `fn visit(&self, ...) { ... }`
generate_visit_function(&self, f: &mut Formatter)173     fn generate_visit_function(&self, f: &mut Formatter) {
174         use dsl::{Customization::*, OperandKind::*};
175         let extra_generic_bound = if self.requires_generic() {
176             ""
177         } else {
178             "<R: Registers>"
179         };
180         let visitor = if self.format.operands.is_empty() && !self.custom.contains(Visit) {
181             "_"
182         } else {
183             "visitor"
184         };
185         f.add_block(&format!("pub fn visit{extra_generic_bound}(&mut self, {visitor}: &mut impl RegisterVisitor<R>)"), |f| {
186             if self.custom.contains(Visit) {
187                 fmtln!(f, "crate::custom::visit::{}(self, visitor)", self.name());
188                 return;
189             }
190             for o in &self.format.operands {
191                 let mutability = o.mutability.generate_snake_case();
192                 let reg = o.location.reg_class();
193                 match o.location.kind() {
194                     Imm(_) => {
195                         // Immediates do not need register allocation.
196                         //
197                         // If an instruction happens to only have immediates
198                         // then generate a dummy use of the `visitor` variable
199                         // to suppress unused variables warnings.
200                         fmtln!(f, "let _ = visitor;");
201                     }
202                     FixedReg(loc) => {
203                         let reg_lower = reg.unwrap().to_string().to_lowercase();
204                         fmtln!(f, "let enc = self.{loc}.expected_enc();");
205                         fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");
206                     }
207                     Reg(loc) => {
208                         let reg_lower = reg.unwrap().to_string().to_lowercase();
209                         fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");
210                     }
211                     RegMem(loc) => {
212                         let reg = reg.unwrap();
213                         let reg_lower = reg.to_string().to_lowercase();
214                         fmtln!(f, "visitor.{mutability}_{reg_lower}_mem(&mut self.{loc});");
215                     }
216                     Mem(loc) => {
217                         // Note that this is always "read" because from a
218                         // regalloc perspective when using an amode it means
219                         // that the while a write is happening that's to
220                         // memory, not registers.
221                         fmtln!(f, "visitor.read_amode(&mut self.{loc});");
222                     }
223 
224                 }
225             }
226         });
227     }
228 
229     /// `fn is_available(&self, ...) -> bool { ... }`
generate_is_available_function(&self, f: &mut Formatter)230     fn generate_is_available_function(&self, f: &mut Formatter) {
231         fmtln!(f, "#[must_use]");
232         f.add_block(
233             "pub fn is_available(&self, features: &impl AvailableFeatures) -> bool",
234             |f| {
235                 let expr = self.features.generate_boolean_expr("features");
236                 fmtln!(f, "{expr}");
237             },
238         );
239     }
240 
241     /// `fn features(&self) -> Features { ... }`
generate_features_function(&self, f: &mut Formatter)242     fn generate_features_function(&self, f: &mut Formatter) {
243         fmtln!(f, "#[must_use]");
244         f.add_block("pub fn features(&self) -> &'static Features", |f| {
245             self.features.generate_constructor_expr(f);
246         });
247     }
248 
249     /// `fn num_registers_available(&self) -> usize { ... }`
generate_num_registers_function(&self, f: &mut Formatter)250     fn generate_num_registers_function(&self, f: &mut Formatter) {
251         fmtln!(f, "#[must_use]");
252         f.add_block("pub fn num_registers_available(&self) -> usize", |f| {
253             use dsl::Encoding::*;
254             let n = match self.encoding {
255                 Rex(_) | Vex(_) => 16,
256                 Evex(_) => 32,
257             };
258             fmtln!(f, "{n}")
259         });
260     }
261 
262     /// `impl Display for <inst> { ... }`
generate_display_impl(&self, f: &mut Formatter)263     pub fn generate_display_impl(&self, f: &mut Formatter) {
264         use crate::dsl::Customization::*;
265         let impl_block = self.generate_impl_block_start();
266         let struct_name = self.struct_name_with_generic();
267         f.add_block(
268             &format!("{impl_block} core::fmt::Display for {struct_name}"),
269             |f| {
270                 f.add_block(
271                     "fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result",
272                     |f| {
273                         if self.custom.contains(Display) {
274                             fmtln!(f, "crate::custom::display::{}(f, self)", self.name());
275                             return;
276                         }
277 
278                         fmtln!(f, "let name = self.mnemonic();");
279                         if self.format.operands.is_empty() {
280                             fmtln!(f, "f.write_str(&name)");
281                             return;
282                         }
283                         for op in self.format.operands.iter() {
284                             let location = op.location;
285                             let to_string = location.generate_to_string(op.extension);
286                             fmtln!(f, "let {location} = {to_string};");
287                         }
288                         let ordered_ops = self.format.generate_att_style_operands();
289                         let mut implicit_ops = self.format.generate_implicit_operands();
290                         if self.has_trap {
291                             fmtln!(f, "let trap = self.trap;");
292                             if implicit_ops.is_empty() {
293                                 implicit_ops.push_str(" ;; {trap}");
294                             } else {
295                                 implicit_ops.push_str(", {trap}");
296                             }
297                         }
298                         fmtln!(f, "write!(f, \"{{name}} {ordered_ops}{implicit_ops}\")");
299                     },
300                 );
301             },
302         );
303     }
304 
305     /// `impl From<struct> for Inst { ... }`
generate_from_impl(&self, f: &mut Formatter)306     pub fn generate_from_impl(&self, f: &mut Formatter) {
307         let struct_name_r = self.struct_name_with_generic();
308         let variant_name = self.name();
309         f.add_block(
310             &format!("impl<R: Registers> From<{struct_name_r}> for Inst<R>"),
311             |f| {
312                 f.add_block(&format!("fn from(inst: {struct_name_r}) -> Self"), |f| {
313                     fmtln!(f, "Self::{variant_name}(inst)");
314                 });
315             },
316         );
317     }
318 }
319 
comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String320 fn comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String {
321     items.map(Into::into).collect::<Vec<_>>().join(", ")
322 }
323