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