juicebox_asm/mem.rs
1// SPDX-License-Identifier: MIT
2//
3// Copyright (c) 2024, Johannes Stoelp <dev@memzero.de>
4
5//! Definition of different addressing modes and memory operande used as input
6//! and ouput operands in various instructions.
7
8use crate::Reg64;
9
10#[derive(Clone, Copy)]
11pub(crate) enum AddrMode {
12 /// An indirect memory operand, eg `mov [rax], rcx`.
13 Indirect,
14 /// An indirect memory operand with additional displacement, eg `mov [rax + 0x10], rcx`.
15 IndirectDisp,
16 /// An indirect memory operand in the form base + index, eg `mov [rax + rcx], rdx`.
17 IndirectBaseIndex,
18}
19
20/// Trait to interact with memory operands.
21pub(crate) trait Mem {
22 /// Get the addressing mode [`AddrMode`] of the memory operand.
23 fn mode(&self) -> AddrMode;
24
25 /// Get the base address register of the memory operand.
26 fn base(&self) -> Reg64;
27
28 /// Get the index register of the memory operand.
29 fn index(&self) -> Reg64;
30
31 /// Get the displacement of the memory operand.
32 fn disp(&self) -> i32;
33
34 /// Check if memory operand is 64 bit.
35 fn is_64() -> bool;
36}
37
38macro_rules! impl_mem {
39 ($(#[$doc:meta] $name:ident)+) => {
40 $(
41 #[$doc]
42 pub struct $name {
43 mode: AddrMode,
44 base: Reg64,
45 index: Reg64,
46 disp: i32,
47 }
48
49 impl Mem for $name {
50 fn mode(&self) -> AddrMode {
51 self.mode
52 }
53
54 fn base(&self) -> Reg64 {
55 self.base
56 }
57
58 fn index(&self) -> Reg64 {
59 self.index
60 }
61
62 fn disp(&self) -> i32 {
63 self.disp
64 }
65
66 fn is_64() -> bool {
67 use std::any::TypeId;
68 TypeId::of::<Self>() == TypeId::of::<Mem64>()
69 }
70 }
71
72 impl $name {
73 /// Create a memory operand with `indirect` addressing mode.
74 /// For example `mov [rax], rcx`.
75 pub fn indirect(base: Reg64) -> Self {
76 Self {
77 mode: AddrMode::Indirect,
78 base,
79 index: Reg64::rax, /* zero index */
80 disp: 0,
81 }
82 }
83
84 /// Create a memory operand with `indirect + displacement`
85 /// addressing mode.
86 /// For example `mov [rax + 0x10], rcx`.
87 pub fn indirect_disp(base: Reg64, disp: i32) -> Self {
88 Self {
89 mode: AddrMode::IndirectDisp,
90 base,
91 index: Reg64::rax, /* zero index */
92 disp,
93 }
94 }
95
96 /// Create a memory operand with `base + index` addressing mode.
97 /// For example `mov [rax + rcx], rdx`.
98 pub fn indirect_base_index(base: Reg64, index: Reg64) -> Self {
99 Self {
100 mode: AddrMode::IndirectBaseIndex,
101 base,
102 index,
103 disp: 0,
104 }
105 }
106 }
107 )+
108 }
109}
110
111impl_mem!(
112 /// A memory operand with `byte` size (8 bit).
113 Mem8
114 /// A memory operand with `word` size (16 bit).
115 Mem16
116 /// A memory operand with `dword` size (32 bit).
117 Mem32
118 /// A memory operand with `qword` size (64 bit).
119 Mem64
120);