Skip to main content

luaur_code_gen/records/
operand_x_64.rs

1use crate::enums::category_x_64::CategoryX64;
2use crate::enums::size_x_64::SizeX64;
3use crate::records::register_x_64::RegisterX64;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6#[repr(C)]
7pub struct OperandX64 {
8    pub(crate) cat: CategoryX64,
9    pub(crate) index: RegisterX64,
10    pub(crate) base: RegisterX64,
11    pub(crate) memSize: SizeX64,
12    pub(crate) scale: u8,
13    // Public in the C++ `OperandX64` struct; the constant-cache tests read `.imm`.
14    pub imm: i32,
15}
16
17impl OperandX64 {
18    pub const fn reg(reg: RegisterX64) -> Self {
19        Self {
20            cat: CategoryX64::reg,
21            index: RegisterX64::noreg,
22            base: reg,
23            memSize: SizeX64::none,
24            scale: 1,
25            imm: 0,
26        }
27    }
28
29    pub const fn imm(imm: i32) -> Self {
30        Self {
31            cat: CategoryX64::imm,
32            // C++ uses `index(noreg), base(noreg)` — NOT register index 0. The
33            // `{bits:0}` mistranslation made `qword[imm]` absolute addressing look
34            // like it had base/index registers (wrong SIB/ModRM).
35            index: RegisterX64::noreg,
36            base: RegisterX64::noreg,
37            memSize: SizeX64::none,
38            scale: 1,
39            imm,
40        }
41    }
42
43    pub const fn mem(
44        size: SizeX64,
45        index: RegisterX64,
46        scale: u8,
47        base: RegisterX64,
48        disp: i32,
49    ) -> Self {
50        Self {
51            cat: CategoryX64::mem,
52            index,
53            base,
54            memSize: size,
55            scale,
56            imm: disp,
57        }
58    }
59
60    pub const fn operator_bracket(&self, mut address: OperandX64) -> OperandX64 {
61        // CODEGEN_ASSERT(cat == CategoryX64::mem);
62        // CODEGEN_ASSERT(index == noreg && scale == 1 && base == noreg && imm == 0);
63        // CODEGEN_ASSERT(address.memSize == SizeX64::none);
64
65        address.cat = CategoryX64::mem;
66        address.memSize = self.memSize;
67        address
68    }
69}
70
71// OperandX64.h:75-81 — namespace-level size-prefix memory-operand globals. Used
72// as `qword[rax]` in the assembler/tests: the `[]` is `operator_bracket`, which
73// stamps this operand's `memSize` onto the address expression. They are C++
74// `inline constexpr OperandX64 name{size, noreg, 1, noreg, 0}` (the `mem` ctor).
75#[allow(non_upper_case_globals)]
76pub const addr: OperandX64 =
77    OperandX64::mem(SizeX64::none, RegisterX64::noreg, 1, RegisterX64::noreg, 0);
78#[allow(non_upper_case_globals)]
79pub const byte: OperandX64 =
80    OperandX64::mem(SizeX64::byte, RegisterX64::noreg, 1, RegisterX64::noreg, 0);
81#[allow(non_upper_case_globals)]
82pub const word: OperandX64 =
83    OperandX64::mem(SizeX64::word, RegisterX64::noreg, 1, RegisterX64::noreg, 0);
84#[allow(non_upper_case_globals)]
85pub const dword: OperandX64 =
86    OperandX64::mem(SizeX64::dword, RegisterX64::noreg, 1, RegisterX64::noreg, 0);
87#[allow(non_upper_case_globals)]
88pub const qword: OperandX64 =
89    OperandX64::mem(SizeX64::qword, RegisterX64::noreg, 1, RegisterX64::noreg, 0);
90#[allow(non_upper_case_globals)]
91pub const xmmword: OperandX64 = OperandX64::mem(
92    SizeX64::xmmword,
93    RegisterX64::noreg,
94    1,
95    RegisterX64::noreg,
96    0,
97);
98#[allow(non_upper_case_globals)]
99pub const ymmword: OperandX64 = OperandX64::mem(
100    SizeX64::ymmword,
101    RegisterX64::noreg,
102    1,
103    RegisterX64::noreg,
104    0,
105);
106
107/// C++ implicit `OperandX64(RegisterX64 reg)` constructor.
108impl From<RegisterX64> for OperandX64 {
109    fn from(reg: RegisterX64) -> Self {
110        Self::reg(reg)
111    }
112}
113
114/// C++ implicit `OperandX64(int32_t imm)` constructor.
115impl From<i32> for OperandX64 {
116    fn from(imm: i32) -> Self {
117        Self::imm(imm)
118    }
119}
120
121// Ergonomic addressing-mode operators, delegating to the translated free
122// functions so `qword[rax + r12 * 2 + 0x1b]`-style operands read like the C++
123// (OperandX64.h `operator*`/`operator+`/`operator-`). The `[]` itself stays
124// `operator_bracket` (Rust `Index` must return a reference, so it can't model
125// the by-value size-stamping the assembler relies on).
126impl core::ops::Mul<i32> for RegisterX64 {
127    type Output = OperandX64;
128    fn mul(self, scale: i32) -> OperandX64 {
129        crate::functions::operator_deref::operator_deref(self, scale as u8)
130    }
131}
132
133impl core::ops::Add<i32> for RegisterX64 {
134    type Output = OperandX64;
135    fn add(self, disp: i32) -> OperandX64 {
136        crate::functions::operator_add_operand_x_64::operator_add_register_x_64_i32(self, disp)
137    }
138}
139
140impl core::ops::Sub<i32> for RegisterX64 {
141    type Output = OperandX64;
142    fn sub(self, disp: i32) -> OperandX64 {
143        crate::functions::operator_sub::operator_sub(self, disp)
144    }
145}
146
147impl core::ops::Add<RegisterX64> for RegisterX64 {
148    type Output = OperandX64;
149    fn add(self, index: RegisterX64) -> OperandX64 {
150        crate::functions::operator_add_operand_x_64_alt_b::operator_add_register_x_64_register_x_64(
151            self, index,
152        )
153    }
154}
155
156impl core::ops::Add<OperandX64> for RegisterX64 {
157    type Output = OperandX64;
158    fn add(self, op: OperandX64) -> OperandX64 {
159        crate::functions::operator_add_operand_x_64_alt_e::operator_add_register_x_64_operand_x_64(
160            self, op,
161        )
162    }
163}
164
165impl core::ops::Add<i32> for OperandX64 {
166    type Output = OperandX64;
167    fn add(self, disp: i32) -> OperandX64 {
168        crate::functions::operator_add_operand_x_64_alt_c::operator_add_operand_x_64_i32(self, disp)
169    }
170}
171
172impl core::ops::Add<RegisterX64> for OperandX64 {
173    type Output = OperandX64;
174    fn add(self, base: RegisterX64) -> OperandX64 {
175        crate::functions::operator_add_operand_x_64_alt_d::operator_add_operand_x_64_register_x_64(
176            self, base,
177        )
178    }
179}