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