Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/riscv64/inst/imms.rs
1693 views
1
//! Riscv64 ISA definitions: immediate constants.
2
3
// Some variants are never constructed, but we still want them as options in the future.
4
use super::Inst;
5
use std::fmt::{Debug, Display, Formatter, Result};
6
7
#[derive(Copy, Clone, Debug, Default)]
8
pub struct Imm12 {
9
/// 16-bit container where the low 12 bits are the data payload.
10
///
11
/// Acquiring the underlying value requires sign-extending the 12th bit.
12
bits: u16,
13
}
14
15
impl Imm12 {
16
pub(crate) const ZERO: Self = Self { bits: 0 };
17
pub(crate) const ONE: Self = Self { bits: 1 };
18
19
pub fn maybe_from_u64(val: u64) -> Option<Imm12> {
20
Self::maybe_from_i64(val as i64)
21
}
22
23
pub fn maybe_from_i64(val: i64) -> Option<Imm12> {
24
if val >= -2048 && val <= 2047 {
25
Some(Imm12 {
26
bits: val as u16 & 0xfff,
27
})
28
} else {
29
None
30
}
31
}
32
33
#[inline]
34
pub fn from_i16(bits: i16) -> Self {
35
assert!(bits >= -2048 && bits <= 2047);
36
Self {
37
bits: (bits & 0xfff) as u16,
38
}
39
}
40
41
#[inline]
42
pub fn as_i16(self) -> i16 {
43
(self.bits << 4) as i16 >> 4
44
}
45
46
#[inline]
47
pub fn bits(&self) -> u32 {
48
self.bits.into()
49
}
50
}
51
52
impl From<Imm12> for i64 {
53
fn from(imm12: Imm12) -> i64 {
54
imm12.as_i16().into()
55
}
56
}
57
58
impl Display for Imm12 {
59
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
60
write!(f, "{:+}", self.as_i16())
61
}
62
}
63
64
// signed
65
#[derive(Clone, Copy, Default)]
66
pub struct Imm20 {
67
/// 32-bit container where the low 20 bits are the data payload.
68
///
69
/// Acquiring the underlying value requires sign-extending the 20th bit.
70
bits: u32,
71
}
72
73
impl Imm20 {
74
pub(crate) const ZERO: Self = Self { bits: 0 };
75
76
pub fn maybe_from_u64(val: u64) -> Option<Imm20> {
77
Self::maybe_from_i64(val as i64)
78
}
79
80
pub fn maybe_from_i64(val: i64) -> Option<Imm20> {
81
if val >= -(0x7_ffff + 1) && val <= 0x7_ffff {
82
Some(Imm20 { bits: val as u32 })
83
} else {
84
None
85
}
86
}
87
88
#[inline]
89
pub fn from_i32(bits: i32) -> Self {
90
assert!(bits >= -(0x7_ffff + 1) && bits <= 0x7_ffff);
91
Self {
92
bits: (bits as u32) & 0xf_ffff,
93
}
94
}
95
96
#[inline]
97
pub fn as_i32(&self) -> i32 {
98
((self.bits << 12) as i32) >> 12
99
}
100
101
#[inline]
102
pub fn bits(&self) -> u32 {
103
self.bits
104
}
105
}
106
107
impl Debug for Imm20 {
108
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
109
write!(f, "{}", self.as_i32())
110
}
111
}
112
113
impl Display for Imm20 {
114
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
115
write!(f, "{}", self.bits)
116
}
117
}
118
119
/// An unsigned 5-bit immediate.
120
#[derive(Clone, Copy, Debug, PartialEq)]
121
pub struct UImm5 {
122
value: u8,
123
}
124
125
impl UImm5 {
126
/// Create an unsigned 5-bit immediate from u8.
127
pub fn maybe_from_u8(value: u8) -> Option<UImm5> {
128
if value < 32 {
129
Some(UImm5 { value })
130
} else {
131
None
132
}
133
}
134
135
/// Bits for encoding.
136
pub fn bits(&self) -> u32 {
137
u32::from(self.value)
138
}
139
}
140
141
impl Display for UImm5 {
142
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
143
write!(f, "{}", self.value)
144
}
145
}
146
147
/// A Signed 5-bit immediate.
148
#[derive(Clone, Copy, Debug, PartialEq)]
149
pub struct Imm5 {
150
value: i8,
151
}
152
153
impl Imm5 {
154
/// Create an signed 5-bit immediate from an i8.
155
pub fn maybe_from_i8(value: i8) -> Option<Imm5> {
156
if value >= -16 && value <= 15 {
157
Some(Imm5 { value })
158
} else {
159
None
160
}
161
}
162
163
pub fn from_bits(value: u8) -> Imm5 {
164
assert_eq!(value & 0x1f, value);
165
let signed = ((value << 3) as i8) >> 3;
166
Imm5 { value: signed }
167
}
168
169
/// Bits for encoding.
170
pub fn bits(&self) -> u8 {
171
self.value as u8 & 0x1f
172
}
173
}
174
175
impl Display for Imm5 {
176
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
177
write!(f, "{}", self.value)
178
}
179
}
180
181
/// A Signed 6-bit immediate.
182
#[derive(Clone, Copy, Debug, PartialEq)]
183
pub struct Imm6 {
184
value: i8,
185
}
186
187
impl Imm6 {
188
/// Create an signed 6-bit immediate from an i16
189
pub fn maybe_from_i16(value: i16) -> Option<Self> {
190
if value >= -32 && value <= 31 {
191
Some(Self { value: value as i8 })
192
} else {
193
None
194
}
195
}
196
197
pub fn maybe_from_i32(value: i32) -> Option<Self> {
198
value.try_into().ok().and_then(Imm6::maybe_from_i16)
199
}
200
201
pub fn maybe_from_imm12(value: Imm12) -> Option<Self> {
202
Imm6::maybe_from_i16(value.as_i16())
203
}
204
205
/// Bits for encoding.
206
pub fn bits(&self) -> u8 {
207
self.value as u8 & 0x3f
208
}
209
}
210
211
impl Display for Imm6 {
212
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
213
write!(f, "{}", self.value)
214
}
215
}
216
217
/// A unsigned 6-bit immediate.
218
#[derive(Clone, Copy, Debug, PartialEq)]
219
pub struct Uimm6 {
220
value: u8,
221
}
222
223
impl Uimm6 {
224
/// Create an unsigned 6-bit immediate from an u8
225
pub fn maybe_from_u8(value: u8) -> Option<Self> {
226
if value <= 63 {
227
Some(Self { value })
228
} else {
229
None
230
}
231
}
232
233
/// Bits for encoding.
234
pub fn bits(&self) -> u8 {
235
self.value & 0x3f
236
}
237
}
238
239
impl Display for Uimm6 {
240
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
241
write!(f, "{}", self.value)
242
}
243
}
244
245
/// A unsigned 5-bit immediate.
246
#[derive(Clone, Copy, Debug, PartialEq)]
247
pub struct Uimm5 {
248
value: u8,
249
}
250
251
impl Uimm5 {
252
/// Create an unsigned 5-bit immediate from an u8
253
pub fn maybe_from_u8(value: u8) -> Option<Self> {
254
if value <= 31 {
255
Some(Self { value })
256
} else {
257
None
258
}
259
}
260
261
/// Bits for encoding.
262
pub fn bits(&self) -> u8 {
263
self.value & 0x1f
264
}
265
}
266
267
impl Display for Uimm5 {
268
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
269
write!(f, "{}", self.value)
270
}
271
}
272
273
/// A unsigned 2-bit immediate.
274
#[derive(Clone, Copy, Debug, PartialEq)]
275
pub struct Uimm2 {
276
value: u8,
277
}
278
279
impl Uimm2 {
280
/// Create an unsigned 2-bit immediate from an u8
281
pub fn maybe_from_u8(value: u8) -> Option<Self> {
282
if value <= 3 {
283
Some(Self { value })
284
} else {
285
None
286
}
287
}
288
289
/// Bits for encoding.
290
pub fn bits(&self) -> u8 {
291
self.value & 0x3
292
}
293
}
294
295
impl Display for Uimm2 {
296
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
297
write!(f, "{}", self.value)
298
}
299
}
300
301
impl Inst {
302
pub(crate) fn imm_min() -> i64 {
303
let imm20_max: i64 = (1 << 19) << 12;
304
let imm12_max = 1 << 11;
305
-imm20_max - imm12_max
306
}
307
pub(crate) fn imm_max() -> i64 {
308
let imm20_max: i64 = ((1 << 19) - 1) << 12;
309
let imm12_max = (1 << 11) - 1;
310
imm20_max + imm12_max
311
}
312
313
/// An imm20 immediate and an Imm12 immediate can generate a 32-bit immediate.
314
/// This helper produces an imm12, imm20, or both to generate the value.
315
///
316
/// `value` must be between `imm_min()` and `imm_max()`, or else
317
/// this helper returns `None`.
318
pub(crate) fn generate_imm(value: u64) -> Option<(Imm20, Imm12)> {
319
if let Some(imm12) = Imm12::maybe_from_u64(value) {
320
// can be load using single imm12.
321
return Some((Imm20::ZERO, imm12));
322
}
323
let value = value as i64;
324
if !(value >= Self::imm_min() && value <= Self::imm_max()) {
325
// not in range, return None.
326
return None;
327
}
328
const MOD_NUM: i64 = 4096;
329
let (imm20, imm12) = if value > 0 {
330
let mut imm20 = value / MOD_NUM;
331
let mut imm12 = value % MOD_NUM;
332
if imm12 >= 2048 {
333
imm12 -= MOD_NUM;
334
imm20 += 1;
335
}
336
assert!(imm12 >= -2048 && imm12 <= 2047);
337
(imm20, imm12)
338
} else {
339
// this is the abs value.
340
let value_abs = value.abs();
341
let imm20 = value_abs / MOD_NUM;
342
let imm12 = value_abs % MOD_NUM;
343
let mut imm20 = -imm20;
344
let mut imm12 = -imm12;
345
if imm12 < -2048 {
346
imm12 += MOD_NUM;
347
imm20 -= 1;
348
}
349
(imm20, imm12)
350
};
351
assert!(imm20 != 0 || imm12 != 0);
352
let imm20 = i32::try_from(imm20).unwrap();
353
let imm12 = i16::try_from(imm12).unwrap();
354
Some((Imm20::from_i32(imm20), Imm12::from_i16(imm12)))
355
}
356
}
357
358
#[cfg(test)]
359
mod test {
360
use super::*;
361
#[test]
362
fn test_imm12() {
363
let x = Imm12::ZERO;
364
assert_eq!(0, x.bits());
365
Imm12::maybe_from_u64(0xffff_ffff_ffff_ffff).unwrap();
366
}
367
368
#[test]
369
fn imm20_and_imm12() {
370
assert!(Inst::imm_max() == (i32::MAX - 2048) as i64);
371
assert!(Inst::imm_min() == i32::MIN as i64 - 2048);
372
}
373
}
374
375