cranelift_assembler_x64_meta/generate/
inst.rs

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