cranelift_assembler_x64_meta/generate/
format.rs

1//! Generate format-related Rust code; this also includes generation of encoding
2//! Rust code.
3use super::{Formatter, fmtln};
4use crate::dsl;
5
6/// Different methods of emitting a ModR/M operand and encoding various bits and
7/// pieces of information into it. The REX/VEX formats plus the operand kinds
8/// dictate how exactly each instruction uses this, if at all.
9#[derive(Copy, Clone)]
10enum ModRmStyle {
11    /// This instruction does not use a ModR/M byte.
12    None,
13
14    /// The R/M bits are encoded with `rm` which is a `Gpr` or `Xmm` (it does
15    /// not have a "mem" possibility), and the Reg/Opcode bits are encoded
16    /// with `reg`.
17    Reg { reg: ModRmReg, rm: dsl::Location },
18
19    /// The R/M bits are encoded with `rm` which is a `GprMem` or `XmmMem`, and
20    /// the Reg/Opcode bits are encoded with `reg`.
21    RegMem {
22        reg: ModRmReg,
23        rm: dsl::Location,
24        evex_scaling: Option<i8>,
25    },
26
27    /// Same as `RegMem` above except that this is also used for VEX-encoded
28    /// instructios with "/is4" which indicates that the 4th register operand
29    /// is encoded in a byte after the ModR/M byte.
30    RegMemIs4 {
31        reg: ModRmReg,
32        rm: dsl::Location,
33        is4: dsl::Location,
34        evex_scaling: Option<i8>,
35    },
36}
37
38/// Different methods of encoding the Reg/Opcode bits in a ModR/M byte.
39#[derive(Copy, Clone)]
40enum ModRmReg {
41    /// A static set of bits is used.
42    Digit(u8),
43    /// A runtime-defined register is used with this field name.
44    Reg(dsl::Location),
45}
46
47impl dsl::Format {
48    /// Re-order the Intel-style operand order to accommodate ATT-style
49    /// printing.
50    ///
51    /// This is an unfortunate necessity to match Cranelift's current
52    /// disassembly, which uses AT&T-style printing. The plan is to eventually
53    /// transition to Intel-style printing (and avoid this awkward reordering)
54    /// once Cranelift has switched to using this assembler predominantly
55    /// (TODO).
56    #[must_use]
57    pub(crate) fn generate_att_style_operands(&self) -> String {
58        let ordered_ops: Vec<_> = self
59            .operands
60            .iter()
61            .filter(|o| !o.implicit)
62            .rev()
63            .map(|o| format!("{{{}}}", o.location))
64            .collect();
65        ordered_ops.join(", ")
66    }
67
68    #[must_use]
69    pub(crate) fn generate_implicit_operands(&self) -> String {
70        let ops: Vec<_> = self
71            .operands
72            .iter()
73            .filter(|o| o.implicit)
74            .map(|o| format!("{{{}}}", o.location))
75            .collect();
76        if ops.is_empty() {
77            String::new()
78        } else {
79            format!(" ;; implicit: {}", ops.join(", "))
80        }
81    }
82
83    pub(crate) fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {
84        self.generate_prefixes(f, rex);
85        let style = self.generate_rex_prefix(f, rex);
86        rex.generate_opcodes(f, self.locations().next());
87        self.generate_modrm_byte(f, style);
88        self.generate_immediate(f, style);
89    }
90
91    pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {
92        let style = self.generate_vex_prefix(f, vex);
93        vex.generate_opcode(f);
94        self.generate_modrm_byte(f, style);
95        self.generate_immediate(f, style);
96    }
97
98    pub fn generate_evex_encoding(&self, f: &mut Formatter, evex: &dsl::Evex) {
99        let style = self.generate_evex_prefix(f, evex);
100        evex.generate_opcode(f);
101        self.generate_modrm_byte(f, style);
102        self.generate_immediate(f, style);
103    }
104
105    /// `buf.put1(...);`
106    fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {
107        if !rex.opcodes.prefixes.is_empty() {
108            f.empty_line();
109            f.comment("Emit prefixes.");
110        }
111        if let Some(group1) = &rex.opcodes.prefixes.group1 {
112            fmtln!(f, "buf.put1({group1});");
113        }
114        if let Some(group2) = &rex.opcodes.prefixes.group2 {
115            fmtln!(f, "buf.put1({group2});");
116        }
117        if let Some(group3) = &rex.opcodes.prefixes.group3 {
118            fmtln!(f, "buf.put1({group3});");
119        }
120        if let Some(group4) = &rex.opcodes.prefixes.group4 {
121            fmtln!(f, "buf.put1({group4});");
122        }
123    }
124
125    fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle {
126        use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
127
128        // If this instruction has only immediates there's no rex/modrm/etc, so
129        // skip everything below.
130        match self.operands_by_kind().as_slice() {
131            [] | [Imm(_)] => return ModRmStyle::None,
132            _ => {}
133        }
134
135        f.empty_line();
136        f.comment("Possibly emit REX prefix.");
137
138        let find_8bit_registers =
139            |l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
140        let uses_8bit = self.locations().any(find_8bit_registers);
141        fmtln!(f, "let uses_8bit = {uses_8bit};");
142        fmtln!(f, "let w_bit = {};", rex.w.as_bool());
143        let bits = "w_bit, uses_8bit";
144
145        let style = match self.operands_by_kind().as_slice() {
146            [FixedReg(dst), FixedReg(_)] | [FixedReg(dst)] | [FixedReg(dst), Imm(_)] => {
147                // TODO: don't emit REX byte here.
148                assert_eq!(rex.unwrap_digit(), None);
149                fmtln!(f, "let digit = 0;");
150                fmtln!(f, "let dst = self.{dst}.enc();");
151                fmtln!(f, "let rex = RexPrefix::with_digit(digit, dst, {bits});");
152                ModRmStyle::None
153            }
154            [Reg(dst)] => {
155                assert_eq!(rex.unwrap_digit(), None);
156                assert!(rex.opcode_mod.is_some());
157                fmtln!(f, "let dst = self.{dst}.enc();");
158                fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
159                ModRmStyle::None
160            }
161            [Reg(dst), Imm(_)] => match rex.unwrap_digit() {
162                Some(digit) => {
163                    fmtln!(f, "let digit = 0x{digit:x};");
164                    fmtln!(f, "let dst = self.{dst}.enc();");
165                    fmtln!(f, "let rex = RexPrefix::two_op(digit, dst, {bits});");
166                    ModRmStyle::Reg {
167                        reg: ModRmReg::Digit(digit),
168                        rm: *dst,
169                    }
170                }
171                None => {
172                    assert!(rex.opcode_mod.is_some());
173                    fmtln!(f, "let dst = self.{dst}.enc();");
174                    fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
175                    ModRmStyle::None
176                }
177            },
178            [FixedReg(_), RegMem(mem)]
179            | [FixedReg(_), FixedReg(_), RegMem(mem)]
180            | [RegMem(mem), FixedReg(_)]
181            | [Mem(mem), Imm(_)]
182            | [RegMem(mem), Imm(_)]
183            | [RegMem(mem)]
184            | [FixedReg(_), FixedReg(_), FixedReg(_), FixedReg(_), Mem(mem)] => {
185                let digit = rex.unwrap_digit().unwrap();
186                fmtln!(f, "let digit = 0x{digit:x};");
187                fmtln!(f, "let rex = self.{mem}.as_rex_prefix(digit, {bits});");
188                ModRmStyle::RegMem {
189                    reg: ModRmReg::Digit(digit),
190                    rm: *mem,
191                    evex_scaling: None,
192                }
193            }
194            [Reg(reg), RegMem(mem) | Mem(mem)]
195            | [Reg(reg), RegMem(mem), Imm(_) | FixedReg(_)]
196            | [RegMem(mem) | Mem(mem), Reg(reg)]
197            | [RegMem(mem) | Mem(mem), Reg(reg), Imm(_) | FixedReg(_)] => {
198                fmtln!(f, "let reg = self.{reg}.enc();");
199                fmtln!(f, "let rex = self.{mem}.as_rex_prefix(reg, {bits});");
200                ModRmStyle::RegMem {
201                    reg: ModRmReg::Reg(*reg),
202                    rm: *mem,
203                    evex_scaling: None,
204                }
205            }
206            [Reg(dst), Reg(src), Imm(_)] | [Reg(dst), Reg(src)] => {
207                fmtln!(f, "let reg = self.{dst}.enc();");
208                fmtln!(f, "let rm = self.{src}.enc();");
209                fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");
210                ModRmStyle::Reg {
211                    reg: ModRmReg::Reg(*dst),
212                    rm: *src,
213                }
214            }
215
216            unknown => unimplemented!("unknown pattern: {unknown:?}"),
217        };
218
219        fmtln!(f, "rex.encode(buf);");
220        style
221    }
222
223    fn generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle {
224        f.empty_line();
225        f.comment("Emit VEX prefix.");
226        fmtln!(f, "let len = {:#03b};", vex.length.vex_bits());
227        fmtln!(f, "let pp = {:#04b};", vex.pp.map_or(0b00, |pp| pp.bits()));
228        fmtln!(f, "let mmmmm = {:#07b};", vex.mmmmm.unwrap().bits());
229        fmtln!(f, "let w = {};", vex.w.as_bool());
230        let bits = "len, pp, mmmmm, w";
231
232        self.generate_vex_or_evex_prefix(f, "VexPrefix", &bits, vex.is4, None, || {
233            vex.unwrap_digit()
234        })
235    }
236
237    fn generate_evex_prefix(&self, f: &mut Formatter, evex: &dsl::Evex) -> ModRmStyle {
238        f.empty_line();
239        f.comment("Emit EVEX prefix.");
240        let ll = evex.length.evex_bits();
241        fmtln!(f, "let ll = {ll:#04b};");
242        fmtln!(f, "let pp = {:#04b};", evex.pp.map_or(0b00, |pp| pp.bits()));
243        fmtln!(f, "let mmm = {:#07b};", evex.mmm.unwrap().bits());
244        fmtln!(f, "let w = {};", evex.w.as_bool());
245        // NB: when bcast is supported in the future the `evex_scaling`
246        // calculation for `Full` and `Half` below need to be updated.
247        let bcast = false;
248        fmtln!(f, "let bcast = {bcast};");
249        let bits = format!("ll, pp, mmm, w, bcast");
250        let is4 = false;
251
252        let length_bytes = match evex.length {
253            dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
254            dsl::Length::L128 => 16,
255            dsl::Length::L256 => 32,
256            dsl::Length::L512 => 64,
257        };
258
259        // Figure out, according to table 2-34 and 2-35 in the Intel manual,
260        // what the scaling factor is for 8-bit displacements to pass through to
261        // encoding.
262        let evex_scaling = Some(match evex.tuple_type {
263            dsl::TupleType::Full => {
264                assert!(!bcast);
265                length_bytes
266            }
267            dsl::TupleType::Half => {
268                assert!(!bcast);
269                length_bytes / 2
270            }
271            dsl::TupleType::FullMem => length_bytes,
272            // FIXME: according to table 2-35 this needs to take into account
273            // "InputSize" which isn't accounted for in our `Evex` structure at
274            // this time.
275            dsl::TupleType::Tuple1Scalar => unimplemented!(),
276            dsl::TupleType::Tuple1Fixed => unimplemented!(),
277            dsl::TupleType::Tuple2 => unimplemented!(),
278            dsl::TupleType::Tuple4 => unimplemented!(),
279            dsl::TupleType::Tuple8 => 32,
280            dsl::TupleType::HalfMem => length_bytes / 2,
281            dsl::TupleType::QuarterMem => length_bytes / 4,
282            dsl::TupleType::EigthMem => length_bytes / 8,
283            dsl::TupleType::Mem128 => 16,
284            dsl::TupleType::Movddup => match evex.length {
285                dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
286                dsl::Length::L128 => 8,
287                dsl::Length::L256 => 32,
288                dsl::Length::L512 => 64,
289            },
290        });
291
292        self.generate_vex_or_evex_prefix(f, "EvexPrefix", &bits, is4, evex_scaling, || {
293            evex.unwrap_digit()
294        })
295    }
296
297    /// Helper function to generate either a vex or evex prefix, mostly handling
298    /// all the operand formats and structures here the same between the two
299    /// forms.
300    fn generate_vex_or_evex_prefix(
301        &self,
302        f: &mut Formatter,
303        prefix_type: &str,
304        bits: &str,
305        is4: bool,
306        evex_scaling: Option<i8>,
307        unwrap_digit: impl Fn() -> Option<u8>,
308    ) -> ModRmStyle {
309        use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
310
311        let style = match self.operands_by_kind().as_slice() {
312            [Reg(reg), Reg(vvvv), Reg(rm)] => {
313                assert!(!is4);
314                fmtln!(f, "let reg = self.{reg}.enc();");
315                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
316                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
317                fmtln!(
318                    f,
319                    "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
320                );
321                ModRmStyle::Reg {
322                    reg: ModRmReg::Reg(*reg),
323                    rm: *rm,
324                }
325            }
326            [Reg(reg), Reg(vvvv), RegMem(rm)]
327            | [Reg(reg), Reg(vvvv), Mem(rm)]
328            | [Reg(reg), Reg(vvvv), RegMem(rm), Imm(_) | FixedReg(_)]
329            | [Reg(reg), RegMem(rm), Reg(vvvv)] => {
330                assert!(!is4);
331                fmtln!(f, "let reg = self.{reg}.enc();");
332                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
333                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
334                fmtln!(
335                    f,
336                    "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
337                );
338                ModRmStyle::RegMem {
339                    reg: ModRmReg::Reg(*reg),
340                    rm: *rm,
341                    evex_scaling,
342                }
343            }
344            [Reg(reg), Reg(vvvv), RegMem(rm), Reg(r_is4)] => {
345                assert!(is4);
346                fmtln!(f, "let reg = self.{reg}.enc();");
347                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
348                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
349                fmtln!(
350                    f,
351                    "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
352                );
353                ModRmStyle::RegMemIs4 {
354                    reg: ModRmReg::Reg(*reg),
355                    rm: *rm,
356                    is4: *r_is4,
357                    evex_scaling,
358                }
359            }
360            [Reg(reg_or_vvvv), RegMem(rm)]
361            | [RegMem(rm), Reg(reg_or_vvvv)]
362            | [Reg(reg_or_vvvv), RegMem(rm), Imm(_)] => match unwrap_digit() {
363                Some(digit) => {
364                    assert!(!is4);
365                    let vvvv = reg_or_vvvv;
366                    fmtln!(f, "let reg = {digit:#x};");
367                    fmtln!(f, "let vvvv = self.{vvvv}.enc();");
368                    fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
369                    fmtln!(
370                        f,
371                        "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
372                    );
373                    ModRmStyle::RegMem {
374                        reg: ModRmReg::Digit(digit),
375                        rm: *rm,
376                        evex_scaling,
377                    }
378                }
379                None => {
380                    assert!(!is4);
381                    let reg = reg_or_vvvv;
382                    fmtln!(f, "let reg = self.{reg}.enc();");
383                    fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
384                    fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
385                    ModRmStyle::RegMem {
386                        reg: ModRmReg::Reg(*reg),
387                        rm: *rm,
388                        evex_scaling,
389                    }
390                }
391            },
392            [Reg(reg_or_vvvv), Reg(rm)] | [Reg(reg_or_vvvv), Reg(rm), Imm(_)] => {
393                match unwrap_digit() {
394                    Some(digit) => {
395                        assert!(!is4);
396                        let vvvv = reg_or_vvvv;
397                        fmtln!(f, "let reg = {digit:#x};");
398                        fmtln!(f, "let vvvv = self.{vvvv}.enc();");
399                        fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
400                        fmtln!(
401                            f,
402                            "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
403                        );
404                        ModRmStyle::Reg {
405                            reg: ModRmReg::Digit(digit),
406                            rm: *rm,
407                        }
408                    }
409                    None => {
410                        assert!(!is4);
411                        let reg = reg_or_vvvv;
412                        fmtln!(f, "let reg = self.{reg}.enc();");
413                        fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
414                        fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
415                        ModRmStyle::Reg {
416                            reg: ModRmReg::Reg(*reg),
417                            rm: *rm,
418                        }
419                    }
420                }
421            }
422            [Reg(reg), Mem(rm)] | [Mem(rm), Reg(reg)] | [RegMem(rm), Reg(reg), Imm(_)] => {
423                assert!(!is4);
424                fmtln!(f, "let reg = self.{reg}.enc();");
425                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
426                fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
427                ModRmStyle::RegMem {
428                    reg: ModRmReg::Reg(*reg),
429                    rm: *rm,
430                    evex_scaling,
431                }
432            }
433            unknown => unimplemented!("unknown pattern: {unknown:?}"),
434        };
435
436        fmtln!(f, "prefix.encode(buf);");
437        style
438    }
439
440    fn generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
441        let operands = self.operands_by_kind();
442        let bytes_at_end = match operands.as_slice() {
443            [.., dsl::OperandKind::Imm(imm)] => imm.bytes(),
444            _ => match modrm_style {
445                ModRmStyle::RegMemIs4 { .. } => 1,
446                _ => 0,
447            },
448        };
449
450        f.empty_line();
451
452        match modrm_style {
453            ModRmStyle::None => f.comment("No need to emit a ModRM byte."),
454            _ => f.comment("Emit ModR/M byte."),
455        }
456
457        match modrm_style {
458            ModRmStyle::None => {}
459            ModRmStyle::RegMem {
460                reg,
461                rm,
462                evex_scaling,
463            }
464            | ModRmStyle::RegMemIs4 {
465                reg,
466                rm,
467                is4: _,
468                evex_scaling,
469            } => {
470                match reg {
471                    ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
472                    ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
473                }
474                fmtln!(
475                    f,
476                    "self.{rm}.encode_rex_suffixes(buf, reg, {bytes_at_end}, {evex_scaling:?});"
477                );
478            }
479            ModRmStyle::Reg { reg, rm } => {
480                match reg {
481                    ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
482                    ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
483                }
484                fmtln!(f, "self.{rm}.encode_modrm(buf, reg);");
485            }
486        }
487    }
488
489    fn generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
490        use dsl::OperandKind::Imm;
491        match self.operands_by_kind().as_slice() {
492            [prefix @ .., Imm(imm)] => {
493                assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));
494                f.empty_line();
495                f.comment("Emit immediate.");
496                fmtln!(f, "self.{imm}.encode(buf);");
497            }
498            unknown => {
499                if let ModRmStyle::RegMemIs4 { is4, .. } = modrm_style {
500                    fmtln!(f, "buf.put1(self.{is4}.enc() << 4);");
501                }
502
503                // Do nothing: no immediates expected.
504                assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));
505            }
506        }
507    }
508}
509
510impl dsl::Rex {
511    // `buf.put1(...);`
512    fn generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>) {
513        f.empty_line();
514        f.comment("Emit opcode(s).");
515        if self.opcodes.escape {
516            fmtln!(f, "buf.put1(0x0f);");
517        }
518        if self.opcode_mod.is_some() {
519            let first_op = first_op.expect("Expected first operand for opcode_mod");
520            assert!(matches!(first_op.kind(), dsl::OperandKind::Reg(_)));
521            fmtln!(f, "let low_bits = self.{first_op}.enc() & 0b111;");
522            fmtln!(f, "buf.put1(0x{:x} | low_bits);", self.opcodes.primary);
523        } else {
524            fmtln!(f, "buf.put1(0x{:x});", self.opcodes.primary);
525        }
526        if let Some(secondary) = self.opcodes.secondary {
527            fmtln!(f, "buf.put1(0x{:x});", secondary);
528        }
529    }
530}
531
532impl dsl::Vex {
533    // `buf.put1(...);`
534    fn generate_opcode(&self, f: &mut Formatter) {
535        f.empty_line();
536        f.comment("Emit opcode.");
537        fmtln!(f, "buf.put1(0x{:x});", self.opcode);
538    }
539}
540
541impl dsl::Evex {
542    // `buf.put1(...);`
543    fn generate_opcode(&self, f: &mut Formatter) {
544        f.empty_line();
545        f.comment("Emit opcode.");
546        fmtln!(f, "buf.put1(0x{:x});", self.opcode);
547    }
548}