1pub(crate) trait Reg {
9 fn is_64() -> bool;
10
11 fn idx(&self) -> u8;
13
14 fn rexw(&self) -> bool;
16
17 fn is_ext(&self) -> bool {
19 self.idx() > 7
20 }
21
22 fn need_rex(&self) -> bool {
24 self.is_ext() || self.rexw()
25 }
26
27 fn need_sib(&self) -> bool {
33 self.idx() == 4 || self.idx() == 12
34 }
35
36 fn is_pc_rel(&self) -> bool {
42 self.idx() == 5 || self.idx() == 13
43 }
44}
45
46macro_rules! enum_reg {
47 (#[$doc:meta] $name:ident, $narrow:ident, $wider:ident, { $($reg:ident),+ $(,)? }) => {
48 #[$doc]
49 #[allow(non_camel_case_types)]
50 #[derive(Copy, Clone)]
51 #[repr(u8)]
52 pub enum $name {
53 $( $reg, )+
54 }
55
56 impl $name {
57 pub fn narrow(&self) -> $narrow {
58 let idx = self.idx();
59 unsafe { std::ptr::read(&idx as *const u8 as *const $narrow) }
60 }
61
62 pub fn wider(&self) -> $wider {
63 let idx = self.idx();
64 unsafe { std::ptr::read(&idx as *const u8 as *const $wider) }
65 }
66 }
67
68 #[cfg(test)]
69 impl $name {
70 fn iter() -> impl Iterator<Item = &'static $name> {
71 use $name::*;
72 [$( $reg, )+].iter()
73 }
74 }
75 };
76}
77
78macro_rules! impl_reg {
79 (#[$doc:meta] $name:ident, $narrow:ident, $wider:ident, $rexw:expr, { $($reg:ident),+ $(,)? }) => {
80 enum_reg!(#[$doc] $name, $narrow, $wider, { $( $reg, )+ });
81
82 impl Reg for $name {
83 fn idx(&self) -> u8 {
85 *self as u8
86 }
87
88 fn rexw(&self) -> bool {
90 $rexw
91 }
92
93 fn is_64() -> bool {
94 use std::any::TypeId;
95 TypeId::of::<Self>() == TypeId::of::<Reg64>()
96 }
97 }
98 }
99}
100
101impl_reg!(
102 Reg64, Reg32, Reg64, true, { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 });
104impl_reg!(
105 Reg32, Reg16, Reg64, false, { eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d });
107impl_reg!(
108 Reg16, Reg8, Reg32, false, { ax, cx, dx, bx, sp, bp, si, di, r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w });
110enum_reg!(
111 Reg8, Reg8, Reg16, { al, cl, dl, bl, spl, bpl, sil, dil, r8l, r9l, r10l, r11l, r12l, r13l, r14l, r15l,
113 ah, ch, dh, bh });
114
115impl Reg for Reg8 {
116 fn idx(&self) -> u8 {
118 match self {
119 Reg8::ah => 4,
120 Reg8::ch => 5,
121 Reg8::dh => 6,
122 Reg8::bh => 7,
123 _ => *self as u8,
124 }
125 }
126
127 fn rexw(&self) -> bool {
129 false
130 }
131
132 fn need_rex(&self) -> bool {
142 self.idx() > 7 || matches!(self, Reg8::spl | Reg8::bpl | Reg8::sil | Reg8::dil)
143 }
144
145 fn is_64() -> bool {
146 use std::any::TypeId;
147 TypeId::of::<Self>() == TypeId::of::<Reg64>()
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_reg8() {
157 use Reg8::*;
158
159 for r in Reg8::iter() {
160 let idx = match r {
162 al => 0,
163 cl => 1,
164 dl => 2,
165 bl => 3,
166 spl => 4,
167 bpl => 5,
168 sil => 6,
169 dil => 7,
170 r8l => 8,
171 r9l => 9,
172 r10l => 10,
173 r11l => 11,
174 r12l => 12,
175 r13l => 13,
176 r14l => 14,
177 r15l => 15,
178 ah => 4,
179 ch => 5,
180 dh => 6,
181 bh => 7,
182 };
183 assert_eq!(r.idx(), idx);
184
185 assert!(!r.rexw());
187
188 let rex = matches!(
190 r,
191 r8l | r9l | r10l | r11l | r12l | r13l | r14l | r15l | spl | bpl | sil | dil
192 );
193 assert_eq!(r.need_rex(), rex);
194
195 let sib = matches!(r, spl | r12l | ah);
197 assert_eq!(r.need_sib(), sib);
198
199 let rel = matches!(r, bpl | r13l | ch);
201 assert_eq!(r.is_pc_rel(), rel);
202 }
203 }
204
205 #[test]
206 fn test_reg16() {
207 use Reg16::*;
208
209 for r in Reg16::iter() {
210 let idx = match r {
212 ax => 0,
213 cx => 1,
214 dx => 2,
215 bx => 3,
216 sp => 4,
217 bp => 5,
218 si => 6,
219 di => 7,
220 r8w => 8,
221 r9w => 9,
222 r10w => 10,
223 r11w => 11,
224 r12w => 12,
225 r13w => 13,
226 r14w => 14,
227 r15w => 15,
228 };
229 assert_eq!(r.idx(), idx);
230
231 assert!(!r.rexw());
233
234 let rex = matches!(r, r8w | r9w | r10w | r11w | r12w | r13w | r14w | r15w);
236 assert_eq!(r.need_rex(), rex);
237
238 let sib = matches!(r, sp | r12w);
240 assert_eq!(r.need_sib(), sib);
241
242 let rel = matches!(r, bp | r13w);
244 assert_eq!(r.is_pc_rel(), rel);
245 }
246 }
247
248 #[test]
249 fn test_reg32() {
250 use Reg32::*;
251
252 for r in Reg32::iter() {
253 let idx = match r {
255 eax => 0,
256 ecx => 1,
257 edx => 2,
258 ebx => 3,
259 esp => 4,
260 ebp => 5,
261 esi => 6,
262 edi => 7,
263 r8d => 8,
264 r9d => 9,
265 r10d => 10,
266 r11d => 11,
267 r12d => 12,
268 r13d => 13,
269 r14d => 14,
270 r15d => 15,
271 };
272 assert_eq!(r.idx(), idx);
273
274 assert!(!r.rexw());
276
277 let rex = matches!(r, r8d | r9d | r10d | r11d | r12d | r13d | r14d | r15d);
279 assert_eq!(r.need_rex(), rex);
280
281 let sib = matches!(r, esp | r12d);
283 assert_eq!(r.need_sib(), sib);
284
285 let rel = matches!(r, ebp | r13d);
287 assert_eq!(r.is_pc_rel(), rel);
288 }
289 }
290
291 #[test]
292 fn test_reg64() {
293 use Reg64::*;
294
295 for r in Reg64::iter() {
296 let idx = match r {
298 rax => 0,
299 rcx => 1,
300 rdx => 2,
301 rbx => 3,
302 rsp => 4,
303 rbp => 5,
304 rsi => 6,
305 rdi => 7,
306 r8 => 8,
307 r9 => 9,
308 r10 => 10,
309 r11 => 11,
310 r12 => 12,
311 r13 => 13,
312 r14 => 14,
313 r15 => 15,
314 };
315 assert_eq!(r.idx(), idx);
316
317 assert!(r.rexw());
319
320 assert!(r.need_rex());
322
323 let sib = matches!(r, rsp | r12);
325 assert_eq!(r.need_sib(), sib);
326
327 let rel = matches!(r, rbp | r13);
329 assert_eq!(r.is_pc_rel(), rel);
330 }
331 }
332}