1 //! Pure register operands; see [`Gpr`].
2 
3 use crate::AsReg;
4 use alloc::string::String;
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, PartialEq)]
11 pub struct Gpr<R: AsReg = u8>(pub(crate) R);
12 
13 impl<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).
new(reg: R) -> Self16     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.
enc(&self) -> u826     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`.
to_string(&self, size: Size) -> String33     pub fn to_string(&self, size: Size) -> String {
34         self.0.to_string(Some(size))
35     }
36 }
37 
38 impl<R: AsReg> AsRef<R> for Gpr<R> {
as_ref(&self) -> &R39     fn as_ref(&self) -> &R {
40         &self.0
41     }
42 }
43 
44 impl<R: AsReg> AsMut<R> for Gpr<R> {
as_mut(&mut self) -> &mut R45     fn as_mut(&mut self) -> &mut R {
46         &mut self.0
47     }
48 }
49 
50 impl<R: AsReg> From<R> for Gpr<R> {
from(reg: R) -> Gpr<R>51     fn from(reg: R) -> Gpr<R> {
52         Gpr(reg)
53     }
54 }
55 
56 /// A single x64 register encoding can access a different number of bits.
57 #[derive(Copy, Clone, Debug)]
58 pub 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, PartialEq)]
74 pub struct NonRspGpr<R: AsReg>(R);
75 
76 impl<R: AsReg> NonRspGpr<R> {
77     /// See [`Gpr::new`].
new(reg: R) -> Self78     pub fn new(reg: R) -> Self {
79         Self(reg)
80     }
81 
82     /// See [`Gpr::to_string`].
to_string(&self, size: Size) -> String83     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`.
enc(&self) -> u892     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 
100 impl<R: AsReg> AsRef<R> for NonRspGpr<R> {
as_ref(&self) -> &R101     fn as_ref(&self) -> &R {
102         &self.0
103     }
104 }
105 
106 impl<R: AsReg> AsMut<R> for NonRspGpr<R> {
as_mut(&mut self) -> &mut R107     fn as_mut(&mut self) -> &mut R {
108         &mut self.0
109     }
110 }
111 
112 impl<R: AsReg> From<R> for NonRspGpr<R> {
from(reg: R) -> NonRspGpr<R>113     fn from(reg: R) -> NonRspGpr<R> {
114         NonRspGpr(reg)
115     }
116 }
117 
118 /// Encode x64 registers.
119 pub mod enc {
120     use super::Size;
121 
122     pub const RAX: u8 = 0;
123     pub const RCX: u8 = 1;
124     pub const RDX: u8 = 2;
125     pub const RBX: u8 = 3;
126     pub const RSP: u8 = 4;
127     pub const RBP: u8 = 5;
128     pub const RSI: u8 = 6;
129     pub const RDI: u8 = 7;
130     pub const R8: u8 = 8;
131     pub const R9: u8 = 9;
132     pub const R10: u8 = 10;
133     pub const R11: u8 = 11;
134     pub const R12: u8 = 12;
135     pub const R13: u8 = 13;
136     pub const R14: u8 = 14;
137     pub const R15: u8 = 15;
138 
139     /// Return the name of a GPR encoding (`enc`) at the given `size`.
140     ///
141     /// # Panics
142     ///
143     /// This function will panic if the encoding is not a valid x64 register.
to_string(enc: u8, size: Size) -> &'static str144     pub fn to_string(enc: u8, size: Size) -> &'static str {
145         use Size::{Byte, Doubleword, Quadword, Word};
146         match enc {
147             RAX => match size {
148                 Byte => "%al",
149                 Word => "%ax",
150                 Doubleword => "%eax",
151                 Quadword => "%rax",
152             },
153             RBX => match size {
154                 Byte => "%bl",
155                 Word => "%bx",
156                 Doubleword => "%ebx",
157                 Quadword => "%rbx",
158             },
159             RCX => match size {
160                 Byte => "%cl",
161                 Word => "%cx",
162                 Doubleword => "%ecx",
163                 Quadword => "%rcx",
164             },
165             RDX => match size {
166                 Byte => "%dl",
167                 Word => "%dx",
168                 Doubleword => "%edx",
169                 Quadword => "%rdx",
170             },
171             RSI => match size {
172                 Byte => "%sil",
173                 Word => "%si",
174                 Doubleword => "%esi",
175                 Quadword => "%rsi",
176             },
177             RDI => match size {
178                 Byte => "%dil",
179                 Word => "%di",
180                 Doubleword => "%edi",
181                 Quadword => "%rdi",
182             },
183             RBP => match size {
184                 Byte => "%bpl",
185                 Word => "%bp",
186                 Doubleword => "%ebp",
187                 Quadword => "%rbp",
188             },
189             RSP => match size {
190                 Byte => "%spl",
191                 Word => "%sp",
192                 Doubleword => "%esp",
193                 Quadword => "%rsp",
194             },
195             R8 => match size {
196                 Byte => "%r8b",
197                 Word => "%r8w",
198                 Doubleword => "%r8d",
199                 Quadword => "%r8",
200             },
201             R9 => match size {
202                 Byte => "%r9b",
203                 Word => "%r9w",
204                 Doubleword => "%r9d",
205                 Quadword => "%r9",
206             },
207             R10 => match size {
208                 Byte => "%r10b",
209                 Word => "%r10w",
210                 Doubleword => "%r10d",
211                 Quadword => "%r10",
212             },
213             R11 => match size {
214                 Byte => "%r11b",
215                 Word => "%r11w",
216                 Doubleword => "%r11d",
217                 Quadword => "%r11",
218             },
219             R12 => match size {
220                 Byte => "%r12b",
221                 Word => "%r12w",
222                 Doubleword => "%r12d",
223                 Quadword => "%r12",
224             },
225             R13 => match size {
226                 Byte => "%r13b",
227                 Word => "%r13w",
228                 Doubleword => "%r13d",
229                 Quadword => "%r13",
230             },
231             R14 => match size {
232                 Byte => "%r14b",
233                 Word => "%r14w",
234                 Doubleword => "%r14d",
235                 Quadword => "%r14",
236             },
237             R15 => match size {
238                 Byte => "%r15b",
239                 Word => "%r15w",
240                 Doubleword => "%r15d",
241                 Quadword => "%r15",
242             },
243             _ => panic!("%invalid{enc}"),
244         }
245     }
246 }
247