Skip to main content

osom_encoders_x86_64/models/
gpr.rs

1use core::mem::transmute;
2
3use super::{GPRKind, Size};
4
5/// Represents a general purpose register in the `X86_64` instruction set.
6#[repr(u8)]
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
8#[must_use]
9pub enum GPR {
10    RAX = 1, // We start from 1 to allow Option<GPR> optimization
11    RBX = 2,
12    RCX = 3,
13    RDX = 4,
14    RSI = 5,
15    RDI = 6,
16    RBP = 7,
17    RSP = 8,
18    R8 = 9,
19    R9 = 10,
20    R10 = 11,
21    R11 = 12,
22    R12 = 13,
23    R13 = 14,
24    R14 = 15,
25    R15 = 16,
26
27    EAX = 17,
28    EBX = 18,
29    ECX = 19,
30    EDX = 20,
31    ESI = 21,
32    EDI = 22,
33    EBP = 23,
34    ESP = 24,
35    R8D = 25,
36    R9D = 26,
37    R10D = 27,
38    R11D = 28,
39    R12D = 29,
40    R13D = 30,
41    R14D = 31,
42    R15D = 32,
43
44    AX = 33,
45    BX = 34,
46    CX = 35,
47    DX = 36,
48    SI = 37,
49    DI = 38,
50    BP = 39,
51    SP = 40,
52    R8W = 41,
53    R9W = 42,
54    R10W = 43,
55    R11W = 44,
56    R12W = 45,
57    R13W = 46,
58    R14W = 47,
59    R15W = 48,
60
61    AL = 49,
62    BL = 50,
63    CL = 51,
64    DL = 52,
65    SIL = 53,
66    DIL = 54,
67    BPL = 55,
68    SPL = 56,
69    R8B = 57,
70    R9B = 58,
71    R10B = 59,
72    R11B = 60,
73    R12B = 61,
74    R13B = 62,
75    R14B = 63,
76    R15B = 64,
77
78    AH = 65,
79    BH = 66,
80    CH = 67,
81    DH = 68,
82}
83
84impl GPR {
85    /// Compares two [`GPR`] values for equality.
86    #[inline(always)]
87    #[must_use]
88    pub const fn equals(self, other: Self) -> bool {
89        self.as_u8() == other.as_u8()
90    }
91
92    /// Represents the kind of the [`GPR`].
93    pub const fn kind(self) -> GPRKind {
94        match self {
95            Self::AH | Self::BH | Self::CH | Self::DH => GPRKind::Bit8High,
96            Self::AL
97            | Self::CL
98            | Self::DL
99            | Self::BL
100            | Self::SPL
101            | Self::BPL
102            | Self::SIL
103            | Self::DIL
104            | Self::R8B
105            | Self::R9B
106            | Self::R10B
107            | Self::R11B
108            | Self::R12B
109            | Self::R13B
110            | Self::R14B
111            | Self::R15B => GPRKind::Bit8,
112            Self::AX
113            | Self::CX
114            | Self::DX
115            | Self::BX
116            | Self::SP
117            | Self::BP
118            | Self::SI
119            | Self::DI
120            | Self::R8W
121            | Self::R9W
122            | Self::R10W
123            | Self::R11W
124            | Self::R12W
125            | Self::R13W
126            | Self::R14W
127            | Self::R15W => GPRKind::Bit16,
128            Self::EAX
129            | Self::ECX
130            | Self::EDX
131            | Self::EBX
132            | Self::ESP
133            | Self::EBP
134            | Self::ESI
135            | Self::EDI
136            | Self::R8D
137            | Self::R9D
138            | Self::R10D
139            | Self::R11D
140            | Self::R12D
141            | Self::R13D
142            | Self::R14D
143            | Self::R15D => GPRKind::Bit32,
144            Self::RAX
145            | Self::RCX
146            | Self::RDX
147            | Self::RBX
148            | Self::RSP
149            | Self::RBP
150            | Self::RSI
151            | Self::RDI
152            | Self::R8
153            | Self::R9
154            | Self::R10
155            | Self::R11
156            | Self::R12
157            | Self::R13
158            | Self::R14
159            | Self::R15 => GPRKind::Bit64,
160        }
161    }
162
163    /// Represents the size of the [`GPR`].
164    pub const fn size(self) -> Size {
165        match self {
166            Self::AH
167            | Self::BH
168            | Self::CH
169            | Self::DH
170            | Self::AL
171            | Self::CL
172            | Self::DL
173            | Self::BL
174            | Self::SPL
175            | Self::BPL
176            | Self::SIL
177            | Self::DIL
178            | Self::R8B
179            | Self::R9B
180            | Self::R10B
181            | Self::R11B
182            | Self::R12B
183            | Self::R13B
184            | Self::R14B
185            | Self::R15B => Size::Bit8,
186            Self::AX
187            | Self::CX
188            | Self::DX
189            | Self::BX
190            | Self::SP
191            | Self::BP
192            | Self::SI
193            | Self::DI
194            | Self::R8W
195            | Self::R9W
196            | Self::R10W
197            | Self::R11W
198            | Self::R12W
199            | Self::R13W
200            | Self::R14W
201            | Self::R15W => Size::Bit16,
202            Self::EAX
203            | Self::ECX
204            | Self::EDX
205            | Self::EBX
206            | Self::ESP
207            | Self::EBP
208            | Self::ESI
209            | Self::EDI
210            | Self::R8D
211            | Self::R9D
212            | Self::R10D
213            | Self::R11D
214            | Self::R12D
215            | Self::R13D
216            | Self::R14D
217            | Self::R15D => Size::Bit32,
218            Self::RAX
219            | Self::RCX
220            | Self::RDX
221            | Self::RBX
222            | Self::RSP
223            | Self::RBP
224            | Self::RSI
225            | Self::RDI
226            | Self::R8
227            | Self::R9
228            | Self::R10
229            | Self::R11
230            | Self::R12
231            | Self::R13
232            | Self::R14
233            | Self::R15 => Size::Bit64,
234        }
235    }
236
237    /// Returns the index of the [`GPR`]. The purpose of the index is to be used
238    /// as a part of binary encoding, as used by Intel.
239    #[must_use]
240    pub(crate) const fn index(self) -> u8 {
241        match self {
242            Self::RAX | Self::EAX | Self::AX | Self::AL => 0,
243            Self::RCX | Self::ECX | Self::CX | Self::CL => 1,
244            Self::RDX | Self::EDX | Self::DX | Self::DL => 2,
245            Self::RBX | Self::EBX | Self::BX | Self::BL => 3,
246            Self::RSP | Self::ESP | Self::SP | Self::SPL | Self::AH => 4,
247            Self::RBP | Self::EBP | Self::BP | Self::BPL | Self::CH => 5,
248            Self::RSI | Self::ESI | Self::SI | Self::SIL | Self::DH => 6,
249            Self::RDI | Self::EDI | Self::DI | Self::DIL | Self::BH => 7,
250            Self::R8 | Self::R8D | Self::R8W | Self::R8B => 8,
251            Self::R9 | Self::R9D | Self::R9W | Self::R9B => 9,
252            Self::R10 | Self::R10D | Self::R10W | Self::R10B => 10,
253            Self::R11 | Self::R11D | Self::R11W | Self::R11B => 11,
254            Self::R12 | Self::R12D | Self::R12W | Self::R12B => 12,
255            Self::R13 | Self::R13D | Self::R13W | Self::R13B => 13,
256            Self::R14 | Self::R14D | Self::R14W | Self::R14B => 14,
257            Self::R15 | Self::R15D | Self::R15W | Self::R15B => 15,
258        }
259    }
260
261    /// Returns true if the [`GPR`] is extended. This typically means
262    /// registers with numerical names, e.g. R8, R9, etc.
263    #[inline(always)]
264    #[must_use]
265    pub(crate) const fn is_extended(self) -> bool {
266        self.index() > 0b111
267    }
268
269    /// Lower 3 bits of the index of the [`GPR`].
270    #[inline(always)]
271    #[must_use]
272    pub(crate) const fn lower_3_bits_index(self) -> u8 {
273        self.index() & 0b111
274    }
275
276    /// This function verifies that the index of given GPR matches
277    /// the index of AH, CH, DH or BH registers. Meaning it is in
278    /// the `4..=7` range. This is important, since those registers
279    /// share the index with SPL, BPL, SIL and DIL registers (which
280    /// are of the same size). And have to be encoded differently,
281    /// typically by using Operand Size Override prefix.
282    #[inline(always)]
283    #[must_use]
284    pub(crate) const fn index_matches_bit8_high(self) -> bool {
285        let idx = self.index();
286        idx >= 4 && idx <= 7
287    }
288
289    #[inline(always)]
290    #[must_use]
291    pub(crate) const fn as_u8(self) -> u8 {
292        unsafe {
293            let result = transmute::<Self, u8>(self);
294            core::hint::assert_unchecked(result > 0);
295            core::hint::assert_unchecked(result <= 68);
296            result
297        }
298    }
299
300    #[inline]
301    #[allow(dead_code)]
302    pub(crate) const fn from_u8(value: u8) -> Self {
303        debug_assert!(value > 0 && value <= 68, "Invalid GPR value");
304        unsafe { transmute(value) }
305    }
306}