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 { reg: ModRmReg, rm: dsl::Location },
22
23    /// Same as `RegMem` above except that this is also used for VEX-encoded
24    /// instructios with "/is4" which indicates that the 4th register operand
25    /// is encoded in a byte after the ModR/M byte.
26    RegMemIs4 {
27        reg: ModRmReg,
28        rm: dsl::Location,
29        is4: dsl::Location,
30    },
31}
32
33/// Different methods of encoding the Reg/Opcode bits in a ModR/M byte.
34#[derive(Copy, Clone)]
35enum ModRmReg {
36    /// A static set of bits is used.
37    Digit(u8),
38    /// A runtime-defined register is used with this field name.
39    Reg(dsl::Location),
40}
41
42impl dsl::Format {
43    /// Re-order the Intel-style operand order to accommodate ATT-style
44    /// printing.
45    ///
46    /// This is an unfortunate necessity to match Cranelift's current
47    /// disassembly, which uses AT&T-style printing. The plan is to eventually
48    /// transition to Intel-style printing (and avoid this awkward reordering)
49    /// once Cranelift has switched to using this assembler predominantly
50    /// (TODO).
51    #[must_use]
52    pub(crate) fn generate_att_style_operands(&self) -> String {
53        let ordered_ops: Vec<_> = self
54            .operands
55            .iter()
56            .filter(|o| !o.implicit)
57            .rev()
58            .map(|o| format!("{{{}}}", o.location))
59            .collect();
60        ordered_ops.join(", ")
61    }
62
63    #[must_use]
64    pub(crate) fn generate_implicit_operands(&self) -> String {
65        let ops: Vec<_> = self
66            .operands
67            .iter()
68            .filter(|o| o.implicit)
69            .map(|o| format!("{{{}}}", o.location))
70            .collect();
71        if ops.is_empty() {
72            String::new()
73        } else {
74            format!(" ;; implicit: {}", ops.join(", "))
75        }
76    }
77
78    pub(crate) fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {
79        self.generate_prefixes(f, rex);
80        let style = self.generate_rex_prefix(f, rex);
81        rex.generate_opcodes(f, self.locations().next());
82        self.generate_modrm_byte(f, style);
83        self.generate_immediate(f, style);
84    }
85
86    pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {
87        let style = self.generate_vex_prefix(f, vex);
88        vex.generate_opcode(f);
89        self.generate_modrm_byte(f, style);
90        self.generate_immediate(f, style);
91    }
92
93    /// `buf.put1(...);`
94    fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {
95        if !rex.opcodes.prefixes.is_empty() {
96            f.empty_line();
97            f.comment("Emit prefixes.");
98        }
99        if let Some(group1) = &rex.opcodes.prefixes.group1 {
100            fmtln!(f, "buf.put1({group1});");
101        }
102        if let Some(group2) = &rex.opcodes.prefixes.group2 {
103            fmtln!(f, "buf.put1({group2});");
104        }
105        if let Some(group3) = &rex.opcodes.prefixes.group3 {
106            fmtln!(f, "buf.put1({group3});");
107        }
108        if let Some(group4) = &rex.opcodes.prefixes.group4 {
109            fmtln!(f, "buf.put1({group4});");
110        }
111    }
112
113    fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle {
114        use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
115
116        // If this instruction has only immediates there's no rex/modrm/etc, so
117        // skip everything below.
118        match self.operands_by_kind().as_slice() {
119            [] | [Imm(_)] => return ModRmStyle::None,
120            _ => {}
121        }
122
123        f.empty_line();
124        f.comment("Possibly emit REX prefix.");
125
126        let find_8bit_registers =
127            |l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
128        let uses_8bit = self.locations().any(find_8bit_registers);
129        fmtln!(f, "let uses_8bit = {uses_8bit};");
130        fmtln!(f, "let w_bit = {};", rex.w);
131        let bits = "w_bit, uses_8bit";
132
133        let style = match self.operands_by_kind().as_slice() {
134            [FixedReg(dst), FixedReg(_)] | [FixedReg(dst)] | [FixedReg(dst), Imm(_)] => {
135                // TODO: don't emit REX byte here.
136                assert_eq!(rex.unwrap_digit(), None);
137                fmtln!(f, "let digit = 0;");
138                fmtln!(f, "let dst = self.{dst}.enc();");
139                fmtln!(f, "let rex = RexPrefix::with_digit(digit, dst, {bits});");
140                ModRmStyle::None
141            }
142            [Reg(dst)] => {
143                assert_eq!(rex.unwrap_digit(), None);
144                assert!(rex.opcode_mod.is_some());
145                fmtln!(f, "let dst = self.{dst}.enc();");
146                fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
147                ModRmStyle::None
148            }
149            [Reg(dst), Imm(_)] => match rex.unwrap_digit() {
150                Some(digit) => {
151                    fmtln!(f, "let digit = 0x{digit:x};");
152                    fmtln!(f, "let dst = self.{dst}.enc();");
153                    fmtln!(f, "let rex = RexPrefix::two_op(digit, dst, {bits});");
154                    ModRmStyle::Reg {
155                        reg: ModRmReg::Digit(digit),
156                        rm: *dst,
157                    }
158                }
159                None => {
160                    assert!(rex.opcode_mod.is_some());
161                    fmtln!(f, "let dst = self.{dst}.enc();");
162                    fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
163                    ModRmStyle::None
164                }
165            },
166            [FixedReg(_), RegMem(mem)]
167            | [FixedReg(_), FixedReg(_), RegMem(mem)]
168            | [RegMem(mem), FixedReg(_)]
169            | [Mem(mem), Imm(_)]
170            | [RegMem(mem), Imm(_)]
171            | [RegMem(mem)]
172            | [FixedReg(_), FixedReg(_), FixedReg(_), FixedReg(_), Mem(mem)] => {
173                let digit = rex.unwrap_digit().unwrap();
174                fmtln!(f, "let digit = 0x{digit:x};");
175                fmtln!(f, "let rex = self.{mem}.as_rex_prefix(digit, {bits});");
176                ModRmStyle::RegMem {
177                    reg: ModRmReg::Digit(digit),
178                    rm: *mem,
179                }
180            }
181            [Reg(reg), RegMem(mem) | Mem(mem)]
182            | [Reg(reg), RegMem(mem), Imm(_) | FixedReg(_)]
183            | [RegMem(mem) | Mem(mem), Reg(reg)]
184            | [RegMem(mem) | Mem(mem), Reg(reg), Imm(_) | FixedReg(_)] => {
185                fmtln!(f, "let reg = self.{reg}.enc();");
186                fmtln!(f, "let rex = self.{mem}.as_rex_prefix(reg, {bits});");
187                ModRmStyle::RegMem {
188                    reg: ModRmReg::Reg(*reg),
189                    rm: *mem,
190                }
191            }
192            [Reg(dst), Reg(src), Imm(_)] | [Reg(dst), Reg(src)] => {
193                fmtln!(f, "let reg = self.{dst}.enc();");
194                fmtln!(f, "let rm = self.{src}.enc();");
195                fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");
196                ModRmStyle::Reg {
197                    reg: ModRmReg::Reg(*dst),
198                    rm: *src,
199                }
200            }
201
202            unknown => unimplemented!("unknown pattern: {unknown:?}"),
203        };
204
205        fmtln!(f, "rex.encode(buf);");
206        style
207    }
208
209    fn generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle {
210        use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
211
212        f.empty_line();
213        f.comment("Emit VEX prefix.");
214        fmtln!(f, "let len = {:#03b};", vex.length.bits());
215        fmtln!(f, "let pp = {:#04b};", vex.pp.map_or(0b00, |pp| pp.bits()));
216        fmtln!(f, "let mmmmm = {:#07b};", vex.mmmmm.unwrap().bits());
217        fmtln!(f, "let w = {};", vex.w.as_bool());
218        let bits = "len, pp, mmmmm, w";
219
220        let style = match self.operands_by_kind().as_slice() {
221            [Reg(reg), Reg(vvvv), Reg(rm)] => {
222                assert!(!vex.is4);
223                fmtln!(f, "let reg = self.{reg}.enc();");
224                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
225                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
226                fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
227                ModRmStyle::Reg {
228                    reg: ModRmReg::Reg(*reg),
229                    rm: *rm,
230                }
231            }
232            [Reg(reg), Reg(vvvv), RegMem(rm)]
233            | [Reg(reg), Reg(vvvv), Mem(rm)]
234            | [Reg(reg), Reg(vvvv), RegMem(rm), Imm(_) | FixedReg(_)]
235            | [Reg(reg), RegMem(rm), Reg(vvvv)] => {
236                assert!(!vex.is4);
237                fmtln!(f, "let reg = self.{reg}.enc();");
238                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
239                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
240                fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
241                ModRmStyle::RegMem {
242                    reg: ModRmReg::Reg(*reg),
243                    rm: *rm,
244                }
245            }
246            [Reg(reg), Reg(vvvv), RegMem(rm), Reg(is4)] => {
247                assert!(vex.is4);
248                fmtln!(f, "let reg = self.{reg}.enc();");
249                fmtln!(f, "let vvvv = self.{vvvv}.enc();");
250                fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
251                fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
252                ModRmStyle::RegMemIs4 {
253                    reg: ModRmReg::Reg(*reg),
254                    rm: *rm,
255                    is4: *is4,
256                }
257            }
258            [Reg(reg_or_vvvv), RegMem(rm)]
259            | [RegMem(rm), Reg(reg_or_vvvv)]
260            | [Reg(reg_or_vvvv), RegMem(rm), Imm(_)] => match vex.unwrap_digit() {
261                Some(digit) => {
262                    assert!(!vex.is4);
263                    let vvvv = reg_or_vvvv;
264                    fmtln!(f, "let reg = {digit:#x};");
265                    fmtln!(f, "let vvvv = self.{vvvv}.enc();");
266                    fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
267                    fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
268                    ModRmStyle::RegMem {
269                        reg: ModRmReg::Digit(digit),
270                        rm: *rm,
271                    }
272                }
273                None => {
274                    assert!(!vex.is4);
275                    let reg = reg_or_vvvv;
276                    fmtln!(f, "let reg = self.{reg}.enc();");
277                    fmtln!(f, "let vvvv = {};", "0b0");
278                    fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
279                    fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
280                    ModRmStyle::RegMem {
281                        reg: ModRmReg::Reg(*reg),
282                        rm: *rm,
283                    }
284                }
285            },
286            [Reg(reg), Reg(rm)] => {
287                assert!(!vex.is4);
288                fmtln!(f, "let reg = self.{reg}.enc();");
289                fmtln!(f, "let vvvv = 0;");
290                fmtln!(f, "let rm = (Some(self.{rm}.enc()), None);");
291                fmtln!(f, "let vex = VexPrefix::three_op(reg, vvvv, rm, {bits});");
292                ModRmStyle::Reg {
293                    reg: ModRmReg::Reg(*reg),
294                    rm: *rm,
295                }
296            }
297            unknown => unimplemented!("unknown pattern: {unknown:?}"),
298        };
299
300        fmtln!(f, "vex.encode(buf);");
301        style
302    }
303
304    fn generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
305        let operands = self.operands_by_kind();
306        let bytes_at_end = match operands.as_slice() {
307            [.., dsl::OperandKind::Imm(imm)] => imm.bytes(),
308            _ => match modrm_style {
309                ModRmStyle::RegMemIs4 { .. } => 1,
310                _ => 0,
311            },
312        };
313
314        f.empty_line();
315
316        match modrm_style {
317            ModRmStyle::None => f.comment("No need to emit a ModRM byte."),
318            _ => f.comment("Emit ModR/M byte."),
319        }
320
321        match modrm_style {
322            ModRmStyle::None => {}
323            ModRmStyle::RegMem { reg, rm } | ModRmStyle::RegMemIs4 { reg, rm, is4: _ } => {
324                match reg {
325                    ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
326                    ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
327                }
328                fmtln!(
329                    f,
330                    "self.{rm}.encode_rex_suffixes(buf, off, reg, {bytes_at_end});"
331                );
332            }
333            ModRmStyle::Reg { reg, rm } => {
334                match reg {
335                    ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
336                    ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
337                }
338                fmtln!(f, "self.{rm}.encode_modrm(buf, reg);");
339            }
340        }
341    }
342
343    fn generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
344        use dsl::OperandKind::Imm;
345        match self.operands_by_kind().as_slice() {
346            [prefix @ .., Imm(imm)] => {
347                assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));
348                f.empty_line();
349                f.comment("Emit immediate.");
350                fmtln!(f, "self.{imm}.encode(buf);");
351            }
352            unknown => {
353                if let ModRmStyle::RegMemIs4 { is4, .. } = modrm_style {
354                    fmtln!(f, "buf.put1(self.{is4}.enc() << 4);");
355                }
356
357                // Do nothing: no immediates expected.
358                assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));
359            }
360        }
361    }
362}
363
364impl dsl::Rex {
365    // `buf.put1(...);`
366    fn generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>) {
367        f.empty_line();
368        f.comment("Emit opcode(s).");
369        if self.opcodes.escape {
370            fmtln!(f, "buf.put1(0x0f);");
371        }
372        if self.opcode_mod.is_some() {
373            let first_op = first_op.expect("Expected first operand for opcode_mod");
374            assert!(matches!(first_op.kind(), dsl::OperandKind::Reg(_)));
375            fmtln!(f, "let low_bits = self.{first_op}.enc() & 0b111;");
376            fmtln!(f, "buf.put1(0x{:x} | low_bits);", self.opcodes.primary);
377        } else {
378            fmtln!(f, "buf.put1(0x{:x});", self.opcodes.primary);
379        }
380        if let Some(secondary) = self.opcodes.secondary {
381            fmtln!(f, "buf.put1(0x{:x});", secondary);
382        }
383    }
384}
385
386impl dsl::Vex {
387    // `buf.put1(...);`
388    fn generate_opcode(&self, f: &mut Formatter) {
389        f.empty_line();
390        f.comment("Emit opcode.");
391        fmtln!(f, "buf.put1(0x{:x});", self.opcode);
392    }
393}