cranelift_assembler_x64_meta/generate/
inst.rs

1use super::{fmtln, generate_derive, generate_derive_arbitrary_bounds, Formatter};
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    }
27
28    fn requires_generic(&self) -> bool {
29        self.format.uses_register()
30    }
31
32    /// `<struct_name><R>`
33    pub(crate) fn struct_name_with_generic(&self) -> String {
34        let struct_name = self.name();
35        if self.requires_generic() {
36            format!("{struct_name}<R>")
37        } else {
38            struct_name
39        }
40    }
41
42    /// `impl...`
43    fn generate_impl_block_start(&self) -> &str {
44        if self.requires_generic() {
45            "impl<R: Registers>"
46        } else {
47            "impl"
48        }
49    }
50
51    /// `impl <inst> { ... }`
52    pub fn generate_struct_impl(&self, f: &mut Formatter) {
53        let impl_block = self.generate_impl_block_start();
54        let struct_name = self.struct_name_with_generic();
55        f.add_block(&format!("{impl_block} {struct_name}"), |f| {
56            self.generate_new_function(f);
57            f.empty_line();
58            self.generate_encode_function(f);
59            f.empty_line();
60            self.generate_visit_function(f);
61            f.empty_line();
62            self.generate_features_function(f);
63        });
64    }
65
66    // `fn new(<params>) -> Self { ... }`
67    pub fn generate_new_function(&self, f: &mut Formatter) {
68        let params = comma_join(
69            self.format
70                .operands
71                .iter()
72                .map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type())),
73        );
74        fmtln!(f, "#[must_use]");
75        f.add_block(&format!("pub fn new({params}) -> Self"), |f| {
76            f.add_block("Self", |f| {
77                for o in &self.format.operands {
78                    let loc = o.location;
79                    fmtln!(f, "{loc}: {loc}.into(),");
80                }
81            });
82        });
83    }
84
85    /// `fn encode(&self, ...) { ... }`
86    fn generate_encode_function(&self, f: &mut Formatter) {
87        let off = if self.format.uses_memory().is_some() {
88            "off"
89        } else {
90            "_"
91        };
92        f.add_block(
93            &format!(
94                "pub fn encode(&self, buf: &mut impl CodeSink, {off}: &impl KnownOffsetTable)"
95            ),
96            |f| {
97                // Emit trap.
98                if let Some(op) = self.format.uses_memory() {
99                    use dsl::OperandKind::*;
100                    f.comment("Emit trap.");
101                    match op.kind() {
102                        Mem(_) => {
103                            f.add_block(
104                                &format!("if let Some(trap_code) = self.{op}.trap_code()"),
105                                |f| {
106                                    fmtln!(f, "buf.add_trap(trap_code);");
107                                },
108                            );
109                        }
110                        RegMem(_) => {
111                            let ty = op.reg_class().unwrap();
112                            f.add_block(&format!("if let {ty}Mem::Mem({op}) = &self.{op}"), |f| {
113                                f.add_block(
114                                    &format!("if let Some(trap_code) = {op}.trap_code()"),
115                                    |f| {
116                                        fmtln!(f, "buf.add_trap(trap_code);");
117                                    },
118                                );
119                            });
120                        }
121                        _ => unreachable!(),
122                    }
123                }
124
125                match &self.encoding {
126                    dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),
127                    dsl::Encoding::Vex(_) => todo!(),
128                }
129            },
130        );
131    }
132
133    /// `fn visit(&self, ...) { ... }`
134    fn generate_visit_function(&self, f: &mut Formatter) {
135        use dsl::OperandKind::*;
136        let extra_generic_bound = if self.requires_generic() {
137            ""
138        } else {
139            "<R: Registers>"
140        };
141        f.add_block(&format!("pub fn visit{extra_generic_bound}(&mut self, visitor: &mut impl RegisterVisitor<R>)"), |f| {
142            for o in &self.format.operands {
143                let mutability = o.mutability.generate_snake_case();
144                let reg = o.location.reg_class();
145                match o.location.kind() {
146                    Imm(_) => {
147                        // Immediates do not need register allocation.
148                    }
149                    FixedReg(loc) => {
150                        let reg_lower = reg.unwrap().to_string().to_lowercase();
151                        fmtln!(f, "let enc = self.{loc}.expected_enc();");
152                        fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");
153                    }
154                    Reg(loc) => {
155                        let reg_lower = reg.unwrap().to_string().to_lowercase();
156                        fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");
157                    }
158                    RegMem(loc) => {
159                        let reg = reg.unwrap();
160                        let reg_lower = reg.to_string().to_lowercase();
161                        f.add_block(&format!("match &mut self.{loc}"), |f| {
162                            fmtln!(f, "{reg}Mem::{reg}(r) => visitor.{mutability}_{reg_lower}(r),");
163                            fmtln!(f, "{reg}Mem::Mem(m) => visit_amode(m, visitor),");
164                        });
165                    }
166                    Mem(loc) => {
167                        fmtln!(f, "visit_amode(&mut self.{loc}, visitor);");
168                    }
169                }
170            }
171        });
172    }
173
174    /// `fn features(&self) -> Vec<Flag> { ... }`
175    fn generate_features_function(&self, f: &mut Formatter) {
176        fmtln!(f, "#[must_use]");
177        f.add_block("pub fn features(&self) -> Vec<Feature>", |f| {
178            let flags = self
179                .features
180                .iter()
181                .map(|f| format!("Feature::{f}"))
182                .collect::<Vec<_>>();
183            fmtln!(f, "vec![{}]", flags.join(", "));
184        });
185    }
186
187    /// `impl Display for <inst> { ... }`
188    pub fn generate_display_impl(&self, f: &mut Formatter) {
189        let impl_block = self.generate_impl_block_start();
190        let struct_name = self.struct_name_with_generic();
191        f.add_block(
192            &format!("{impl_block} std::fmt::Display for {struct_name}"),
193            |f| {
194                f.add_block(
195                    "fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result",
196                    |f| {
197                        for op in &self.format.operands {
198                            let location = op.location;
199                            let to_string = location.generate_to_string(op.extension);
200                            fmtln!(f, "let {location} = {to_string};");
201                        }
202                        // Fix up the mnemonic for locked instructions: we want to print
203                        // "lock <inst>", not "lock_<inst>".
204                        let inst_name = if self.mnemonic.starts_with("lock_") {
205                            &format!("lock {}", &self.mnemonic[5..])
206                        } else {
207                            &self.mnemonic
208                        };
209                        let ordered_ops = self.format.generate_att_style_operands();
210                        fmtln!(f, "write!(f, \"{inst_name} {ordered_ops}\")");
211                    },
212                );
213            },
214        );
215    }
216
217    /// `impl From<struct> for Inst { ... }`
218    pub fn generate_from_impl(&self, f: &mut Formatter) {
219        let struct_name_r = self.struct_name_with_generic();
220        let variant_name = self.name();
221        f.add_block(
222            &format!("impl<R: Registers> From<{struct_name_r}> for Inst<R>"),
223            |f| {
224                f.add_block(&format!("fn from(inst: {struct_name_r}) -> Self"), |f| {
225                    fmtln!(f, "Self::{variant_name}(inst)");
226                });
227            },
228        );
229    }
230}
231
232fn comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String {
233    items.map(Into::into).collect::<Vec<_>>().join(", ")
234}