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