cranelift_assembler_x64/
gpr.rs

1//! Pure register operands; see [`Gpr`].
2
3use crate::rex::RexFlags;
4use crate::AsReg;
5
6/// A general purpose x64 register (e.g., `%rax`).
7///
8/// This container wraps true register type `R` to allow users to specify their
9/// own; by default this will use `u8`.
10#[derive(Clone, Copy, Debug)]
11pub struct Gpr<R: AsReg = u8>(pub(crate) R);
12
13impl<R: AsReg> Gpr<R> {
14    /// Create a [`Gpr`] that may be real (immediately emit-able in machine
15    /// code) or virtual (waiting for register allocation).
16    pub fn new(reg: R) -> Self {
17        Self(reg)
18    }
19
20    /// Return the register's hardware encoding; the underlying type `R` _must_
21    /// be a real register at this point.
22    ///
23    /// # Panics
24    ///
25    /// Panics if the register is not a valid x64 register.
26    pub fn enc(&self) -> u8 {
27        let enc = self.0.enc();
28        assert!(enc < 16, "invalid register: {enc}");
29        enc
30    }
31
32    /// Return the register name at the given `size`.
33    pub fn to_string(&self, size: Size) -> String {
34        self.0.to_string(Some(size))
35    }
36
37    /// Proxy on the 8-bit REX flag emission; helpful for simplifying generated
38    /// code.
39    pub(crate) fn always_emit_if_8bit_needed(&self, rex: &mut RexFlags) {
40        rex.always_emit_if_8bit_needed(self.enc());
41    }
42}
43
44impl<R: AsReg> AsRef<R> for Gpr<R> {
45    fn as_ref(&self) -> &R {
46        &self.0
47    }
48}
49
50impl<R: AsReg> AsMut<R> for Gpr<R> {
51    fn as_mut(&mut self) -> &mut R {
52        &mut self.0
53    }
54}
55
56/// A single x64 register encoding can access a different number of bits.
57#[derive(Copy, Clone, Debug)]
58pub enum Size {
59    /// An 8-bit access.
60    Byte,
61    /// A 16-bit access.
62    Word,
63    /// A 32-bit access.
64    Doubleword,
65    /// A 64-bit access.
66    Quadword,
67}
68
69/// Like [`Gpr`], but with `%rsp` disallowed.
70///
71/// This is due to avoid special cases of REX encodings, see Intel SDM Vol. 2A,
72/// table 2-5.
73#[derive(Clone, Copy, Debug)]
74pub struct NonRspGpr<R: AsReg>(R);
75
76impl<R: AsReg> NonRspGpr<R> {
77    /// See [`Gpr::new`].
78    pub fn new(reg: R) -> Self {
79        Self(reg)
80    }
81
82    /// See [`Gpr::to_string`].
83    pub fn to_string(&self, size: Size) -> String {
84        self.0.to_string(Some(size))
85    }
86
87    /// See [`Gpr::enc`].
88    ///
89    /// # Panics
90    ///
91    /// Panics if the register is invalid or `%rsp`.
92    pub fn enc(&self) -> u8 {
93        let enc = self.0.enc();
94        assert!(enc < 16, "invalid register: {enc}");
95        assert_ne!(enc, enc::RSP, "invalid register: %rsp");
96        enc
97    }
98}
99
100impl<R: AsReg> AsMut<R> for NonRspGpr<R> {
101    fn as_mut(&mut self) -> &mut R {
102        &mut self.0
103    }
104}
105
106/// Encode x64 registers.
107pub mod enc {
108    use super::Size;
109
110    pub const RAX: u8 = 0;
111    pub const RCX: u8 = 1;
112    pub const RDX: u8 = 2;
113    pub const RBX: u8 = 3;
114    pub const RSP: u8 = 4;
115    pub const RBP: u8 = 5;
116    pub const RSI: u8 = 6;
117    pub const RDI: u8 = 7;
118    pub const R8: u8 = 8;
119    pub const R9: u8 = 9;
120    pub const R10: u8 = 10;
121    pub const R11: u8 = 11;
122    pub const R12: u8 = 12;
123    pub const R13: u8 = 13;
124    pub const R14: u8 = 14;
125    pub const R15: u8 = 15;
126
127    /// Return the name of a GPR encoding (`enc`) at the given `size`.
128    ///
129    /// # Panics
130    ///
131    /// This function will panic if the encoding is not a valid x64 register.
132    pub fn to_string(enc: u8, size: Size) -> &'static str {
133        use Size::{Byte, Doubleword, Quadword, Word};
134        match enc {
135            RAX => match size {
136                Byte => "%al",
137                Word => "%ax",
138                Doubleword => "%eax",
139                Quadword => "%rax",
140            },
141            RBX => match size {
142                Byte => "%bl",
143                Word => "%bx",
144                Doubleword => "%ebx",
145                Quadword => "%rbx",
146            },
147            RCX => match size {
148                Byte => "%cl",
149                Word => "%cx",
150                Doubleword => "%ecx",
151                Quadword => "%rcx",
152            },
153            RDX => match size {
154                Byte => "%dl",
155                Word => "%dx",
156                Doubleword => "%edx",
157                Quadword => "%rdx",
158            },
159            RSI => match size {
160                Byte => "%sil",
161                Word => "%si",
162                Doubleword => "%esi",
163                Quadword => "%rsi",
164            },
165            RDI => match size {
166                Byte => "%dil",
167                Word => "%di",
168                Doubleword => "%edi",
169                Quadword => "%rdi",
170            },
171            RBP => match size {
172                Byte => "%bpl",
173                Word => "%bp",
174                Doubleword => "%ebp",
175                Quadword => "%rbp",
176            },
177            RSP => match size {
178                Byte => "%spl",
179                Word => "%sp",
180                Doubleword => "%esp",
181                Quadword => "%rsp",
182            },
183            R8 => match size {
184                Byte => "%r8b",
185                Word => "%r8w",
186                Doubleword => "%r8d",
187                Quadword => "%r8",
188            },
189            R9 => match size {
190                Byte => "%r9b",
191                Word => "%r9w",
192                Doubleword => "%r9d",
193                Quadword => "%r9",
194            },
195            R10 => match size {
196                Byte => "%r10b",
197                Word => "%r10w",
198                Doubleword => "%r10d",
199                Quadword => "%r10",
200            },
201            R11 => match size {
202                Byte => "%r11b",
203                Word => "%r11w",
204                Doubleword => "%r11d",
205                Quadword => "%r11",
206            },
207            R12 => match size {
208                Byte => "%r12b",
209                Word => "%r12w",
210                Doubleword => "%r12d",
211                Quadword => "%r12",
212            },
213            R13 => match size {
214                Byte => "%r13b",
215                Word => "%r13w",
216                Doubleword => "%r13d",
217                Quadword => "%r13",
218            },
219            R14 => match size {
220                Byte => "%r14b",
221                Word => "%r14w",
222                Doubleword => "%r14d",
223                Quadword => "%r14",
224            },
225            R15 => match size {
226                Byte => "%r15b",
227                Word => "%r15w",
228                Doubleword => "%r15d",
229                Quadword => "%r15",
230            },
231            _ => panic!("%invalid{enc}"),
232        }
233    }
234}