1use crate::isa::Register;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct MemoryOperand {
12 pub segment: Register,
14 pub base: Register,
16 pub index: Register,
18 pub scale: u8,
20 pub displacement: i64,
22 pub disp_size: u8,
24}
25
26impl MemoryOperand {
27 #[must_use]
29 pub const fn new() -> Self {
30 Self {
31 segment: Register::None,
32 base: Register::None,
33 index: Register::None,
34 scale: 1,
35 displacement: 0,
36 disp_size: 0,
37 }
38 }
39
40 #[must_use]
42 pub const fn base(base: Register) -> Self {
43 Self {
44 segment: Register::None,
45 base,
46 index: Register::None,
47 scale: 1,
48 displacement: 0,
49 disp_size: 0,
50 }
51 }
52
53 #[must_use]
55 pub const fn base_disp(base: Register, displacement: i64) -> Self {
56 Self {
57 segment: Register::None,
58 base,
59 index: Register::None,
60 scale: 1,
61 displacement,
62 disp_size: 0, }
64 }
65
66 #[must_use]
68 pub const fn base_index_scale(base: Register, index: Register, scale: u8) -> Self {
69 Self {
70 segment: Register::None,
71 base,
72 index,
73 scale,
74 displacement: 0,
75 disp_size: 0,
76 }
77 }
78
79 #[must_use]
81 pub const fn full(
82 segment: Register,
83 base: Register,
84 index: Register,
85 scale: u8,
86 displacement: i64,
87 ) -> Self {
88 Self {
89 segment,
90 base,
91 index,
92 scale,
93 displacement,
94 disp_size: 0,
95 }
96 }
97
98 #[must_use]
100 pub const fn with_segment(mut self, segment: Register) -> Self {
101 self.segment = segment;
102 self
103 }
104
105 #[must_use]
107 pub const fn with_displacement(mut self, displacement: i64) -> Self {
108 self.displacement = displacement;
109 self
110 }
111
112 #[must_use]
114 pub const fn is_rip_relative(&self) -> bool {
115 matches!(self.base, Register::RIP | Register::EIP | Register::IP)
116 }
117
118 #[must_use]
120 pub fn requires_sib(&self) -> bool {
121 self.index != Register::None
125 || matches!(
126 self.base,
127 Register::RSP
128 | Register::ESP
129 | Register::SP
130 | Register::R12
131 | Register::R12D
132 | Register::R12W
133 )
134 }
135
136 #[must_use]
138 pub const fn is_valid_scale(&self) -> bool {
139 matches!(self.scale, 1 | 2 | 4 | 8)
140 }
141
142 #[must_use]
144 pub fn has_base(&self) -> bool {
145 self.base != Register::None
146 }
147
148 #[must_use]
150 pub fn has_index(&self) -> bool {
151 self.index != Register::None
152 }
153
154 #[must_use]
156 pub const fn has_displacement(&self) -> bool {
157 self.displacement != 0
158 }
159}
160
161impl Default for MemoryOperand {
162 fn default() -> Self {
163 Self::new()
164 }
165}
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
171pub enum EncoderOperand {
172 #[default]
174 None,
175 Reg(Register),
177 Mem(MemoryOperand),
179 Imm(u64),
181 Rel(i32),
183}
184
185impl EncoderOperand {
186 #[must_use]
188 pub const fn reg(register: Register) -> Self {
189 Self::Reg(register)
190 }
191
192 #[must_use]
194 pub const fn mem(memory: MemoryOperand) -> Self {
195 Self::Mem(memory)
196 }
197
198 #[must_use]
200 pub const fn imm(value: u64) -> Self {
201 Self::Imm(value)
202 }
203
204 #[must_use]
206 pub const fn rel(offset: i32) -> Self {
207 Self::Rel(offset)
208 }
209
210 #[must_use]
212 pub const fn is_register(&self) -> bool {
213 matches!(self, Self::Reg(_))
214 }
215
216 #[must_use]
218 pub const fn is_memory(&self) -> bool {
219 matches!(self, Self::Mem(_))
220 }
221
222 #[must_use]
224 pub const fn is_immediate(&self) -> bool {
225 matches!(self, Self::Imm(_))
226 }
227
228 #[must_use]
230 pub const fn is_relative(&self) -> bool {
231 matches!(self, Self::Rel(_))
232 }
233
234 #[must_use]
236 pub const fn as_register(&self) -> Option<Register> {
237 match self {
238 Self::Reg(reg) => Some(*reg),
239 _ => None,
240 }
241 }
242
243 #[must_use]
245 pub const fn as_memory(&self) -> Option<&MemoryOperand> {
246 match self {
247 Self::Mem(mem) => Some(mem),
248 _ => None,
249 }
250 }
251
252 #[must_use]
254 pub const fn as_immediate(&self) -> Option<u64> {
255 match self {
256 Self::Imm(value) => Some(*value),
257 _ => None,
258 }
259 }
260
261 #[must_use]
263 pub const fn as_relative(&self) -> Option<i32> {
264 match self {
265 Self::Rel(offset) => Some(*offset),
266 _ => None,
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_memory_operand_new() {
277 let mem = MemoryOperand::new();
278 assert_eq!(mem.base, Register::None);
279 assert_eq!(mem.index, Register::None);
280 assert_eq!(mem.scale, 1);
281 assert_eq!(mem.displacement, 0);
282 }
283
284 #[test]
285 fn test_memory_operand_base() {
286 let mem = MemoryOperand::base(Register::RAX);
287 assert_eq!(mem.base, Register::RAX);
288 assert_eq!(mem.index, Register::None);
289 assert!(!mem.requires_sib());
290 }
291
292 #[test]
293 fn test_memory_operand_base_disp() {
294 let mem = MemoryOperand::base_disp(Register::RBP, -16);
295 assert_eq!(mem.base, Register::RBP);
296 assert_eq!(mem.displacement, -16);
297 }
298
299 #[test]
300 fn test_memory_operand_base_index_scale() {
301 let mem = MemoryOperand::base_index_scale(Register::RAX, Register::RCX, 4);
302 assert_eq!(mem.base, Register::RAX);
303 assert_eq!(mem.index, Register::RCX);
304 assert_eq!(mem.scale, 4);
305 assert!(mem.requires_sib());
306 }
307
308 #[test]
309 fn test_memory_operand_requires_sib() {
310 let mem = MemoryOperand::base(Register::RSP);
312 assert!(mem.requires_sib());
313
314 let mem = MemoryOperand::base(Register::R12);
316 assert!(mem.requires_sib());
317
318 let mem = MemoryOperand::base_index_scale(Register::RAX, Register::RCX, 1);
320 assert!(mem.requires_sib());
321
322 let mem = MemoryOperand::base(Register::RAX);
324 assert!(!mem.requires_sib());
325 }
326
327 #[test]
328 fn test_memory_operand_rip_relative() {
329 let mem = MemoryOperand::base(Register::RIP);
330 assert!(mem.is_rip_relative());
331
332 let mem = MemoryOperand::base(Register::RAX);
333 assert!(!mem.is_rip_relative());
334 }
335
336 #[test]
337 fn test_encoder_operand_reg() {
338 let op = EncoderOperand::reg(Register::RAX);
339 assert!(op.is_register());
340 assert!(!op.is_memory());
341 assert_eq!(op.as_register(), Some(Register::RAX));
342 }
343
344 #[test]
345 fn test_encoder_operand_mem() {
346 let mem = MemoryOperand::base(Register::RBP);
347 let op = EncoderOperand::mem(mem);
348 assert!(op.is_memory());
349 assert!(!op.is_register());
350 }
351
352 #[test]
353 fn test_encoder_operand_imm() {
354 let op = EncoderOperand::imm(0x12345678);
355 assert!(op.is_immediate());
356 assert_eq!(op.as_immediate(), Some(0x12345678));
357 }
358
359 #[test]
360 fn test_encoder_operand_rel() {
361 let op = EncoderOperand::rel(-128);
362 assert!(op.is_relative());
363 assert_eq!(op.as_relative(), Some(-128));
364 }
365
366 #[test]
367 fn test_encoder_operand_default() {
368 let op = EncoderOperand::default();
369 assert!(matches!(op, EncoderOperand::None));
370 }
371}