cranelift_assembler_x64_meta/generate/
inst.rs1use super::{Formatter, fmtln, generate_derive, generate_derive_arbitrary_bounds};
2use crate::dsl;
3
4impl dsl::Inst {
5 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 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 fn generate_impl_block_start(&self) -> &str {
48 if self.requires_generic() {
49 "impl<R: Registers>"
50 } else {
51 "impl"
52 }
53 }
54
55 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 self.generate_xed_mnemonic_function(f);
64 f.empty_line();
65 self.generate_encode_function(f);
66 f.empty_line();
67 self.generate_visit_function(f);
68 f.empty_line();
69 self.generate_is_available_function(f);
70 f.empty_line();
71 self.generate_features_function(f);
72 f.empty_line();
73 self.generate_num_registers_function(f);
74 });
75 }
76
77 pub fn generate_new_function(&self, f: &mut Formatter) {
79 let params = comma_join(
80 self.format
81 .operands
82 .iter()
83 .map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type()))
84 .chain(if self.has_trap {
85 Some("trap: impl Into<TrapCode>".to_string())
86 } else {
87 None
88 }),
89 );
90 fmtln!(f, "#[must_use]");
91 f.add_block(&format!("pub fn new({params}) -> Self"), |f| {
92 f.add_block("Self", |f| {
93 for o in &self.format.operands {
94 let loc = o.location;
95 fmtln!(f, "{loc}: {loc}.into(),");
96 }
97 if self.has_trap {
98 fmtln!(f, "trap: trap.into(),");
99 }
100 });
101 });
102 }
103
104 pub fn generate_mnemonic_function(&self, f: &mut Formatter) {
106 use dsl::Customization::*;
107
108 fmtln!(f, "#[must_use]");
109 fmtln!(f, "#[inline]");
110 f.add_block(
111 &format!("pub fn mnemonic(&self) -> alloc::borrow::Cow<'static, str>"),
112 |f| {
113 if self.custom.contains(Mnemonic) {
114 fmtln!(f, "crate::custom::mnemonic::{}(self)", self.name());
115 } else {
116 fmtln!(f, "alloc::borrow::Cow::Borrowed(\"{}\")", self.mnemonic);
117 }
118 },
119 );
120 }
121
122 pub fn generate_xed_mnemonic_function(&self, f: &mut Formatter) {
129 let (reg, mem) = self.xed_mnemonics();
130 fmtln!(f, "#[must_use]");
131 fmtln!(f, "#[inline]");
132 f.add_block(
133 &format!("pub fn xed_mnemonic(&self) -> alloc::borrow::Cow<'static, str>"),
134 |f| {
135 let borrow = |m| format!("alloc::borrow::Cow::Borrowed(\"{m}\")");
136 let loc = self.format.uses_memory();
137 match loc {
138 Some(loc) if reg != mem && !loc.is_memory_only() => {
141 fmtln!(f, "if self.{loc}.is_memory() {{");
142 f.indent(|f| fmtln!(f, "{}", borrow(&mem)));
143 fmtln!(f, "}} else {{");
144 f.indent(|f| fmtln!(f, "{}", borrow(®)));
145 fmtln!(f, "}}");
146 }
147 Some(_) if reg != mem => fmtln!(f, "{}", borrow(&mem)),
148 _ => fmtln!(f, "{}", borrow(®)),
149 }
150 },
151 );
152 }
153
154 fn generate_encode_function(&self, f: &mut Formatter) {
156 use dsl::Customization::*;
157
158 f.add_block(
159 &format!("pub fn encode(&self, buf: &mut impl CodeSink)"),
160 |f| {
161 if self.custom.contains(Encode) {
162 fmtln!(f, "crate::custom::encode::{}(self, buf);", self.name());
163 } else {
164 self.generate_possible_trap(f);
165 match &self.encoding {
166 dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),
167 dsl::Encoding::Vex(vex) => self.format.generate_vex_encoding(f, vex),
168 dsl::Encoding::Evex(evex) => self.format.generate_evex_encoding(f, evex),
169 }
170 }
171 },
172 );
173 }
174
175 fn generate_possible_trap(&self, f: &mut Formatter) {
177 if self.has_trap {
178 f.comment("Emit trap.");
179 fmtln!(f, "buf.add_trap(self.trap);");
180 } else if let Some(op) = self.format.uses_memory() {
181 use dsl::OperandKind::*;
182 f.comment("Emit trap.");
183 match op.kind() {
184 Mem(_) => {
185 f.add_block(
186 &format!("if let Some(trap_code) = self.{op}.trap_code()"),
187 |f| {
188 fmtln!(f, "buf.add_trap(trap_code);");
189 },
190 );
191 }
192 RegMem(_) => {
193 let ty = op.reg_class().unwrap();
194 f.add_block(&format!("if let {ty}Mem::Mem({op}) = &self.{op}"), |f| {
195 f.add_block(&format!("if let Some(trap_code) = {op}.trap_code()"), |f| {
196 fmtln!(f, "buf.add_trap(trap_code);");
197 });
198 });
199 }
200 _ => unreachable!(),
201 }
202 }
203 }
204
205 fn generate_visit_function(&self, f: &mut Formatter) {
207 use dsl::{Customization::*, OperandKind::*};
208 let extra_generic_bound = if self.requires_generic() {
209 ""
210 } else {
211 "<R: Registers>"
212 };
213 let visitor = if self.format.operands.is_empty() && !self.custom.contains(Visit) {
214 "_"
215 } else {
216 "visitor"
217 };
218 f.add_block(&format!("pub fn visit{extra_generic_bound}(&mut self, {visitor}: &mut impl RegisterVisitor<R>)"), |f| {
219 if self.custom.contains(Visit) {
220 fmtln!(f, "crate::custom::visit::{}(self, visitor)", self.name());
221 return;
222 }
223 for o in &self.format.operands {
224 let mutability = o.mutability.generate_snake_case();
225 let reg = o.location.reg_class();
226 match o.location.kind() {
227 Imm(_) => {
228 fmtln!(f, "let _ = visitor;");
234 }
235 FixedReg(loc) => {
236 let reg_lower = reg.unwrap().to_string().to_lowercase();
237 fmtln!(f, "let enc = self.{loc}.expected_enc();");
238 fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");
239 }
240 Reg(loc) => {
241 let reg_lower = reg.unwrap().to_string().to_lowercase();
242 fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");
243 }
244 RegMem(loc) => {
245 let reg = reg.unwrap();
246 let reg_lower = reg.to_string().to_lowercase();
247 fmtln!(f, "visitor.{mutability}_{reg_lower}_mem(&mut self.{loc});");
248 }
249 Mem(loc) => {
250 fmtln!(f, "visitor.read_amode(&mut self.{loc});");
255 }
256
257 }
258 }
259 });
260 }
261
262 fn generate_is_available_function(&self, f: &mut Formatter) {
264 fmtln!(f, "#[must_use]");
265 f.add_block(
266 "pub fn is_available(&self, features: &impl AvailableFeatures) -> bool",
267 |f| {
268 let expr = self.features.generate_boolean_expr("features");
269 fmtln!(f, "{expr}");
270 },
271 );
272 }
273
274 fn generate_features_function(&self, f: &mut Formatter) {
276 fmtln!(f, "#[must_use]");
277 f.add_block("pub fn features(&self) -> &'static Features", |f| {
278 self.features.generate_constructor_expr(f);
279 });
280 }
281
282 fn generate_num_registers_function(&self, f: &mut Formatter) {
284 fmtln!(f, "#[must_use]");
285 f.add_block("pub fn num_registers_available(&self) -> usize", |f| {
286 use dsl::Encoding::*;
287 let n = match self.encoding {
288 Rex(_) | Vex(_) => 16,
289 Evex(_) => 32,
290 };
291 fmtln!(f, "{n}")
292 });
293 }
294
295 pub fn generate_display_impl(&self, f: &mut Formatter) {
297 use crate::dsl::Customization::*;
298 let impl_block = self.generate_impl_block_start();
299 let struct_name = self.struct_name_with_generic();
300 f.add_block(
301 &format!("{impl_block} core::fmt::Display for {struct_name}"),
302 |f| {
303 f.add_block(
304 "fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result",
305 |f| {
306 if self.custom.contains(Display) {
307 fmtln!(f, "crate::custom::display::{}(f, self)", self.name());
308 return;
309 }
310
311 fmtln!(f, "let name = if f.alternate() {{ self.xed_mnemonic() }} else {{ self.mnemonic() }};");
312 if self.format.operands.is_empty() {
313 fmtln!(f, "f.write_str(&name)");
314 return;
315 }
316 for op in self.format.operands.iter() {
317 let location = op.location;
318 let to_string = location.generate_to_string(op.extension);
319 match location.generate_to_string_xed(op.extension) {
320 Some(xed) => fmtln!(
321 f,
322 "let {location} = if f.alternate() {{ {xed} }} else {{ {to_string} }};"
323 ),
324 None => fmtln!(f, "let {location} = {to_string};"),
325 }
326 }
327 let ordered_ops = self.format.generate_att_style_operands();
328 let xed_ops = self.format.generate_xed_style_operands();
329 let mut implicit_ops = self.format.generate_implicit_operands();
330 if self.has_trap {
331 fmtln!(f, "let trap = self.trap;");
332 if implicit_ops.is_empty() {
333 implicit_ops.push_str(" ;; {trap}");
334 } else {
335 implicit_ops.push_str(", {trap}");
336 }
337 }
338 if implicit_ops.is_empty() && xed_ops == ordered_ops {
339 fmtln!(f, "write!(f, \"{{name}} {ordered_ops}\")");
340 } else {
341 fmtln!(f, "if f.alternate() {{");
345 f.indent(|f| fmtln!(f, "write!(f, \"{{name}} {xed_ops}\")"));
346 fmtln!(f, "}} else {{");
347 f.indent(|f| {
348 fmtln!(f, "write!(f, \"{{name}} {ordered_ops}{implicit_ops}\")")
349 });
350 fmtln!(f, "}}");
351 }
352 },
353 );
354 },
355 );
356 }
357
358 pub fn generate_from_impl(&self, f: &mut Formatter) {
360 let struct_name_r = self.struct_name_with_generic();
361 let variant_name = self.name();
362 f.add_block(
363 &format!("impl<R: Registers> From<{struct_name_r}> for Inst<R>"),
364 |f| {
365 f.add_block(&format!("fn from(inst: {struct_name_r}) -> Self"), |f| {
366 fmtln!(f, "Self::{variant_name}(inst)");
367 });
368 },
369 );
370 }
371}
372
373fn comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String {
374 items.map(Into::into).collect::<Vec<_>>().join(", ")
375}