cranelift_assembler_x64_meta/generate/
format.rs

1//! Generate format-related Rust code; this also includes generation of encoding
2//! Rust code.
3
4use super::{fmtln, Formatter};
5use crate::dsl;
6
7impl dsl::Format {
8    /// Re-order the Intel-style operand order to accommodate ATT-style
9    /// printing.
10    ///
11    /// This is an unfortunate necessity to match Cranelift's current
12    /// disassembly, which uses AT&T-style printing. The plan is to eventually
13    /// transition to Intel-style printing (and avoid this awkward reordering)
14    /// once Cranelift has switched to using this assembler predominantly
15    /// (TODO).
16    #[must_use]
17    pub fn generate_att_style_operands(&self) -> String {
18        let ordered_ops: Vec<_> = self
19            .operands
20            .iter()
21            .rev()
22            .map(|o| format!("{{{}}}", o.location))
23            .collect();
24        ordered_ops.join(", ")
25    }
26
27    pub fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {
28        self.generate_legacy_prefix(f, rex);
29        self.generate_rex_prefix(f, rex);
30        self.generate_opcodes(f, rex);
31        self.generate_modrm_byte(f, rex);
32        self.generate_immediate(f);
33    }
34
35    /// `buf.put1(...);`
36    fn generate_legacy_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) {
37        use dsl::LegacyPrefix::*;
38        if rex.opcodes.prefix != NoPrefix {
39            f.empty_line();
40            f.comment("Emit legacy prefixes.");
41            match rex.opcodes.prefix {
42                NoPrefix => unreachable!(),
43                _66 => fmtln!(f, "buf.put1(0x66);"),
44                _F0 => fmtln!(f, "buf.put1(0xf0);"),
45                _66F0 => {
46                    fmtln!(f, "buf.put1(0x66);");
47                    fmtln!(f, "buf.put1(0xf0);");
48                }
49                _F2 => fmtln!(f, "buf.put1(0xf2);"),
50                _F3 => fmtln!(f, "buf.put1(0xf3);"),
51                _66F3 => {
52                    fmtln!(f, "buf.put1(0x66);");
53                    fmtln!(f, "buf.put1(0xf3);");
54                }
55            }
56        }
57    }
58
59    // `buf.put1(...);`
60    fn generate_opcodes(&self, f: &mut Formatter, rex: &dsl::Rex) {
61        f.empty_line();
62        f.comment("Emit opcode(s).");
63        if rex.opcodes.escape {
64            fmtln!(f, "buf.put1(0x0f);");
65        }
66        fmtln!(f, "buf.put1(0x{:x});", rex.opcodes.primary);
67        if let Some(secondary) = rex.opcodes.secondary {
68            fmtln!(f, "buf.put1(0x{:x});", secondary);
69        }
70    }
71
72    fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) {
73        use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
74        f.empty_line();
75        f.comment("Emit REX prefix.");
76
77        let find_8bit_registers = |l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
78        if self.locations().any(find_8bit_registers) {
79            fmtln!(f, "let mut rex = {};", rex.generate_flags());
80            for op in self.locations().copied().filter(find_8bit_registers) {
81                fmtln!(f, "self.{op}.always_emit_if_8bit_needed(&mut rex);");
82            }
83        } else {
84            fmtln!(f, "let rex = {};", rex.generate_flags());
85        }
86
87        match self.operands_by_kind().as_slice() {
88            [FixedReg(dst), Imm(_)] => {
89                // TODO: don't emit REX byte here.
90                fmtln!(f, "let {dst} = {};", dst.generate_fixed_reg().unwrap());
91                assert_eq!(rex.digit, None, "we expect no digit for operands: [FixedReg, Imm]");
92                fmtln!(f, "let digit = 0;");
93                fmtln!(f, "rex.emit_two_op(buf, digit, {dst}.enc());");
94            }
95            [RegMem(dst), Imm(_)] => {
96                let digit = rex
97                    .digit
98                    .expect("REX digit must be set for operands: [RegMem, Imm]");
99                fmtln!(f, "let digit = 0x{digit:x};");
100                f.add_block(&format!("match &self.{dst}"), |f| {
101                    fmtln!(f, "GprMem::Gpr({dst}) => rex.emit_two_op(buf, digit, {dst}.enc()),");
102                    fmtln!(f, "GprMem::Mem({dst}) => {dst}.emit_rex_prefix(rex, digit, buf),");
103                });
104            }
105            [Reg(dst), RegMem(src)] => {
106                fmtln!(f, "let {dst} = self.{dst}.enc();");
107                f.add_block(&format!("match &self.{src}"), |f| {
108                    match dst.bits() {
109                        128 => {
110                            fmtln!(f, "XmmMem::Xmm({src}) => rex.emit_two_op(buf, {dst}, {src}.enc()),");
111                            fmtln!(f, "XmmMem::Mem({src}) => {src}.emit_rex_prefix(rex, {dst}, buf),");
112                        }
113                        _ => {
114                            fmtln!(f, "GprMem::Gpr({src}) => rex.emit_two_op(buf, {dst}, {src}.enc()),");
115                            fmtln!(f, "GprMem::Mem({src}) => {src}.emit_rex_prefix(rex, {dst}, buf),");
116                        }
117                    };
118                });
119            }
120            [RegMem(dst), Reg(src)]
121            | [RegMem(dst), Reg(src), Imm(_)]
122            | [RegMem(dst), Reg(src), FixedReg(_)] => {
123                fmtln!(f, "let {src} = self.{src}.enc();");
124                f.add_block(&format!("match &self.{dst}"), |f| match src.bits() {
125                    128 => {
126                        fmtln!(f, "XmmMem::Xmm({dst}) => rex.emit_two_op(buf, {src}, {dst}.enc()),");
127                        fmtln!(f, "XmmMem::Mem({dst}) => {dst}.emit_rex_prefix(rex, {src}, buf),");
128                    }
129                    _ => {
130                        fmtln!(f, "GprMem::Gpr({dst}) => rex.emit_two_op(buf, {src}, {dst}.enc()),");
131                        fmtln!(f, "GprMem::Mem({dst}) => {dst}.emit_rex_prefix(rex, {src}, buf),");
132                    }
133                });
134            }
135
136            unknown => unimplemented!("unknown pattern: {unknown:?}"),
137        }
138    }
139
140    fn generate_modrm_byte(&self, f: &mut Formatter, rex: &dsl::Rex) {
141        use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
142
143        if let [FixedReg(_), Imm(_)] = self.operands_by_kind().as_slice() {
144            // No need to emit a comment.
145        } else {
146            f.empty_line();
147            f.comment("Emit ModR/M byte.");
148        }
149
150        match self.operands_by_kind().as_slice() {
151            [FixedReg(_), Imm(_)] => {
152                // No need to emit a ModRM byte: we know the register used.
153            }
154            [RegMem(dst), Imm(_)] => {
155                let digit = rex
156                    .digit
157                    .expect("REX digit must be set for operands: [RegMem, Imm]");
158                fmtln!(f, "let digit = 0x{digit:x};");
159                f.add_block(&format!("match &self.{dst}"), |f| {
160                    fmtln!(f, "GprMem::Gpr({dst}) => emit_modrm(buf, digit, {dst}.enc()),");
161                    fmtln!(f, "GprMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, digit, {dst}, 0, None),");
162                });
163            }
164            [Reg(dst), RegMem(src)] => {
165                fmtln!(f, "let {dst} = self.{dst}.enc();");
166                f.add_block(&format!("match &self.{src}"), |f| {
167                    match dst.bits() {
168                        128 => {
169                            fmtln!(f, "XmmMem::Xmm({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
170                            fmtln!(
171                                f,
172                                "XmmMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
173                            );
174                        }
175                        _ => {
176                            fmtln!(f, "GprMem::Gpr({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
177                            fmtln!(
178                                f,
179                                "GprMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
180                            );
181                        }
182                    };
183                });
184            }
185            [RegMem(dst), Reg(src)]
186            | [RegMem(dst), Reg(src), Imm(_)]
187            | [RegMem(dst), Reg(src), FixedReg(_)] => {
188                fmtln!(f, "let {src} = self.{src}.enc();");
189                f.add_block(&format!("match &self.{dst}"), |f| {
190                    match src.bits() {
191                        128 => {
192                            fmtln!(f, "XmmMem::Xmm({dst}) => emit_modrm(buf, {src}, {dst}.enc()),");
193                            fmtln!(
194                                f,
195                                "XmmMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),"
196                            );
197                        }
198                        _ => {
199                            fmtln!(f, "GprMem::Gpr({dst}) => emit_modrm(buf, {src}, {dst}.enc()),");
200                            fmtln!(
201                                f,
202                                "GprMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),"
203                            );
204                        }
205                    };
206                });
207            }
208            unknown => unimplemented!("unknown pattern: {unknown:?}"),
209        }
210    }
211
212    fn generate_immediate(&self, f: &mut Formatter) {
213        use dsl::OperandKind::Imm;
214        match self.operands_by_kind().as_slice() {
215            [prefix @ .., Imm(imm)] => {
216                assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));
217
218                f.empty_line();
219                f.comment("Emit immediate.");
220                fmtln!(f, "self.{imm}.encode(buf);");
221            }
222            unknown => {
223                // Do nothing: no immediates expected.
224                assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));
225            }
226        }
227    }
228}
229
230impl dsl::Rex {
231    fn generate_flags(&self) -> &str {
232        if self.w {
233            "RexFlags::set_w()"
234        } else {
235            "RexFlags::clear_w()"
236        }
237    }
238}