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);