/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cranelift-assembler-x64-0.129.1/src/mem.rs
Line | Count | Source |
1 | | //! Memory operands to instructions. |
2 | | |
3 | | use alloc::string::{String, ToString}; |
4 | | |
5 | | use crate::api::{AsReg, CodeSink, Constant, KnownOffset, Label, TrapCode}; |
6 | | use crate::gpr::{self, NonRspGpr, Size}; |
7 | | use crate::rex::{Disp, RexPrefix, encode_modrm, encode_sib}; |
8 | | |
9 | | /// x64 memory addressing modes. |
10 | | #[derive(Copy, Clone, Debug, PartialEq)] |
11 | | #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] |
12 | | pub enum Amode<R: AsReg> { |
13 | | ImmReg { |
14 | | base: R, |
15 | | simm32: AmodeOffsetPlusKnownOffset, |
16 | | trap: Option<TrapCode>, |
17 | | }, |
18 | | ImmRegRegShift { |
19 | | base: R, |
20 | | index: NonRspGpr<R>, |
21 | | scale: Scale, |
22 | | simm32: AmodeOffset, |
23 | | trap: Option<TrapCode>, |
24 | | }, |
25 | | RipRelative { |
26 | | target: DeferredTarget, |
27 | | }, |
28 | | } |
29 | | |
30 | | impl<R: AsReg> Amode<R> { |
31 | | /// Return the [`TrapCode`] associated with this [`Amode`], if any. |
32 | 8.70M | pub fn trap_code(&self) -> Option<TrapCode> { |
33 | 8.70M | match self { |
34 | 8.63M | Amode::ImmReg { trap, .. } | Amode::ImmRegRegShift { trap, .. } => *trap, |
35 | 70.9k | Amode::RipRelative { .. } => None, |
36 | | } |
37 | 8.70M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::trap_code Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<_>>::trap_code <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::trap_code Line | Count | Source | 32 | 8.70M | pub fn trap_code(&self) -> Option<TrapCode> { | 33 | 8.70M | match self { | 34 | 8.63M | Amode::ImmReg { trap, .. } | Amode::ImmRegRegShift { trap, .. } => *trap, | 35 | 70.9k | Amode::RipRelative { .. } => None, | 36 | | } | 37 | 8.70M | } |
|
38 | | |
39 | | /// Return the [`RexPrefix`] for each variant of this [`Amode`]. |
40 | | #[must_use] |
41 | 7.68M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { |
42 | 7.68M | match self { |
43 | 7.56M | Amode::ImmReg { base, .. } => { |
44 | 7.56M | RexPrefix::mem_op(enc_reg, base.enc(), has_w_bit, uses_8bit) |
45 | | } |
46 | 96.6k | Amode::ImmRegRegShift { base, index, .. } => { |
47 | 96.6k | RexPrefix::three_op(enc_reg, index.enc(), base.enc(), has_w_bit, uses_8bit) |
48 | | } |
49 | 25.4k | Amode::RipRelative { .. } => RexPrefix::two_op(enc_reg, 0, has_w_bit, uses_8bit), |
50 | | } |
51 | 7.68M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<_>>::as_rex_prefix <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 41 | 7.68M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 42 | 7.68M | match self { | 43 | 7.56M | Amode::ImmReg { base, .. } => { | 44 | 7.56M | RexPrefix::mem_op(enc_reg, base.enc(), has_w_bit, uses_8bit) | 45 | | } | 46 | 96.6k | Amode::ImmRegRegShift { base, index, .. } => { | 47 | 96.6k | RexPrefix::three_op(enc_reg, index.enc(), base.enc(), has_w_bit, uses_8bit) | 48 | | } | 49 | 25.4k | Amode::RipRelative { .. } => RexPrefix::two_op(enc_reg, 0, has_w_bit, uses_8bit), | 50 | | } | 51 | 7.68M | } |
|
52 | | |
53 | | /// Emit the ModR/M, SIB, and displacement suffixes as needed for this |
54 | | /// `Amode`. |
55 | 8.70M | pub(crate) fn encode_rex_suffixes( |
56 | 8.70M | &self, |
57 | 8.70M | sink: &mut impl CodeSink, |
58 | 8.70M | enc_reg: u8, |
59 | 8.70M | bytes_at_end: u8, |
60 | 8.70M | evex_scaling: Option<i8>, |
61 | 8.70M | ) { |
62 | 8.70M | emit_modrm_sib_disp(sink, enc_reg, self, bytes_at_end, evex_scaling); |
63 | 8.70M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<_>>::encode_rex_suffixes::<_> <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 55 | 8.70M | pub(crate) fn encode_rex_suffixes( | 56 | 8.70M | &self, | 57 | 8.70M | sink: &mut impl CodeSink, | 58 | 8.70M | enc_reg: u8, | 59 | 8.70M | bytes_at_end: u8, | 60 | 8.70M | evex_scaling: Option<i8>, | 61 | 8.70M | ) { | 62 | 8.70M | emit_modrm_sib_disp(sink, enc_reg, self, bytes_at_end, evex_scaling); | 63 | 8.70M | } |
|
64 | | |
65 | | /// Return the registers for encoding the `b` and `x` bits (e.g., in a VEX |
66 | | /// prefix). |
67 | | /// |
68 | | /// During encoding, the `b` bit is set by the topmost bit (the fourth bit) |
69 | | /// of either the `reg` register or, if this is a memory address, the `base` |
70 | | /// register. The `x` bit is set by the `index` register, when used. |
71 | 1.02M | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { |
72 | 1.02M | match self { |
73 | 972k | Amode::ImmReg { base, .. } => (Some(base.enc()), None), |
74 | 4.29k | Amode::ImmRegRegShift { base, index, .. } => (Some(base.enc()), Some(index.enc())), |
75 | 45.5k | Amode::RipRelative { .. } => (None, None), |
76 | | } |
77 | 1.02M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<_>>::encode_bx_regs <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Line | Count | Source | 71 | 1.02M | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { | 72 | 1.02M | match self { | 73 | 972k | Amode::ImmReg { base, .. } => (Some(base.enc()), None), | 74 | 4.29k | Amode::ImmRegRegShift { base, index, .. } => (Some(base.enc()), Some(index.enc())), | 75 | 45.5k | Amode::RipRelative { .. } => (None, None), | 76 | | } | 77 | 1.02M | } |
|
78 | | } |
79 | | |
80 | | /// A 32-bit immediate for address offsets. |
81 | | #[derive(Clone, Copy, Debug, PartialEq)] |
82 | | pub struct AmodeOffset(i32); |
83 | | |
84 | | impl AmodeOffset { |
85 | | pub const ZERO: AmodeOffset = AmodeOffset::new(0); |
86 | | |
87 | | #[must_use] |
88 | 0 | pub const fn new(value: i32) -> Self { |
89 | 0 | Self(value) |
90 | 0 | } |
91 | | |
92 | | #[must_use] |
93 | 8.64M | pub fn value(self) -> i32 { |
94 | 8.64M | self.0 |
95 | 8.64M | } |
96 | | } |
97 | | |
98 | | impl From<i32> for AmodeOffset { |
99 | 8.64M | fn from(value: i32) -> Self { |
100 | 8.64M | Self(value) |
101 | 8.64M | } |
102 | | } |
103 | | |
104 | | impl core::fmt::LowerHex for AmodeOffset { |
105 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
106 | | // This rather complex implementation is necessary to match how |
107 | | // `capstone` pretty-prints memory immediates. |
108 | 0 | if self.0 == 0 { |
109 | 0 | return Ok(()); |
110 | 0 | } |
111 | 0 | if self.0 < 0 { |
112 | 0 | write!(f, "-")?; |
113 | 0 | } |
114 | 0 | if self.0 > 9 || self.0 < -9 { |
115 | 0 | write!(f, "0x")?; |
116 | 0 | } |
117 | 0 | let abs = match self.0.checked_abs() { |
118 | 0 | Some(i) => i, |
119 | 0 | None => -2_147_483_648, |
120 | | }; |
121 | 0 | core::fmt::LowerHex::fmt(&abs, f) |
122 | 0 | } |
123 | | } |
124 | | |
125 | | /// An [`AmodeOffset`] immediate with an optional known offset. |
126 | | /// |
127 | | /// Cranelift does not know certain offsets until emission time. To accommodate |
128 | | /// Cranelift, this structure stores an optional [`KnownOffset`]. The following |
129 | | /// happens immediately before emission: |
130 | | /// - the [`KnownOffset`] is looked up, mapping it to an offset value |
131 | | /// - the [`AmodeOffset`] value is added to the offset value |
132 | | #[derive(Copy, Clone, Debug, PartialEq)] |
133 | | pub struct AmodeOffsetPlusKnownOffset { |
134 | | pub simm32: AmodeOffset, |
135 | | pub offset: Option<KnownOffset>, |
136 | | } |
137 | | |
138 | | impl AmodeOffsetPlusKnownOffset { |
139 | | pub const ZERO: AmodeOffsetPlusKnownOffset = AmodeOffsetPlusKnownOffset { |
140 | | simm32: AmodeOffset::ZERO, |
141 | | offset: None, |
142 | | }; |
143 | | |
144 | | /// # Panics |
145 | | /// |
146 | | /// Panics if the sum of the immediate and the known offset value overflows. |
147 | | #[must_use] |
148 | 8.53M | pub fn value(&self, sink: &impl CodeSink) -> i32 { |
149 | 8.53M | let known_offset = match self.offset { |
150 | 1.93M | Some(offset) => sink.known_offset(offset), |
151 | 6.60M | None => 0, |
152 | | }; |
153 | 8.53M | known_offset |
154 | 8.53M | .checked_add(self.simm32.value()) |
155 | 8.53M | .expect("no wrapping") |
156 | 8.53M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::AmodeOffsetPlusKnownOffset>::value::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::AmodeOffsetPlusKnownOffset>::value::<_> <cranelift_assembler_x64::mem::AmodeOffsetPlusKnownOffset>::value::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 148 | 8.53M | pub fn value(&self, sink: &impl CodeSink) -> i32 { | 149 | 8.53M | let known_offset = match self.offset { | 150 | 1.93M | Some(offset) => sink.known_offset(offset), | 151 | 6.60M | None => 0, | 152 | | }; | 153 | 8.53M | known_offset | 154 | 8.53M | .checked_add(self.simm32.value()) | 155 | 8.53M | .expect("no wrapping") | 156 | 8.53M | } |
|
157 | | } |
158 | | |
159 | | impl core::fmt::LowerHex for AmodeOffsetPlusKnownOffset { |
160 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
161 | 0 | if let Some(offset) = self.offset { |
162 | 0 | write!(f, "<offset:{offset}>+")?; |
163 | 0 | } |
164 | 0 | core::fmt::LowerHex::fmt(&self.simm32, f) |
165 | 0 | } |
166 | | } |
167 | | |
168 | | /// For RIP-relative addressing, keep track of the [`CodeSink`]-specific target. |
169 | | #[derive(Copy, Clone, Debug, PartialEq)] |
170 | | #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] |
171 | | pub enum DeferredTarget { |
172 | | Label(Label), |
173 | | Constant(Constant), |
174 | | None, |
175 | | } |
176 | | |
177 | | impl<R: AsReg> core::fmt::Display for Amode<R> { |
178 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
179 | 0 | let pointer_width = Size::Quadword; |
180 | 0 | match self { |
181 | 0 | Amode::ImmReg { simm32, base, .. } => { |
182 | | // Note: size is always 8; the address is 64 bits, |
183 | | // even if the addressed operand is smaller. |
184 | 0 | let base = base.to_string(Some(pointer_width)); |
185 | 0 | write!(f, "{simm32:x}({base})") |
186 | | } |
187 | | Amode::ImmRegRegShift { |
188 | 0 | simm32, |
189 | 0 | base, |
190 | 0 | index, |
191 | 0 | scale, |
192 | | .. |
193 | | } => { |
194 | 0 | let base = base.to_string(Some(pointer_width)); |
195 | 0 | let index = index.to_string(pointer_width); |
196 | 0 | let shift = scale.shift(); |
197 | 0 | if shift > 1 { |
198 | 0 | write!(f, "{simm32:x}({base}, {index}, {shift})") |
199 | | } else { |
200 | 0 | write!(f, "{simm32:x}({base}, {index})") |
201 | | } |
202 | | } |
203 | 0 | Amode::RipRelative { .. } => write!(f, "(%rip)"), |
204 | | } |
205 | 0 | } Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr> as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<_> as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr> as core::fmt::Display>::fmt |
206 | | } |
207 | | |
208 | | /// The scaling factor for the index register in certain [`Amode`]s. |
209 | | #[derive(Copy, Clone, Debug, PartialEq)] |
210 | | #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] |
211 | | pub enum Scale { |
212 | | One, |
213 | | Two, |
214 | | Four, |
215 | | Eight, |
216 | | } |
217 | | |
218 | | impl Scale { |
219 | | /// Create a new [`Scale`] from its hardware encoding. |
220 | | /// |
221 | | /// # Panics |
222 | | /// |
223 | | /// Panics if `enc` is not a valid encoding for a scale (0-3). |
224 | | #[must_use] |
225 | 103k | pub fn new(enc: u8) -> Self { |
226 | 103k | match enc { |
227 | 103k | 0b00 => Scale::One, |
228 | 6 | 0b01 => Scale::Two, |
229 | 307 | 0b10 => Scale::Four, |
230 | 290 | 0b11 => Scale::Eight, |
231 | 0 | _ => panic!("invalid scale encoding: {enc}"), |
232 | | } |
233 | 103k | } |
234 | | |
235 | | /// Return the hardware encoding of this [`Scale`]. |
236 | 100k | fn enc(&self) -> u8 { |
237 | 100k | match self { |
238 | 100k | Scale::One => 0b00, |
239 | 6 | Scale::Two => 0b01, |
240 | 307 | Scale::Four => 0b10, |
241 | 290 | Scale::Eight => 0b11, |
242 | | } |
243 | 100k | } |
244 | | |
245 | | /// Return how much this [`Scale`] will shift the value in the index |
246 | | /// register of the SIB byte. |
247 | | /// |
248 | | /// This is useful for pretty-printing; when encoding, one usually needs |
249 | | /// [`Scale::enc`]. |
250 | 0 | fn shift(&self) -> u8 { |
251 | 0 | 1 << self.enc() |
252 | 0 | } |
253 | | } |
254 | | |
255 | | /// A general-purpose register or memory operand. |
256 | | #[derive(Copy, Clone, Debug, PartialEq)] |
257 | | #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] |
258 | | #[allow( |
259 | | clippy::module_name_repetitions, |
260 | | reason = "'GprMem' indicates this has GPR and memory variants" |
261 | | )] |
262 | | pub enum GprMem<R: AsReg, M: AsReg> { |
263 | | Gpr(R), |
264 | | Mem(Amode<M>), |
265 | | } |
266 | | |
267 | | impl<R: AsReg, M: AsReg> GprMem<R, M> { |
268 | | /// Pretty-print the operand. |
269 | 0 | pub fn to_string(&self, size: Size) -> String { |
270 | 0 | match self { |
271 | 0 | GprMem::Gpr(gpr) => gpr.to_string(Some(size)), |
272 | 0 | GprMem::Mem(amode) => amode.to_string(), |
273 | | } |
274 | 0 | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string |
275 | | |
276 | | /// Return the [`RexPrefix`] for each variant of this [`GprMem`]. |
277 | | #[must_use] |
278 | 10.3M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { |
279 | 10.3M | match self { |
280 | 4.32M | GprMem::Gpr(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), |
281 | 6.01M | GprMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), |
282 | | } |
283 | 10.3M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _>>::as_rex_prefix <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 278 | 4.73M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 279 | 4.73M | match self { | 280 | 1.77M | GprMem::Gpr(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), | 281 | 2.95M | GprMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), | 282 | | } | 283 | 4.73M | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 278 | 4.93M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 279 | 4.93M | match self { | 280 | 1.98M | GprMem::Gpr(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), | 281 | 2.95M | GprMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), | 282 | | } | 283 | 4.93M | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 278 | 662k | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 279 | 662k | match self { | 280 | 559k | GprMem::Gpr(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), | 281 | 102k | GprMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), | 282 | | } | 283 | 662k | } |
|
284 | | |
285 | | /// Emit the ModR/M, SIB, and displacement suffixes for this [`GprMem`]. |
286 | 10.5M | pub(crate) fn encode_rex_suffixes( |
287 | 10.5M | &self, |
288 | 10.5M | sink: &mut impl CodeSink, |
289 | 10.5M | enc_reg: u8, |
290 | 10.5M | bytes_at_end: u8, |
291 | 10.5M | evex_scaling: Option<i8>, |
292 | 10.5M | ) { |
293 | 10.5M | match self { |
294 | 4.55M | GprMem::Gpr(gpr) => { |
295 | 4.55M | sink.put1(encode_modrm(0b11, enc_reg & 0b111, gpr.enc() & 0b111)); |
296 | 4.55M | } |
297 | 6.01M | GprMem::Mem(amode) => { |
298 | 6.01M | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); |
299 | 6.01M | } |
300 | | } |
301 | 10.5M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _>>::encode_rex_suffixes::<_> <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 286 | 4.76M | pub(crate) fn encode_rex_suffixes( | 287 | 4.76M | &self, | 288 | 4.76M | sink: &mut impl CodeSink, | 289 | 4.76M | enc_reg: u8, | 290 | 4.76M | bytes_at_end: u8, | 291 | 4.76M | evex_scaling: Option<i8>, | 292 | 4.76M | ) { | 293 | 4.76M | match self { | 294 | 1.80M | GprMem::Gpr(gpr) => { | 295 | 1.80M | sink.put1(encode_modrm(0b11, enc_reg & 0b111, gpr.enc() & 0b111)); | 296 | 1.80M | } | 297 | 2.95M | GprMem::Mem(amode) => { | 298 | 2.95M | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); | 299 | 2.95M | } | 300 | | } | 301 | 4.76M | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 286 | 5.13M | pub(crate) fn encode_rex_suffixes( | 287 | 5.13M | &self, | 288 | 5.13M | sink: &mut impl CodeSink, | 289 | 5.13M | enc_reg: u8, | 290 | 5.13M | bytes_at_end: u8, | 291 | 5.13M | evex_scaling: Option<i8>, | 292 | 5.13M | ) { | 293 | 5.13M | match self { | 294 | 2.18M | GprMem::Gpr(gpr) => { | 295 | 2.18M | sink.put1(encode_modrm(0b11, enc_reg & 0b111, gpr.enc() & 0b111)); | 296 | 2.18M | } | 297 | 2.95M | GprMem::Mem(amode) => { | 298 | 2.95M | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); | 299 | 2.95M | } | 300 | | } | 301 | 5.13M | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 286 | 662k | pub(crate) fn encode_rex_suffixes( | 287 | 662k | &self, | 288 | 662k | sink: &mut impl CodeSink, | 289 | 662k | enc_reg: u8, | 290 | 662k | bytes_at_end: u8, | 291 | 662k | evex_scaling: Option<i8>, | 292 | 662k | ) { | 293 | 662k | match self { | 294 | 559k | GprMem::Gpr(gpr) => { | 295 | 559k | sink.put1(encode_modrm(0b11, enc_reg & 0b111, gpr.enc() & 0b111)); | 296 | 559k | } | 297 | 102k | GprMem::Mem(amode) => { | 298 | 102k | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); | 299 | 102k | } | 300 | | } | 301 | 662k | } |
|
302 | | |
303 | | /// Same as `XmmMem::encode_bx_regs`, but for `GprMem`. |
304 | 231k | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { |
305 | 231k | match self { |
306 | 230k | GprMem::Gpr(reg) => (Some(reg.enc()), None), |
307 | 1.12k | GprMem::Mem(amode) => amode.encode_bx_regs(), |
308 | | } |
309 | 231k | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _>>::encode_bx_regs <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Line | Count | Source | 304 | 32.1k | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { | 305 | 32.1k | match self { | 306 | 32.1k | GprMem::Gpr(reg) => (Some(reg.enc()), None), | 307 | 0 | GprMem::Mem(amode) => amode.encode_bx_regs(), | 308 | | } | 309 | 32.1k | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Line | Count | Source | 304 | 199k | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { | 305 | 199k | match self { | 306 | 198k | GprMem::Gpr(reg) => (Some(reg.enc()), None), | 307 | 1.12k | GprMem::Mem(amode) => amode.encode_bx_regs(), | 308 | | } | 309 | 199k | } |
|
310 | | } |
311 | | |
312 | | impl<R: AsReg, M: AsReg> From<R> for GprMem<R, M> { |
313 | 1.84M | fn from(reg: R) -> GprMem<R, M> { |
314 | 1.84M | GprMem::Gpr(reg) |
315 | 1.84M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::external::PairedGpr>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _> as core::convert::From<_>>::from <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr>>>::from Line | Count | Source | 313 | 1.64M | fn from(reg: R) -> GprMem<R, M> { | 314 | 1.64M | GprMem::Gpr(reg) | 315 | 1.64M | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from Line | Count | Source | 313 | 193k | fn from(reg: R) -> GprMem<R, M> { | 314 | 193k | GprMem::Gpr(reg) | 315 | 193k | } |
<cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::external::PairedGpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::external::PairedGpr>>::from Line | Count | Source | 313 | 6.17k | fn from(reg: R) -> GprMem<R, M> { | 314 | 6.17k | GprMem::Gpr(reg) | 315 | 6.17k | } |
|
316 | | } |
317 | | |
318 | | impl<R: AsReg, M: AsReg> From<Amode<M>> for GprMem<R, M> { |
319 | 0 | fn from(amode: Amode<M>) -> GprMem<R, M> { |
320 | 0 | GprMem::Mem(amode) |
321 | 0 | } Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<_, _> as core::convert::From<cranelift_assembler_x64::mem::Amode<_>>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::GprMem<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_assembler_x64::mem::Amode<cranelift_codegen::isa::x64::inst::args::Gpr>>>::from |
322 | | } |
323 | | |
324 | | /// An XMM register or memory operand. |
325 | | #[derive(Copy, Clone, Debug)] |
326 | | #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] |
327 | | #[allow( |
328 | | clippy::module_name_repetitions, |
329 | | reason = "'XmmMem' indicates this has Xmm and memory variants" |
330 | | )] |
331 | | pub enum XmmMem<R: AsReg, M: AsReg> { |
332 | | Xmm(R), |
333 | | Mem(Amode<M>), |
334 | | } |
335 | | |
336 | | impl<R: AsReg, M: AsReg> XmmMem<R, M> { |
337 | | /// Pretty-print the operand. |
338 | 0 | pub fn to_string(&self) -> String { |
339 | 0 | match self { |
340 | 0 | XmmMem::Xmm(xmm) => xmm.to_string(None), |
341 | 0 | XmmMem::Mem(amode) => amode.to_string(), |
342 | | } |
343 | 0 | } Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<_, _>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::to_string |
344 | | |
345 | | /// Return the [`RexPrefix`] for each variant of this [`XmmMem`]. |
346 | | #[must_use] |
347 | 1.24M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { |
348 | 1.24M | match self { |
349 | 669k | XmmMem::Xmm(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), |
350 | 578k | XmmMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), |
351 | | } |
352 | 1.24M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<_, _>>::as_rex_prefix <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 347 | 83.7k | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 348 | 83.7k | match self { | 349 | 0 | XmmMem::Xmm(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), | 350 | 83.7k | XmmMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), | 351 | | } | 352 | 83.7k | } |
<cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::as_rex_prefix Line | Count | Source | 347 | 1.16M | pub(crate) fn as_rex_prefix(&self, enc_reg: u8, has_w_bit: bool, uses_8bit: bool) -> RexPrefix { | 348 | 1.16M | match self { | 349 | 669k | XmmMem::Xmm(rm) => RexPrefix::two_op(enc_reg, rm.enc(), has_w_bit, uses_8bit), | 350 | 494k | XmmMem::Mem(amode) => amode.as_rex_prefix(enc_reg, has_w_bit, uses_8bit), | 351 | | } | 352 | 1.16M | } |
|
353 | | |
354 | | /// Emit the ModR/M, SIB, and displacement suffixes for this [`XmmMem`]. |
355 | 2.02M | pub(crate) fn encode_rex_suffixes( |
356 | 2.02M | &self, |
357 | 2.02M | sink: &mut impl CodeSink, |
358 | 2.02M | enc_reg: u8, |
359 | 2.02M | bytes_at_end: u8, |
360 | 2.02M | evex_scaling: Option<i8>, |
361 | 2.02M | ) { |
362 | 2.02M | match self { |
363 | 1.39M | XmmMem::Xmm(xmm) => { |
364 | 1.39M | sink.put1(encode_modrm(0b11, enc_reg & 0b111, xmm.enc() & 0b111)); |
365 | 1.39M | } |
366 | 622k | XmmMem::Mem(amode) => { |
367 | 622k | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); |
368 | 622k | } |
369 | | } |
370 | 2.02M | } Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<_, _>>::encode_rex_suffixes::<_> <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 355 | 83.7k | pub(crate) fn encode_rex_suffixes( | 356 | 83.7k | &self, | 357 | 83.7k | sink: &mut impl CodeSink, | 358 | 83.7k | enc_reg: u8, | 359 | 83.7k | bytes_at_end: u8, | 360 | 83.7k | evex_scaling: Option<i8>, | 361 | 83.7k | ) { | 362 | 83.7k | match self { | 363 | 0 | XmmMem::Xmm(xmm) => { | 364 | 0 | sink.put1(encode_modrm(0b11, enc_reg & 0b111, xmm.enc() & 0b111)); | 365 | 0 | } | 366 | 83.7k | XmmMem::Mem(amode) => { | 367 | 83.7k | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); | 368 | 83.7k | } | 369 | | } | 370 | 83.7k | } |
<cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_rex_suffixes::<cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 355 | 1.93M | pub(crate) fn encode_rex_suffixes( | 356 | 1.93M | &self, | 357 | 1.93M | sink: &mut impl CodeSink, | 358 | 1.93M | enc_reg: u8, | 359 | 1.93M | bytes_at_end: u8, | 360 | 1.93M | evex_scaling: Option<i8>, | 361 | 1.93M | ) { | 362 | 1.93M | match self { | 363 | 1.39M | XmmMem::Xmm(xmm) => { | 364 | 1.39M | sink.put1(encode_modrm(0b11, enc_reg & 0b111, xmm.enc() & 0b111)); | 365 | 1.39M | } | 366 | 539k | XmmMem::Mem(amode) => { | 367 | 539k | amode.encode_rex_suffixes(sink, enc_reg, bytes_at_end, evex_scaling); | 368 | 539k | } | 369 | | } | 370 | 1.93M | } |
|
371 | | |
372 | | /// Return the registers for encoding the `b` and `x` bits (e.g., in a VEX |
373 | | /// prefix). |
374 | | /// |
375 | | /// During encoding, the `b` bit is set by the topmost bit (the fourth bit) |
376 | | /// of either the `reg` register or, if this is a memory address, the `base` |
377 | | /// register. The `x` bit is set by the `index` register, when used. |
378 | 774k | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { |
379 | 774k | match self { |
380 | 729k | XmmMem::Xmm(reg) => (Some(reg.enc()), None), |
381 | 44.4k | XmmMem::Mem(amode) => amode.encode_bx_regs(), |
382 | | } |
383 | 774k | } Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<_, _>>::encode_bx_regs Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm>, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr>>::encode_bx_regs Line | Count | Source | 378 | 774k | pub(crate) fn encode_bx_regs(&self) -> (Option<u8>, Option<u8>) { | 379 | 774k | match self { | 380 | 729k | XmmMem::Xmm(reg) => (Some(reg.enc()), None), | 381 | 44.4k | XmmMem::Mem(amode) => amode.encode_bx_regs(), | 382 | | } | 383 | 774k | } |
|
384 | | } |
385 | | |
386 | | impl<R: AsReg, M: AsReg> From<R> for XmmMem<R, M> { |
387 | 127k | fn from(reg: R) -> XmmMem<R, M> { |
388 | 127k | XmmMem::Xmm(reg) |
389 | 127k | } Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from Unexecuted instantiation: <cranelift_assembler_x64::mem::XmmMem<_, _> as core::convert::From<_>>::from <cranelift_assembler_x64::mem::XmmMem<cranelift_codegen::isa::x64::inst::args::Xmm, cranelift_codegen::isa::x64::inst::args::Gpr> as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from Line | Count | Source | 387 | 127k | fn from(reg: R) -> XmmMem<R, M> { | 388 | 127k | XmmMem::Xmm(reg) | 389 | 127k | } |
|
390 | | } |
391 | | |
392 | | impl<R: AsReg, M: AsReg> From<Amode<M>> for XmmMem<R, M> { |
393 | 0 | fn from(amode: Amode<M>) -> XmmMem<R, M> { |
394 | 0 | XmmMem::Mem(amode) |
395 | 0 | } |
396 | | } |
397 | | |
398 | | /// Emit the ModRM/SIB/displacement sequence for a memory operand. |
399 | 8.70M | pub fn emit_modrm_sib_disp<R: AsReg>( |
400 | 8.70M | sink: &mut impl CodeSink, |
401 | 8.70M | enc_g: u8, |
402 | 8.70M | mem_e: &Amode<R>, |
403 | 8.70M | bytes_at_end: u8, |
404 | 8.70M | evex_scaling: Option<i8>, |
405 | 8.70M | ) { |
406 | 8.70M | match *mem_e { |
407 | 8.53M | Amode::ImmReg { simm32, base, .. } => { |
408 | 8.53M | let enc_e = base.enc(); |
409 | 8.53M | let mut imm = Disp::new(simm32.value(sink), evex_scaling); |
410 | | |
411 | | // Most base registers allow for a single ModRM byte plus an |
412 | | // optional immediate. If rsp is the base register, however, then a |
413 | | // SIB byte must be used. |
414 | 8.53M | let enc_e_low3 = enc_e & 7; |
415 | 8.53M | if enc_e_low3 == gpr::enc::RSP { |
416 | 3.88M | // Displacement from RSP is encoded with a SIB byte where |
417 | 3.88M | // the index and base are both encoded as RSP's encoding of |
418 | 3.88M | // 0b100. This special encoding means that the index register |
419 | 3.88M | // isn't used and the base is 0b100 with or without a |
420 | 3.88M | // REX-encoded 4th bit (e.g. rsp or r12) |
421 | 3.88M | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); |
422 | 3.88M | sink.put1(0b00_100_100); |
423 | 3.88M | imm.emit(sink); |
424 | 3.88M | } else { |
425 | | // If the base register is rbp and there's no offset then force |
426 | | // a 1-byte zero offset since otherwise the encoding would be |
427 | | // invalid. |
428 | 4.65M | if enc_e_low3 == gpr::enc::RBP { |
429 | 129k | imm.force_immediate(); |
430 | 4.52M | } |
431 | 4.65M | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, enc_e & 7)); |
432 | 4.65M | imm.emit(sink); |
433 | | } |
434 | | } |
435 | | |
436 | | Amode::ImmRegRegShift { |
437 | 100k | simm32, |
438 | 100k | base, |
439 | 100k | index, |
440 | 100k | scale, |
441 | | .. |
442 | | } => { |
443 | 100k | let enc_base = base.enc(); |
444 | 100k | let enc_index = index.enc(); |
445 | | |
446 | | // Encoding of ModRM/SIB bytes don't allow the index register to |
447 | | // ever be rsp. Note, though, that the encoding of r12, whose three |
448 | | // lower bits match the encoding of rsp, is explicitly allowed with |
449 | | // REX bytes so only rsp is disallowed. |
450 | 100k | assert!(enc_index != gpr::enc::RSP); |
451 | | |
452 | | // If the offset is zero then there is no immediate. Note, though, |
453 | | // that if the base register's lower three bits are `101` then an |
454 | | // offset must be present. This is a special case in the encoding of |
455 | | // the SIB byte and requires an explicit displacement with rbp/r13. |
456 | 100k | let mut imm = Disp::new(simm32.value(), evex_scaling); |
457 | 100k | if enc_base & 7 == gpr::enc::RBP { |
458 | 48 | imm.force_immediate(); |
459 | 100k | } |
460 | | |
461 | | // With the above determined encode the ModRM byte, then the SIB |
462 | | // byte, then any immediate as necessary. |
463 | 100k | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); |
464 | 100k | sink.put1(encode_sib(scale.enc(), enc_index & 7, enc_base & 7)); |
465 | 100k | imm.emit(sink); |
466 | | } |
467 | | |
468 | 70.9k | Amode::RipRelative { target } => { |
469 | 70.9k | // RIP-relative is mod=00, rm=101. |
470 | 70.9k | sink.put1(encode_modrm(0b00, enc_g & 7, 0b101)); |
471 | 70.9k | |
472 | 70.9k | // Inform the code sink about the RIP-relative `target` at the |
473 | 70.9k | // current offset, emitting a `LabelUse`, a relocation, or etc as |
474 | 70.9k | // appropriate. |
475 | 70.9k | sink.use_target(target); |
476 | 70.9k | |
477 | 70.9k | // N.B.: some instructions (XmmRmRImm format for example) |
478 | 70.9k | // have bytes *after* the RIP-relative offset. The |
479 | 70.9k | // addressed location is relative to the end of the |
480 | 70.9k | // instruction, but the relocation is nominally relative |
481 | 70.9k | // to the end of the u32 field. So, to compensate for |
482 | 70.9k | // this, we emit a negative extra offset in the u32 field |
483 | 70.9k | // initially, and the relocation will add to it. |
484 | 70.9k | sink.put4(-(i32::from(bytes_at_end)) as u32); |
485 | 70.9k | } |
486 | | } |
487 | 8.70M | } Unexecuted instantiation: cranelift_assembler_x64::mem::emit_modrm_sib_disp::<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Unexecuted instantiation: cranelift_assembler_x64::mem::emit_modrm_sib_disp::<_, _> cranelift_assembler_x64::mem::emit_modrm_sib_disp::<cranelift_codegen::isa::x64::inst::args::Gpr, cranelift_codegen::isa::x64::inst::external::AsmCodeSink> Line | Count | Source | 399 | 8.70M | pub fn emit_modrm_sib_disp<R: AsReg>( | 400 | 8.70M | sink: &mut impl CodeSink, | 401 | 8.70M | enc_g: u8, | 402 | 8.70M | mem_e: &Amode<R>, | 403 | 8.70M | bytes_at_end: u8, | 404 | 8.70M | evex_scaling: Option<i8>, | 405 | 8.70M | ) { | 406 | 8.70M | match *mem_e { | 407 | 8.53M | Amode::ImmReg { simm32, base, .. } => { | 408 | 8.53M | let enc_e = base.enc(); | 409 | 8.53M | let mut imm = Disp::new(simm32.value(sink), evex_scaling); | 410 | | | 411 | | // Most base registers allow for a single ModRM byte plus an | 412 | | // optional immediate. If rsp is the base register, however, then a | 413 | | // SIB byte must be used. | 414 | 8.53M | let enc_e_low3 = enc_e & 7; | 415 | 8.53M | if enc_e_low3 == gpr::enc::RSP { | 416 | 3.88M | // Displacement from RSP is encoded with a SIB byte where | 417 | 3.88M | // the index and base are both encoded as RSP's encoding of | 418 | 3.88M | // 0b100. This special encoding means that the index register | 419 | 3.88M | // isn't used and the base is 0b100 with or without a | 420 | 3.88M | // REX-encoded 4th bit (e.g. rsp or r12) | 421 | 3.88M | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); | 422 | 3.88M | sink.put1(0b00_100_100); | 423 | 3.88M | imm.emit(sink); | 424 | 3.88M | } else { | 425 | | // If the base register is rbp and there's no offset then force | 426 | | // a 1-byte zero offset since otherwise the encoding would be | 427 | | // invalid. | 428 | 4.65M | if enc_e_low3 == gpr::enc::RBP { | 429 | 129k | imm.force_immediate(); | 430 | 4.52M | } | 431 | 4.65M | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, enc_e & 7)); | 432 | 4.65M | imm.emit(sink); | 433 | | } | 434 | | } | 435 | | | 436 | | Amode::ImmRegRegShift { | 437 | 100k | simm32, | 438 | 100k | base, | 439 | 100k | index, | 440 | 100k | scale, | 441 | | .. | 442 | | } => { | 443 | 100k | let enc_base = base.enc(); | 444 | 100k | let enc_index = index.enc(); | 445 | | | 446 | | // Encoding of ModRM/SIB bytes don't allow the index register to | 447 | | // ever be rsp. Note, though, that the encoding of r12, whose three | 448 | | // lower bits match the encoding of rsp, is explicitly allowed with | 449 | | // REX bytes so only rsp is disallowed. | 450 | 100k | assert!(enc_index != gpr::enc::RSP); | 451 | | | 452 | | // If the offset is zero then there is no immediate. Note, though, | 453 | | // that if the base register's lower three bits are `101` then an | 454 | | // offset must be present. This is a special case in the encoding of | 455 | | // the SIB byte and requires an explicit displacement with rbp/r13. | 456 | 100k | let mut imm = Disp::new(simm32.value(), evex_scaling); | 457 | 100k | if enc_base & 7 == gpr::enc::RBP { | 458 | 48 | imm.force_immediate(); | 459 | 100k | } | 460 | | | 461 | | // With the above determined encode the ModRM byte, then the SIB | 462 | | // byte, then any immediate as necessary. | 463 | 100k | sink.put1(encode_modrm(imm.m0d(), enc_g & 7, 0b100)); | 464 | 100k | sink.put1(encode_sib(scale.enc(), enc_index & 7, enc_base & 7)); | 465 | 100k | imm.emit(sink); | 466 | | } | 467 | | | 468 | 70.9k | Amode::RipRelative { target } => { | 469 | 70.9k | // RIP-relative is mod=00, rm=101. | 470 | 70.9k | sink.put1(encode_modrm(0b00, enc_g & 7, 0b101)); | 471 | 70.9k | | 472 | 70.9k | // Inform the code sink about the RIP-relative `target` at the | 473 | 70.9k | // current offset, emitting a `LabelUse`, a relocation, or etc as | 474 | 70.9k | // appropriate. | 475 | 70.9k | sink.use_target(target); | 476 | 70.9k | | 477 | 70.9k | // N.B.: some instructions (XmmRmRImm format for example) | 478 | 70.9k | // have bytes *after* the RIP-relative offset. The | 479 | 70.9k | // addressed location is relative to the end of the | 480 | 70.9k | // instruction, but the relocation is nominally relative | 481 | 70.9k | // to the end of the u32 field. So, to compensate for | 482 | 70.9k | // this, we emit a negative extra offset in the u32 field | 483 | 70.9k | // initially, and the relocation will add to it. | 484 | 70.9k | sink.put4(-(i32::from(bytes_at_end)) as u32); | 485 | 70.9k | } | 486 | | } | 487 | 8.70M | } |
|