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