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