cranelift_codegen/isa/x64/inst/
regs.rs

1//! Register definitions for regalloc2.
2//!
3//! We define 16 GPRs, with indices equal to the hardware encoding,
4//! and 16 XMM registers.
5//!
6//! Note also that we make use of pinned VRegs to refer to PRegs.
7
8use crate::machinst::{AllocationConsumer, RealReg, Reg};
9use crate::settings;
10use alloc::string::ToString;
11use regalloc2::{MachineEnv, PReg, RegClass, VReg};
12use std::string::String;
13
14// Hardware encodings (note the special rax, rcx, rdx, rbx order).
15
16pub const ENC_RAX: u8 = 0;
17pub const ENC_RCX: u8 = 1;
18pub const ENC_RDX: u8 = 2;
19pub const ENC_RBX: u8 = 3;
20pub const ENC_RSP: u8 = 4;
21pub const ENC_RBP: u8 = 5;
22pub const ENC_RSI: u8 = 6;
23pub const ENC_RDI: u8 = 7;
24pub const ENC_R8: u8 = 8;
25pub const ENC_R9: u8 = 9;
26pub const ENC_R10: u8 = 10;
27pub const ENC_R11: u8 = 11;
28pub const ENC_R12: u8 = 12;
29pub const ENC_R13: u8 = 13;
30pub const ENC_R14: u8 = 14;
31pub const ENC_R15: u8 = 15;
32
33// Constructors for Regs.
34
35fn gpr(enc: u8) -> Reg {
36    let preg = gpr_preg(enc);
37    Reg::from(VReg::new(preg.index(), RegClass::Int))
38}
39pub(crate) const fn gpr_preg(enc: u8) -> PReg {
40    PReg::new(enc as usize, RegClass::Int)
41}
42
43pub(crate) fn rsi() -> Reg {
44    gpr(ENC_RSI)
45}
46pub(crate) fn rdi() -> Reg {
47    gpr(ENC_RDI)
48}
49pub(crate) fn rax() -> Reg {
50    gpr(ENC_RAX)
51}
52pub(crate) fn rcx() -> Reg {
53    gpr(ENC_RCX)
54}
55pub(crate) fn rdx() -> Reg {
56    gpr(ENC_RDX)
57}
58pub(crate) fn r8() -> Reg {
59    gpr(ENC_R8)
60}
61pub(crate) fn r9() -> Reg {
62    gpr(ENC_R9)
63}
64pub(crate) fn r10() -> Reg {
65    gpr(ENC_R10)
66}
67pub(crate) fn r11() -> Reg {
68    gpr(ENC_R11)
69}
70pub(crate) fn r12() -> Reg {
71    gpr(ENC_R12)
72}
73pub(crate) fn r13() -> Reg {
74    gpr(ENC_R13)
75}
76pub(crate) fn r14() -> Reg {
77    gpr(ENC_R14)
78}
79pub(crate) fn rbx() -> Reg {
80    gpr(ENC_RBX)
81}
82
83pub(crate) fn r15() -> Reg {
84    gpr(ENC_R15)
85}
86
87pub(crate) fn rsp() -> Reg {
88    gpr(ENC_RSP)
89}
90pub(crate) fn rbp() -> Reg {
91    gpr(ENC_RBP)
92}
93
94/// The pinned register on this architecture.
95/// It must be the same as Spidermonkey's HeapReg, as found in this file.
96/// https://searchfox.org/mozilla-central/source/js/src/jit/x64/Assembler-x64.h#99
97pub(crate) fn pinned_reg() -> Reg {
98    r15()
99}
100
101fn fpr(enc: u8) -> Reg {
102    let preg = fpr_preg(enc);
103    Reg::from(VReg::new(preg.index(), RegClass::Float))
104}
105
106pub(crate) const fn fpr_preg(enc: u8) -> PReg {
107    PReg::new(enc as usize, RegClass::Float)
108}
109
110pub(crate) fn xmm0() -> Reg {
111    fpr(0)
112}
113pub(crate) fn xmm1() -> Reg {
114    fpr(1)
115}
116pub(crate) fn xmm2() -> Reg {
117    fpr(2)
118}
119pub(crate) fn xmm3() -> Reg {
120    fpr(3)
121}
122pub(crate) fn xmm4() -> Reg {
123    fpr(4)
124}
125pub(crate) fn xmm5() -> Reg {
126    fpr(5)
127}
128pub(crate) fn xmm6() -> Reg {
129    fpr(6)
130}
131pub(crate) fn xmm7() -> Reg {
132    fpr(7)
133}
134pub(crate) fn xmm8() -> Reg {
135    fpr(8)
136}
137pub(crate) fn xmm9() -> Reg {
138    fpr(9)
139}
140pub(crate) fn xmm10() -> Reg {
141    fpr(10)
142}
143pub(crate) fn xmm11() -> Reg {
144    fpr(11)
145}
146pub(crate) fn xmm12() -> Reg {
147    fpr(12)
148}
149pub(crate) fn xmm13() -> Reg {
150    fpr(13)
151}
152pub(crate) fn xmm14() -> Reg {
153    fpr(14)
154}
155pub(crate) fn xmm15() -> Reg {
156    fpr(15)
157}
158
159/// Create the register environment for x64.
160pub(crate) fn create_reg_env_systemv(flags: &settings::Flags) -> MachineEnv {
161    fn preg(r: Reg) -> PReg {
162        r.to_real_reg().unwrap().into()
163    }
164
165    let mut env = MachineEnv {
166        preferred_regs_by_class: [
167            // Preferred GPRs: caller-saved in the SysV ABI.
168            vec![
169                preg(rsi()),
170                preg(rdi()),
171                preg(rax()),
172                preg(rcx()),
173                preg(rdx()),
174                preg(r8()),
175                preg(r9()),
176                preg(r10()),
177                preg(r11()),
178            ],
179            // Preferred XMMs: all of them.
180            vec![
181                preg(xmm0()),
182                preg(xmm1()),
183                preg(xmm2()),
184                preg(xmm3()),
185                preg(xmm4()),
186                preg(xmm5()),
187                preg(xmm6()),
188                preg(xmm7()),
189                preg(xmm8()),
190                preg(xmm9()),
191                preg(xmm10()),
192                preg(xmm11()),
193                preg(xmm12()),
194                preg(xmm13()),
195                preg(xmm14()),
196                preg(xmm15()),
197            ],
198        ],
199        non_preferred_regs_by_class: [
200            // Non-preferred GPRs: callee-saved in the SysV ABI.
201            vec![preg(rbx()), preg(r12()), preg(r13()), preg(r14())],
202            // Non-preferred XMMs: none.
203            vec![],
204        ],
205        fixed_stack_slots: vec![],
206    };
207
208    debug_assert_eq!(r15(), pinned_reg());
209    if !flags.enable_pinned_reg() {
210        env.non_preferred_regs_by_class[0].push(preg(r15()));
211    }
212
213    env
214}
215
216/// Give the name of a RealReg.
217pub fn realreg_name(reg: RealReg) -> &'static str {
218    let preg = PReg::from(reg);
219    match preg.class() {
220        RegClass::Int => match preg.hw_enc() as u8 {
221            ENC_RAX => "%rax",
222            ENC_RBX => "%rbx",
223            ENC_RCX => "%rcx",
224            ENC_RDX => "%rdx",
225            ENC_RSI => "%rsi",
226            ENC_RDI => "%rdi",
227            ENC_RBP => "%rbp",
228            ENC_RSP => "%rsp",
229            ENC_R8 => "%r8",
230            ENC_R9 => "%r9",
231            ENC_R10 => "%r10",
232            ENC_R11 => "%r11",
233            ENC_R12 => "%r12",
234            ENC_R13 => "%r13",
235            ENC_R14 => "%r14",
236            ENC_R15 => "%r15",
237            _ => panic!("Invalid PReg: {:?}", preg),
238        },
239        RegClass::Float => match preg.hw_enc() {
240            0 => "%xmm0",
241            1 => "%xmm1",
242            2 => "%xmm2",
243            3 => "%xmm3",
244            4 => "%xmm4",
245            5 => "%xmm5",
246            6 => "%xmm6",
247            7 => "%xmm7",
248            8 => "%xmm8",
249            9 => "%xmm9",
250            10 => "%xmm10",
251            11 => "%xmm11",
252            12 => "%xmm12",
253            13 => "%xmm13",
254            14 => "%xmm14",
255            15 => "%xmm15",
256            _ => panic!("Invalid PReg: {:?}", preg),
257        },
258    }
259}
260
261pub fn show_reg(reg: Reg) -> String {
262    if let Some(rreg) = reg.to_real_reg() {
263        realreg_name(rreg).to_string()
264    } else {
265        format!("%{:?}", reg)
266    }
267}
268
269/// If `ireg` denotes an I64-classed reg, make a best-effort attempt to show its name at some
270/// smaller size (4, 2 or 1 bytes).
271pub fn show_ireg_sized(reg: Reg, size: u8) -> String {
272    let mut s = show_reg(reg);
273
274    if reg.class() != RegClass::Int || size == 8 {
275        // We can't do any better.
276        return s;
277    }
278
279    if reg.is_real() {
280        // Change (eg) "rax" into "eax", "ax" or "al" as appropriate.  This is something one could
281        // describe diplomatically as "a kludge", but it's only debug code.
282        let remapper = match s.as_str() {
283            "%rax" => Some(["%eax", "%ax", "%al"]),
284            "%rbx" => Some(["%ebx", "%bx", "%bl"]),
285            "%rcx" => Some(["%ecx", "%cx", "%cl"]),
286            "%rdx" => Some(["%edx", "%dx", "%dl"]),
287            "%rsi" => Some(["%esi", "%si", "%sil"]),
288            "%rdi" => Some(["%edi", "%di", "%dil"]),
289            "%rbp" => Some(["%ebp", "%bp", "%bpl"]),
290            "%rsp" => Some(["%esp", "%sp", "%spl"]),
291            "%r8" => Some(["%r8d", "%r8w", "%r8b"]),
292            "%r9" => Some(["%r9d", "%r9w", "%r9b"]),
293            "%r10" => Some(["%r10d", "%r10w", "%r10b"]),
294            "%r11" => Some(["%r11d", "%r11w", "%r11b"]),
295            "%r12" => Some(["%r12d", "%r12w", "%r12b"]),
296            "%r13" => Some(["%r13d", "%r13w", "%r13b"]),
297            "%r14" => Some(["%r14d", "%r14w", "%r14b"]),
298            "%r15" => Some(["%r15d", "%r15w", "%r15b"]),
299            _ => None,
300        };
301        if let Some(smaller_names) = remapper {
302            match size {
303                4 => s = smaller_names[0].into(),
304                2 => s = smaller_names[1].into(),
305                1 => s = smaller_names[2].into(),
306                _ => panic!("show_ireg_sized: real"),
307            }
308        }
309    } else {
310        // Add a "l", "w" or "b" suffix to RegClass::I64 vregs used at narrower widths.
311        let suffix = match size {
312            4 => "l",
313            2 => "w",
314            1 => "b",
315            _ => panic!("show_ireg_sized: virtual"),
316        };
317        s = s + suffix;
318    }
319
320    s
321}
322
323// N.B.: this is not an `impl PrettyPrint for Reg` because it is
324// specific to x64; other backends have analogous functions. The
325// disambiguation happens statically by virtue of higher-level,
326// x64-specific, types calling the right `pretty_print_reg`. (In other
327// words, we can't pretty-print a `Reg` all by itself in a build that
328// may have multiple backends; but we can pretty-print one as part of
329// an x64 Inst or x64 RegMemImm.)
330pub fn pretty_print_reg(reg: Reg, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
331    let reg = allocs.next(reg);
332    show_ireg_sized(reg, size)
333}