cranelift_codegen/isa/riscv64/inst/
imms.rs1use super::Inst;
5use std::fmt::{Debug, Display, Formatter, Result};
6
7#[derive(Copy, Clone, Debug, Default)]
8pub struct Imm12 {
9 bits: u16,
13}
14
15impl 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
52impl Into<i64> for Imm12 {
53 fn into(self) -> i64 {
54 self.as_i16().into()
55 }
56}
57
58impl Display for Imm12 {
59 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
60 write!(f, "{:+}", self.as_i16())
61 }
62}
63
64#[derive(Clone, Copy, Default)]
66pub struct Imm20 {
67 bits: u32,
71}
72
73impl 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
107impl Debug for Imm20 {
108 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
109 write!(f, "{}", self.as_i32())
110 }
111}
112
113impl Display for Imm20 {
114 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
115 write!(f, "{}", self.bits)
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq)]
121pub struct UImm5 {
122 value: u8,
123}
124
125impl UImm5 {
126 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 pub fn bits(&self) -> u32 {
137 u32::from(self.value)
138 }
139}
140
141impl Display for UImm5 {
142 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
143 write!(f, "{}", self.value)
144 }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq)]
149pub struct Imm5 {
150 value: i8,
151}
152
153impl Imm5 {
154 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 pub fn bits(&self) -> u8 {
171 self.value as u8 & 0x1f
172 }
173}
174
175impl Display for Imm5 {
176 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
177 write!(f, "{}", self.value)
178 }
179}
180
181#[derive(Clone, Copy, Debug, PartialEq)]
183pub struct Imm6 {
184 value: i8,
185}
186
187impl Imm6 {
188 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 pub fn bits(&self) -> u8 {
207 self.value as u8 & 0x3f
208 }
209}
210
211impl Display for Imm6 {
212 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
213 write!(f, "{}", self.value)
214 }
215}
216
217#[derive(Clone, Copy, Debug, PartialEq)]
219pub struct Uimm6 {
220 value: u8,
221}
222
223impl Uimm6 {
224 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 pub fn bits(&self) -> u8 {
235 self.value & 0x3f
236 }
237}
238
239impl Display for Uimm6 {
240 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
241 write!(f, "{}", self.value)
242 }
243}
244
245#[derive(Clone, Copy, Debug, PartialEq)]
247pub struct Uimm5 {
248 value: u8,
249}
250
251impl Uimm5 {
252 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 pub fn bits(&self) -> u8 {
263 self.value & 0x1f
264 }
265}
266
267impl Display for Uimm5 {
268 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
269 write!(f, "{}", self.value)
270 }
271}
272
273#[derive(Clone, Copy, Debug, PartialEq)]
275pub struct Uimm2 {
276 value: u8,
277}
278
279impl Uimm2 {
280 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 pub fn bits(&self) -> u8 {
291 self.value & 0x3
292 }
293}
294
295impl Display for Uimm2 {
296 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
297 write!(f, "{}", self.value)
298 }
299}
300
301impl 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 pub(crate) fn generate_imm(value: u64) -> Option<(Imm20, Imm12)> {
319 if let Some(imm12) = Imm12::maybe_from_u64(value) {
320 return Some((Imm20::ZERO, imm12));
322 }
323 let value = value as i64;
324 if !(value >= Self::imm_min() && value <= Self::imm_max()) {
325 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 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)]
359mod 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}