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