Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/src/imm.rs
3068 views
1
//! Immediate operands to instructions.
2
3
use crate::api::CodeSink;
4
use alloc::{format, string::String};
5
use core::fmt;
6
7
/// This helper function prints the unsigned hexadecimal representation of the
8
/// immediate value: e.g., this prints `$0xfe` to represent both the signed `-2`
9
/// and the unsigned `254`.
10
macro_rules! hexify {
11
($n:expr) => {
12
format!("$0x{:x}", $n)
13
};
14
}
15
16
/// Like `hexify!`, but this performs a sign extension.
17
macro_rules! hexify_sign_extend {
18
($n:expr, $from:ty => $to:ty) => {{
19
let from: $from = $n; // Assert the type we expect.
20
let to = <$to>::from(from);
21
format!("$0x{:x}", to)
22
}};
23
}
24
25
/// An 8-bit immediate operand.
26
#[derive(Clone, Copy, Debug)]
27
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
28
pub struct Imm8(u8);
29
30
impl Imm8 {
31
#[must_use]
32
pub fn new(value: u8) -> Self {
33
Self(value)
34
}
35
36
#[must_use]
37
pub fn value(&self) -> u8 {
38
self.0
39
}
40
41
pub fn encode(&self, sink: &mut impl CodeSink) {
42
sink.put1(self.0);
43
}
44
}
45
46
impl From<u8> for Imm8 {
47
fn from(imm8: u8) -> Self {
48
Self(imm8)
49
}
50
}
51
52
impl TryFrom<i32> for Imm8 {
53
type Error = core::num::TryFromIntError;
54
fn try_from(simm32: i32) -> Result<Self, Self::Error> {
55
Ok(Self(u8::try_from(simm32)?))
56
}
57
}
58
59
impl fmt::Display for Imm8 {
60
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61
write!(f, "$0x{:x}", self.0)
62
}
63
}
64
65
/// A _signed_ 8-bit immediate operand (suitable for sign extension).
66
#[derive(Clone, Copy, Debug)]
67
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
68
pub struct Simm8(i8);
69
70
impl Simm8 {
71
#[must_use]
72
pub fn new(value: i8) -> Self {
73
Self(value)
74
}
75
76
#[must_use]
77
pub fn value(&self) -> i8 {
78
self.0
79
}
80
81
pub fn encode(&self, sink: &mut impl CodeSink) {
82
sink.put1(self.0 as u8);
83
}
84
85
#[must_use]
86
pub fn to_string(&self, extend: Extension) -> String {
87
use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
88
match extend {
89
None => hexify!(self.0),
90
SignExtendWord => hexify_sign_extend!(self.0, i8 => i16),
91
SignExtendLong => hexify_sign_extend!(self.0, i8 => i32),
92
SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64),
93
}
94
}
95
}
96
97
impl From<i8> for Simm8 {
98
fn from(simm8: i8) -> Self {
99
Self(simm8)
100
}
101
}
102
103
impl TryFrom<i32> for Simm8 {
104
type Error = core::num::TryFromIntError;
105
fn try_from(simm32: i32) -> Result<Self, Self::Error> {
106
Ok(Self(i8::try_from(simm32)?))
107
}
108
}
109
110
/// A 16-bit immediate operand.
111
#[derive(Copy, Clone, Debug)]
112
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
113
pub struct Imm16(u16);
114
115
impl Imm16 {
116
#[must_use]
117
pub fn new(value: u16) -> Self {
118
Self(value)
119
}
120
121
#[must_use]
122
pub fn value(&self) -> u16 {
123
self.0
124
}
125
126
pub fn encode(&self, sink: &mut impl CodeSink) {
127
sink.put2(self.0);
128
}
129
}
130
131
impl From<u16> for Imm16 {
132
fn from(imm16: u16) -> Self {
133
Self(imm16)
134
}
135
}
136
137
impl TryFrom<i32> for Imm16 {
138
type Error = core::num::TryFromIntError;
139
fn try_from(simm32: i32) -> Result<Self, Self::Error> {
140
Ok(Self(u16::try_from(simm32)?))
141
}
142
}
143
144
impl fmt::Display for Imm16 {
145
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146
write!(f, "$0x{:x}", self.0)
147
}
148
}
149
150
/// A _signed_ 16-bit immediate operand (suitable for sign extension).
151
#[derive(Copy, Clone, Debug)]
152
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
153
pub struct Simm16(i16);
154
155
impl Simm16 {
156
#[must_use]
157
pub fn new(value: i16) -> Self {
158
Self(value)
159
}
160
161
#[must_use]
162
pub fn value(&self) -> i16 {
163
self.0
164
}
165
166
pub fn encode(&self, sink: &mut impl CodeSink) {
167
sink.put2(self.0 as u16);
168
}
169
170
#[must_use]
171
pub fn to_string(&self, extend: Extension) -> String {
172
use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
173
match extend {
174
None => hexify!(self.0),
175
SignExtendWord => unreachable!("the 16-bit value is already 16 bits"),
176
SignExtendLong => hexify_sign_extend!(self.0, i16 => i32),
177
SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64),
178
}
179
}
180
}
181
182
impl From<i16> for Simm16 {
183
fn from(simm16: i16) -> Self {
184
Self(simm16)
185
}
186
}
187
188
impl TryFrom<i32> for Simm16 {
189
type Error = core::num::TryFromIntError;
190
fn try_from(simm32: i32) -> Result<Self, Self::Error> {
191
Ok(Self(i16::try_from(simm32)?))
192
}
193
}
194
195
/// A 32-bit immediate operand.
196
///
197
/// Note that, "in 64-bit mode, the typical size of immediate operands remains
198
/// 32 bits. When the operand size is 64 bits, the processor sign-extends all
199
/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
200
#[derive(Copy, Clone, Debug)]
201
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
202
pub struct Imm32(u32);
203
204
impl Imm32 {
205
#[must_use]
206
pub fn new(value: u32) -> Self {
207
Self(value)
208
}
209
210
#[must_use]
211
pub fn value(&self) -> u32 {
212
self.0
213
}
214
215
pub fn encode(&self, sink: &mut impl CodeSink) {
216
sink.put4(self.0);
217
}
218
}
219
220
impl From<u32> for Imm32 {
221
fn from(imm32: u32) -> Self {
222
Self(imm32)
223
}
224
}
225
226
impl From<i32> for Imm32 {
227
fn from(simm32: i32) -> Self {
228
// TODO: should this be a `TryFrom`?
229
Self(simm32 as u32)
230
}
231
}
232
233
impl fmt::Display for Imm32 {
234
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
235
write!(f, "$0x{:x}", self.0)
236
}
237
}
238
239
/// A _signed_ 32-bit immediate operand (suitable for sign extension).
240
///
241
/// Note that, "in 64-bit mode, the typical size of immediate operands remains
242
/// 32 bits. When the operand size is 64 bits, the processor sign-extends all
243
/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).
244
#[derive(Copy, Clone, Debug)]
245
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
246
pub struct Simm32(i32);
247
248
impl Simm32 {
249
#[must_use]
250
pub fn new(value: i32) -> Self {
251
Self(value)
252
}
253
254
#[must_use]
255
pub fn value(&self) -> i32 {
256
self.0
257
}
258
259
pub fn encode(&self, sink: &mut impl CodeSink) {
260
sink.put4(self.0 as u32);
261
}
262
263
#[must_use]
264
pub fn to_string(&self, extend: Extension) -> String {
265
use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};
266
match extend {
267
None => hexify!(self.0),
268
SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"),
269
SignExtendLong => unreachable!("the 32-bit value is already 32 bits"),
270
SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64),
271
}
272
}
273
}
274
275
impl From<i32> for Simm32 {
276
fn from(simm32: i32) -> Self {
277
Self(simm32)
278
}
279
}
280
281
/// A 64-bit immediate operand.
282
///
283
/// This form is quite rare; see certain `mov` instructions.
284
#[derive(Copy, Clone, Debug)]
285
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
286
pub struct Imm64(u64);
287
288
impl Imm64 {
289
#[must_use]
290
pub fn new(value: u64) -> Self {
291
Self(value)
292
}
293
294
#[must_use]
295
pub fn value(&self) -> u64 {
296
self.0
297
}
298
299
pub fn encode(&self, sink: &mut impl CodeSink) {
300
sink.put8(self.0);
301
}
302
}
303
304
impl From<u64> for Imm64 {
305
fn from(imm64: u64) -> Self {
306
Self(imm64)
307
}
308
}
309
310
impl fmt::Display for Imm64 {
311
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312
write!(f, "$0x{:x}", self.0)
313
}
314
}
315
316
/// Define the ways an immediate may be sign- or zero-extended.
317
#[derive(Clone, Copy, Debug)]
318
pub enum Extension {
319
None,
320
SignExtendQuad,
321
SignExtendLong,
322
SignExtendWord,
323
}
324
325