1 //! AArch64 ISA definitions: immediate constants.
2 
3 // Some variants are never constructed, but we still want them as options in the future.
4 #[allow(dead_code)]
5 use crate::ir::types::*;
6 use crate::ir::Type;
7 use crate::isa::aarch64::inst::InstSize;
8 use crate::machinst::*;
9 
10 use regalloc::RealRegUniverse;
11 
12 use core::convert::TryFrom;
13 use std::string::String;
14 
15 /// An immediate that represents the NZCV flags.
16 #[derive(Clone, Copy, Debug)]
17 pub struct NZCV {
18     /// The negative condition flag.
19     n: bool,
20     /// The zero condition flag.
21     z: bool,
22     /// The carry condition flag.
23     c: bool,
24     /// The overflow condition flag.
25     v: bool,
26 }
27 
28 impl NZCV {
new(n: bool, z: bool, c: bool, v: bool) -> NZCV29     pub fn new(n: bool, z: bool, c: bool, v: bool) -> NZCV {
30         NZCV { n, z, c, v }
31     }
32 
33     /// Bits for encoding.
bits(&self) -> u3234     pub fn bits(&self) -> u32 {
35         (u32::from(self.n) << 3)
36             | (u32::from(self.z) << 2)
37             | (u32::from(self.c) << 1)
38             | u32::from(self.v)
39     }
40 }
41 
42 /// An unsigned 5-bit immediate.
43 #[derive(Clone, Copy, Debug)]
44 pub struct UImm5 {
45     /// The value.
46     value: u8,
47 }
48 
49 impl UImm5 {
maybe_from_u8(value: u8) -> Option<UImm5>50     pub fn maybe_from_u8(value: u8) -> Option<UImm5> {
51         if value < 32 {
52             Some(UImm5 { value })
53         } else {
54             None
55         }
56     }
57 
58     /// Bits for encoding.
bits(&self) -> u3259     pub fn bits(&self) -> u32 {
60         u32::from(self.value)
61     }
62 }
63 
64 /// A signed, scaled 7-bit offset.
65 #[derive(Clone, Copy, Debug)]
66 pub struct SImm7Scaled {
67     /// The value.
68     pub value: i16,
69     /// multiplied by the size of this type
70     pub scale_ty: Type,
71 }
72 
73 impl SImm7Scaled {
74     /// Create a SImm7Scaled from a raw offset and the known scale type, if
75     /// possible.
maybe_from_i64(value: i64, scale_ty: Type) -> Option<SImm7Scaled>76     pub fn maybe_from_i64(value: i64, scale_ty: Type) -> Option<SImm7Scaled> {
77         assert!(scale_ty == I64 || scale_ty == I32);
78         let scale = scale_ty.bytes();
79         assert!(scale.is_power_of_two());
80         let scale = i64::from(scale);
81         let upper_limit = 63 * scale;
82         let lower_limit = -(64 * scale);
83         if value >= lower_limit && value <= upper_limit && (value & (scale - 1)) == 0 {
84             Some(SImm7Scaled {
85                 value: i16::try_from(value).unwrap(),
86                 scale_ty,
87             })
88         } else {
89             None
90         }
91     }
92 
93     /// Create a zero immediate of this format.
zero(scale_ty: Type) -> SImm7Scaled94     pub fn zero(scale_ty: Type) -> SImm7Scaled {
95         SImm7Scaled { value: 0, scale_ty }
96     }
97 
98     /// Bits for encoding.
bits(&self) -> u3299     pub fn bits(&self) -> u32 {
100         let ty_bytes: i16 = self.scale_ty.bytes() as i16;
101         let scaled: i16 = self.value / ty_bytes;
102         assert!(scaled <= 63 && scaled >= -64);
103         let scaled: i8 = scaled as i8;
104         let encoded: u32 = scaled as u32;
105         encoded & 0x7f
106     }
107 }
108 
109 #[derive(Clone, Copy, Debug)]
110 pub struct FPULeftShiftImm {
111     pub amount: u8,
112     pub lane_size_in_bits: u8,
113 }
114 
115 impl FPULeftShiftImm {
maybe_from_u8(amount: u8, lane_size_in_bits: u8) -> Option<Self>116     pub fn maybe_from_u8(amount: u8, lane_size_in_bits: u8) -> Option<Self> {
117         debug_assert!(lane_size_in_bits == 32 || lane_size_in_bits == 64);
118         if amount < lane_size_in_bits {
119             Some(Self {
120                 amount,
121                 lane_size_in_bits,
122             })
123         } else {
124             None
125         }
126     }
127 
enc(&self) -> u32128     pub fn enc(&self) -> u32 {
129         debug_assert!(self.lane_size_in_bits.is_power_of_two());
130         debug_assert!(self.lane_size_in_bits > self.amount);
131         // The encoding of the immediate follows the table below,
132         // where xs encode the shift amount.
133         //
134         // | lane_size_in_bits | encoding |
135         // +------------------------------+
136         // | 8                 | 0001xxx  |
137         // | 16                | 001xxxx  |
138         // | 32                | 01xxxxx  |
139         // | 64                | 1xxxxxx  |
140         //
141         // The highest one bit is represented by `lane_size_in_bits`. Since
142         // `lane_size_in_bits` is a power of 2 and `amount` is less
143         // than `lane_size_in_bits`, they can be ORed
144         // together to produced the encoded value.
145         u32::from(self.lane_size_in_bits | self.amount)
146     }
147 }
148 
149 #[derive(Clone, Copy, Debug)]
150 pub struct FPURightShiftImm {
151     pub amount: u8,
152     pub lane_size_in_bits: u8,
153 }
154 
155 impl FPURightShiftImm {
maybe_from_u8(amount: u8, lane_size_in_bits: u8) -> Option<Self>156     pub fn maybe_from_u8(amount: u8, lane_size_in_bits: u8) -> Option<Self> {
157         debug_assert!(lane_size_in_bits == 32 || lane_size_in_bits == 64);
158         if amount > 0 && amount <= lane_size_in_bits {
159             Some(Self {
160                 amount,
161                 lane_size_in_bits,
162             })
163         } else {
164             None
165         }
166     }
167 
enc(&self) -> u32168     pub fn enc(&self) -> u32 {
169         debug_assert_ne!(0, self.amount);
170         // The encoding of the immediate follows the table below,
171         // where xs encodes the negated shift amount.
172         //
173         // | lane_size_in_bits | encoding |
174         // +------------------------------+
175         // | 8                 | 0001xxx  |
176         // | 16                | 001xxxx  |
177         // | 32                | 01xxxxx  |
178         // | 64                | 1xxxxxx  |
179         //
180         // The shift amount is negated such that a shift ammount
181         // of 1 (in 64-bit) is encoded as 0b111111 and a shift
182         // amount of 64 is encoded as 0b000000,
183         // in the bottom 6 bits.
184         u32::from((self.lane_size_in_bits * 2) - self.amount)
185     }
186 }
187 
188 /// a 9-bit signed offset.
189 #[derive(Clone, Copy, Debug)]
190 pub struct SImm9 {
191     /// The value.
192     pub value: i16,
193 }
194 
195 impl SImm9 {
196     /// Create a signed 9-bit offset from a full-range value, if possible.
maybe_from_i64(value: i64) -> Option<SImm9>197     pub fn maybe_from_i64(value: i64) -> Option<SImm9> {
198         if value >= -256 && value <= 255 {
199             Some(SImm9 {
200                 value: value as i16,
201             })
202         } else {
203             None
204         }
205     }
206 
207     /// Create a zero immediate of this format.
zero() -> SImm9208     pub fn zero() -> SImm9 {
209         SImm9 { value: 0 }
210     }
211 
212     /// Bits for encoding.
bits(&self) -> u32213     pub fn bits(&self) -> u32 {
214         (self.value as u32) & 0x1ff
215     }
216 
217     /// Signed value of immediate.
value(&self) -> i32218     pub fn value(&self) -> i32 {
219         self.value as i32
220     }
221 }
222 
223 /// An unsigned, scaled 12-bit offset.
224 #[derive(Clone, Copy, Debug)]
225 pub struct UImm12Scaled {
226     /// The value.
227     pub value: u16,
228     /// multiplied by the size of this type
229     pub scale_ty: Type,
230 }
231 
232 impl UImm12Scaled {
233     /// Create a UImm12Scaled from a raw offset and the known scale type, if
234     /// possible.
maybe_from_i64(value: i64, scale_ty: Type) -> Option<UImm12Scaled>235     pub fn maybe_from_i64(value: i64, scale_ty: Type) -> Option<UImm12Scaled> {
236         let scale = scale_ty.bytes();
237         assert!(scale.is_power_of_two());
238         let scale = scale as i64;
239         let limit = 4095 * scale;
240         if value >= 0 && value <= limit && (value & (scale - 1)) == 0 {
241             Some(UImm12Scaled {
242                 value: value as u16,
243                 scale_ty,
244             })
245         } else {
246             None
247         }
248     }
249 
250     /// Create a zero immediate of this format.
zero(scale_ty: Type) -> UImm12Scaled251     pub fn zero(scale_ty: Type) -> UImm12Scaled {
252         UImm12Scaled { value: 0, scale_ty }
253     }
254 
255     /// Encoded bits.
bits(&self) -> u32256     pub fn bits(&self) -> u32 {
257         (self.value as u32 / self.scale_ty.bytes()) & 0xfff
258     }
259 
260     /// Value after scaling.
value(&self) -> u32261     pub fn value(&self) -> u32 {
262         self.value as u32
263     }
264 
265     /// The value type which is the scaling base.
scale_ty(&self) -> Type266     pub fn scale_ty(&self) -> Type {
267         self.scale_ty
268     }
269 }
270 
271 /// A shifted immediate value in 'imm12' format: supports 12 bits, shifted
272 /// left by 0 or 12 places.
273 #[derive(Clone, Debug)]
274 pub struct Imm12 {
275     /// The immediate bits.
276     pub bits: u16,
277     /// Whether the immediate bits are shifted left by 12 or not.
278     pub shift12: bool,
279 }
280 
281 impl Imm12 {
282     /// Compute a Imm12 from raw bits, if possible.
maybe_from_u64(val: u64) -> Option<Imm12>283     pub fn maybe_from_u64(val: u64) -> Option<Imm12> {
284         if val == 0 {
285             Some(Imm12 {
286                 bits: 0,
287                 shift12: false,
288             })
289         } else if val < 0xfff {
290             Some(Imm12 {
291                 bits: val as u16,
292                 shift12: false,
293             })
294         } else if val < 0xfff_000 && (val & 0xfff == 0) {
295             Some(Imm12 {
296                 bits: (val >> 12) as u16,
297                 shift12: true,
298             })
299         } else {
300             None
301         }
302     }
303 
304     /// Bits for 2-bit "shift" field in e.g. AddI.
shift_bits(&self) -> u32305     pub fn shift_bits(&self) -> u32 {
306         if self.shift12 {
307             0b01
308         } else {
309             0b00
310         }
311     }
312 
313     /// Bits for 12-bit "imm" field in e.g. AddI.
imm_bits(&self) -> u32314     pub fn imm_bits(&self) -> u32 {
315         self.bits as u32
316     }
317 }
318 
319 /// An immediate for logical instructions.
320 #[derive(Clone, Debug)]
321 #[cfg_attr(test, derive(PartialEq))]
322 pub struct ImmLogic {
323     /// The actual value.
324     value: u64,
325     /// `N` flag.
326     pub n: bool,
327     /// `S` field: element size and element bits.
328     pub r: u8,
329     /// `R` field: rotate amount.
330     pub s: u8,
331     /// Was this constructed for a 32-bit or 64-bit instruction?
332     pub size: InstSize,
333 }
334 
335 impl ImmLogic {
336     /// Compute an ImmLogic from raw bits, if possible.
maybe_from_u64(value: u64, ty: Type) -> Option<ImmLogic>337     pub fn maybe_from_u64(value: u64, ty: Type) -> Option<ImmLogic> {
338         // Note: This function is a port of VIXL's Assembler::IsImmLogical.
339 
340         if ty != I64 && ty != I32 {
341             return None;
342         }
343         let inst_size = InstSize::from_ty(ty);
344 
345         let original_value = value;
346 
347         let value = if ty == I32 {
348             // To handle 32-bit logical immediates, the very easiest thing is to repeat
349             // the input value twice to make a 64-bit word. The correct encoding of that
350             // as a logical immediate will also be the correct encoding of the 32-bit
351             // value.
352 
353             // Avoid making the assumption that the most-significant 32 bits are zero by
354             // shifting the value left and duplicating it.
355             let value = value << 32;
356             value | value >> 32
357         } else {
358             value
359         };
360 
361         // Logical immediates are encoded using parameters n, imm_s and imm_r using
362         // the following table:
363         //
364         //    N   imms    immr    size        S             R
365         //    1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
366         //    0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
367         //    0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
368         //    0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
369         //    0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
370         //    0  11110s  xxxxxr     2    UInt(s)       UInt(r)
371         // (s bits must not be all set)
372         //
373         // A pattern is constructed of size bits, where the least significant S+1 bits
374         // are set. The pattern is rotated right by R, and repeated across a 32 or
375         // 64-bit value, depending on destination register width.
376         //
377         // Put another way: the basic format of a logical immediate is a single
378         // contiguous stretch of 1 bits, repeated across the whole word at intervals
379         // given by a power of 2. To identify them quickly, we first locate the
380         // lowest stretch of 1 bits, then the next 1 bit above that; that combination
381         // is different for every logical immediate, so it gives us all the
382         // information we need to identify the only logical immediate that our input
383         // could be, and then we simply check if that's the value we actually have.
384         //
385         // (The rotation parameter does give the possibility of the stretch of 1 bits
386         // going 'round the end' of the word. To deal with that, we observe that in
387         // any situation where that happens the bitwise NOT of the value is also a
388         // valid logical immediate. So we simply invert the input whenever its low bit
389         // is set, and then we know that the rotated case can't arise.)
390         let (value, inverted) = if value & 1 == 1 {
391             (!value, true)
392         } else {
393             (value, false)
394         };
395 
396         if value == 0 {
397             return None;
398         }
399 
400         // The basic analysis idea: imagine our input word looks like this.
401         //
402         //    0011111000111110001111100011111000111110001111100011111000111110
403         //                                                          c  b    a
404         //                                                          |<--d-->|
405         //
406         // We find the lowest set bit (as an actual power-of-2 value, not its index)
407         // and call it a. Then we add a to our original number, which wipes out the
408         // bottommost stretch of set bits and replaces it with a 1 carried into the
409         // next zero bit. Then we look for the new lowest set bit, which is in
410         // position b, and subtract it, so now our number is just like the original
411         // but with the lowest stretch of set bits completely gone. Now we find the
412         // lowest set bit again, which is position c in the diagram above. Then we'll
413         // measure the distance d between bit positions a and c (using CLZ), and that
414         // tells us that the only valid logical immediate that could possibly be equal
415         // to this number is the one in which a stretch of bits running from a to just
416         // below b is replicated every d bits.
417         fn lowest_set_bit(value: u64) -> u64 {
418             let bit = value.trailing_zeros();
419             1u64.checked_shl(bit).unwrap_or(0)
420         }
421         let a = lowest_set_bit(value);
422         assert_ne!(0, a);
423         let value_plus_a = value.wrapping_add(a);
424         let b = lowest_set_bit(value_plus_a);
425         let value_plus_a_minus_b = value_plus_a - b;
426         let c = lowest_set_bit(value_plus_a_minus_b);
427 
428         let (d, clz_a, out_n, mask) = if c != 0 {
429             // The general case, in which there is more than one stretch of set bits.
430             // Compute the repeat distance d, and set up a bitmask covering the basic
431             // unit of repetition (i.e. a word with the bottom d bits set). Also, in all
432             // of these cases the N bit of the output will be zero.
433             let clz_a = a.leading_zeros();
434             let clz_c = c.leading_zeros();
435             let d = clz_a - clz_c;
436             let mask = (1 << d) - 1;
437             (d, clz_a, 0, mask)
438         } else {
439             (64, a.leading_zeros(), 1, u64::max_value())
440         };
441 
442         // If the repeat period d is not a power of two, it can't be encoded.
443         if !d.is_power_of_two() {
444             return None;
445         }
446 
447         if ((b.wrapping_sub(a)) & !mask) != 0 {
448             // If the bit stretch (b - a) does not fit within the mask derived from the
449             // repeat period, then fail.
450             return None;
451         }
452 
453         // The only possible option is b - a repeated every d bits. Now we're going to
454         // actually construct the valid logical immediate derived from that
455         // specification, and see if it equals our original input.
456         //
457         // To repeat a value every d bits, we multiply it by a number of the form
458         // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
459         // be derived using a table lookup on CLZ(d).
460         const MULTIPLIERS: [u64; 6] = [
461             0x0000000000000001,
462             0x0000000100000001,
463             0x0001000100010001,
464             0x0101010101010101,
465             0x1111111111111111,
466             0x5555555555555555,
467         ];
468         let multiplier = MULTIPLIERS[(u64::from(d).leading_zeros() - 57) as usize];
469         let candidate = b.wrapping_sub(a) * multiplier;
470 
471         if value != candidate {
472             // The candidate pattern doesn't match our input value, so fail.
473             return None;
474         }
475 
476         // We have a match! This is a valid logical immediate, so now we have to
477         // construct the bits and pieces of the instruction encoding that generates
478         // it.
479 
480         // Count the set bits in our basic stretch. The special case of clz(0) == -1
481         // makes the answer come out right for stretches that reach the very top of
482         // the word (e.g. numbers like 0xffffc00000000000).
483         let clz_b = if b == 0 {
484             u32::max_value() // -1
485         } else {
486             b.leading_zeros()
487         };
488         let s = clz_a.wrapping_sub(clz_b);
489 
490         // Decide how many bits to rotate right by, to put the low bit of that basic
491         // stretch in position a.
492         let (s, r) = if inverted {
493             // If we inverted the input right at the start of this function, here's
494             // where we compensate: the number of set bits becomes the number of clear
495             // bits, and the rotation count is based on position b rather than position
496             // a (since b is the location of the 'lowest' 1 bit after inversion).
497             // Need wrapping for when clz_b is max_value() (for when b == 0).
498             (d - s, clz_b.wrapping_add(1) & (d - 1))
499         } else {
500             (s, (clz_a + 1) & (d - 1))
501         };
502 
503         // Now we're done, except for having to encode the S output in such a way that
504         // it gives both the number of set bits and the length of the repeated
505         // segment. The s field is encoded like this:
506         //
507         //     imms    size        S
508         //    ssssss    64    UInt(ssssss)
509         //    0sssss    32    UInt(sssss)
510         //    10ssss    16    UInt(ssss)
511         //    110sss     8    UInt(sss)
512         //    1110ss     4    UInt(ss)
513         //    11110s     2    UInt(s)
514         //
515         // So we 'or' (2 * -d) with our computed s to form imms.
516         let s = ((d * 2).wrapping_neg() | (s - 1)) & 0x3f;
517         debug_assert!(u8::try_from(r).is_ok());
518         debug_assert!(u8::try_from(s).is_ok());
519         Some(ImmLogic {
520             value: original_value,
521             n: out_n != 0,
522             r: r as u8,
523             s: s as u8,
524             size: inst_size,
525         })
526     }
527 
528     /// Returns bits ready for encoding: (N:1, R:6, S:6)
enc_bits(&self) -> u32529     pub fn enc_bits(&self) -> u32 {
530         ((self.n as u32) << 12) | ((self.r as u32) << 6) | (self.s as u32)
531     }
532 
533     /// Returns the value that this immediate represents.
value(&self) -> u64534     pub fn value(&self) -> u64 {
535         self.value
536     }
537 
538     /// Return an immediate for the bitwise-inverted value.
invert(&self) -> ImmLogic539     pub fn invert(&self) -> ImmLogic {
540         // For every ImmLogical immediate, the inverse can also be encoded.
541         Self::maybe_from_u64(!self.value, self.size.to_ty()).unwrap()
542     }
543 }
544 
545 /// An immediate for shift instructions.
546 #[derive(Clone, Debug)]
547 pub struct ImmShift {
548     /// 6-bit shift amount.
549     pub imm: u8,
550 }
551 
552 impl ImmShift {
553     /// Create an ImmShift from raw bits, if possible.
maybe_from_u64(val: u64) -> Option<ImmShift>554     pub fn maybe_from_u64(val: u64) -> Option<ImmShift> {
555         if val < 64 {
556             Some(ImmShift { imm: val as u8 })
557         } else {
558             None
559         }
560     }
561 
562     /// Get the immediate value.
value(&self) -> u8563     pub fn value(&self) -> u8 {
564         self.imm
565     }
566 }
567 
568 /// A 16-bit immediate for a MOVZ instruction, with a {0,16,32,48}-bit shift.
569 #[derive(Clone, Copy, Debug)]
570 pub struct MoveWideConst {
571     /// The value.
572     pub bits: u16,
573     /// Result is `bits` shifted 16*shift bits to the left.
574     pub shift: u8,
575 }
576 
577 impl MoveWideConst {
578     /// Construct a MoveWideConst from an arbitrary 64-bit constant if possible.
maybe_from_u64(value: u64) -> Option<MoveWideConst>579     pub fn maybe_from_u64(value: u64) -> Option<MoveWideConst> {
580         let mask0 = 0x0000_0000_0000_ffffu64;
581         let mask1 = 0x0000_0000_ffff_0000u64;
582         let mask2 = 0x0000_ffff_0000_0000u64;
583         let mask3 = 0xffff_0000_0000_0000u64;
584 
585         if value == (value & mask0) {
586             return Some(MoveWideConst {
587                 bits: (value & mask0) as u16,
588                 shift: 0,
589             });
590         }
591         if value == (value & mask1) {
592             return Some(MoveWideConst {
593                 bits: ((value >> 16) & mask0) as u16,
594                 shift: 1,
595             });
596         }
597         if value == (value & mask2) {
598             return Some(MoveWideConst {
599                 bits: ((value >> 32) & mask0) as u16,
600                 shift: 2,
601             });
602         }
603         if value == (value & mask3) {
604             return Some(MoveWideConst {
605                 bits: ((value >> 48) & mask0) as u16,
606                 shift: 3,
607             });
608         }
609         None
610     }
611 
maybe_with_shift(imm: u16, shift: u8) -> Option<MoveWideConst>612     pub fn maybe_with_shift(imm: u16, shift: u8) -> Option<MoveWideConst> {
613         let shift_enc = shift / 16;
614         if shift_enc > 3 {
615             None
616         } else {
617             Some(MoveWideConst {
618                 bits: imm,
619                 shift: shift_enc,
620             })
621         }
622     }
623 
624     /// Returns the value that this constant represents.
value(&self) -> u64625     pub fn value(&self) -> u64 {
626         (self.bits as u64) << (16 * self.shift)
627     }
628 }
629 
630 impl ShowWithRRU for NZCV {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String631     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
632         let fmt = |c: char, v| if v { c.to_ascii_uppercase() } else { c };
633         format!(
634             "#{}{}{}{}",
635             fmt('n', self.n),
636             fmt('z', self.z),
637             fmt('c', self.c),
638             fmt('v', self.v)
639         )
640     }
641 }
642 
643 impl ShowWithRRU for UImm5 {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String644     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
645         format!("#{}", self.value)
646     }
647 }
648 
649 impl ShowWithRRU for Imm12 {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String650     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
651         let shift = if self.shift12 { 12 } else { 0 };
652         let value = u32::from(self.bits) << shift;
653         format!("#{}", value)
654     }
655 }
656 
657 impl ShowWithRRU for SImm7Scaled {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String658     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
659         format!("#{}", self.value)
660     }
661 }
662 
663 impl ShowWithRRU for FPULeftShiftImm {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String664     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
665         format!("#{}", self.amount)
666     }
667 }
668 
669 impl ShowWithRRU for FPURightShiftImm {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String670     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
671         format!("#{}", self.amount)
672     }
673 }
674 
675 impl ShowWithRRU for SImm9 {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String676     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
677         format!("#{}", self.value)
678     }
679 }
680 
681 impl ShowWithRRU for UImm12Scaled {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String682     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
683         format!("#{}", self.value)
684     }
685 }
686 
687 impl ShowWithRRU for ImmLogic {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String688     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
689         format!("#{}", self.value())
690     }
691 }
692 
693 impl ShowWithRRU for ImmShift {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String694     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
695         format!("#{}", self.imm)
696     }
697 }
698 
699 impl ShowWithRRU for MoveWideConst {
show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String700     fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
701         if self.shift == 0 {
702             format!("#{}", self.bits)
703         } else {
704             format!("#{}, LSL #{}", self.bits, self.shift * 16)
705         }
706     }
707 }
708 
709 #[cfg(test)]
710 mod test {
711     use super::*;
712 
713     #[test]
imm_logical_test()714     fn imm_logical_test() {
715         assert_eq!(None, ImmLogic::maybe_from_u64(0, I64));
716         assert_eq!(None, ImmLogic::maybe_from_u64(u64::max_value(), I64));
717 
718         assert_eq!(
719             Some(ImmLogic {
720                 value: 1,
721                 n: true,
722                 r: 0,
723                 s: 0,
724                 size: InstSize::Size64,
725             }),
726             ImmLogic::maybe_from_u64(1, I64)
727         );
728 
729         assert_eq!(
730             Some(ImmLogic {
731                 value: 2,
732                 n: true,
733                 r: 63,
734                 s: 0,
735                 size: InstSize::Size64,
736             }),
737             ImmLogic::maybe_from_u64(2, I64)
738         );
739 
740         assert_eq!(None, ImmLogic::maybe_from_u64(5, I64));
741 
742         assert_eq!(None, ImmLogic::maybe_from_u64(11, I64));
743 
744         assert_eq!(
745             Some(ImmLogic {
746                 value: 248,
747                 n: true,
748                 r: 61,
749                 s: 4,
750                 size: InstSize::Size64,
751             }),
752             ImmLogic::maybe_from_u64(248, I64)
753         );
754 
755         assert_eq!(None, ImmLogic::maybe_from_u64(249, I64));
756 
757         assert_eq!(
758             Some(ImmLogic {
759                 value: 1920,
760                 n: true,
761                 r: 57,
762                 s: 3,
763                 size: InstSize::Size64,
764             }),
765             ImmLogic::maybe_from_u64(1920, I64)
766         );
767 
768         assert_eq!(
769             Some(ImmLogic {
770                 value: 0x7ffe,
771                 n: true,
772                 r: 63,
773                 s: 13,
774                 size: InstSize::Size64,
775             }),
776             ImmLogic::maybe_from_u64(0x7ffe, I64)
777         );
778 
779         assert_eq!(
780             Some(ImmLogic {
781                 value: 0x30000,
782                 n: true,
783                 r: 48,
784                 s: 1,
785                 size: InstSize::Size64,
786             }),
787             ImmLogic::maybe_from_u64(0x30000, I64)
788         );
789 
790         assert_eq!(
791             Some(ImmLogic {
792                 value: 0x100000,
793                 n: true,
794                 r: 44,
795                 s: 0,
796                 size: InstSize::Size64,
797             }),
798             ImmLogic::maybe_from_u64(0x100000, I64)
799         );
800 
801         assert_eq!(
802             Some(ImmLogic {
803                 value: u64::max_value() - 1,
804                 n: true,
805                 r: 63,
806                 s: 62,
807                 size: InstSize::Size64,
808             }),
809             ImmLogic::maybe_from_u64(u64::max_value() - 1, I64)
810         );
811 
812         assert_eq!(
813             Some(ImmLogic {
814                 value: 0xaaaaaaaaaaaaaaaa,
815                 n: false,
816                 r: 1,
817                 s: 60,
818                 size: InstSize::Size64,
819             }),
820             ImmLogic::maybe_from_u64(0xaaaaaaaaaaaaaaaa, I64)
821         );
822 
823         assert_eq!(
824             Some(ImmLogic {
825                 value: 0x8181818181818181,
826                 n: false,
827                 r: 1,
828                 s: 49,
829                 size: InstSize::Size64,
830             }),
831             ImmLogic::maybe_from_u64(0x8181818181818181, I64)
832         );
833 
834         assert_eq!(
835             Some(ImmLogic {
836                 value: 0xffc3ffc3ffc3ffc3,
837                 n: false,
838                 r: 10,
839                 s: 43,
840                 size: InstSize::Size64,
841             }),
842             ImmLogic::maybe_from_u64(0xffc3ffc3ffc3ffc3, I64)
843         );
844 
845         assert_eq!(
846             Some(ImmLogic {
847                 value: 0x100000001,
848                 n: false,
849                 r: 0,
850                 s: 0,
851                 size: InstSize::Size64,
852             }),
853             ImmLogic::maybe_from_u64(0x100000001, I64)
854         );
855 
856         assert_eq!(
857             Some(ImmLogic {
858                 value: 0x1111111111111111,
859                 n: false,
860                 r: 0,
861                 s: 56,
862                 size: InstSize::Size64,
863             }),
864             ImmLogic::maybe_from_u64(0x1111111111111111, I64)
865         );
866 
867         for n in 0..2 {
868             let types = if n == 0 { vec![I64, I32] } else { vec![I64] };
869             for s in 0..64 {
870                 for r in 0..64 {
871                     let imm = get_logical_imm(n, s, r);
872                     for &ty in &types {
873                         match ImmLogic::maybe_from_u64(imm, ty) {
874                             Some(ImmLogic { value, .. }) => {
875                                 assert_eq!(imm, value);
876                                 ImmLogic::maybe_from_u64(!value, ty).unwrap();
877                             }
878                             None => assert_eq!(0, imm),
879                         };
880                     }
881                 }
882             }
883         }
884     }
885 
886     // Repeat a value that has `width` bits, across a 64-bit value.
repeat(value: u64, width: u64) -> u64887     fn repeat(value: u64, width: u64) -> u64 {
888         let mut result = value & ((1 << width) - 1);
889         let mut i = width;
890         while i < 64 {
891             result |= result << i;
892             i *= 2;
893         }
894         result
895     }
896 
897     // Get the logical immediate, from the encoding N/R/S bits.
get_logical_imm(n: u32, s: u32, r: u32) -> u64898     fn get_logical_imm(n: u32, s: u32, r: u32) -> u64 {
899         // An integer is constructed from the n, imm_s and imm_r bits according to
900         // the following table:
901         //
902         //  N   imms    immr    size        S             R
903         //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
904         //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
905         //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
906         //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
907         //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
908         //  0  11110s  xxxxxr     2    UInt(s)       UInt(r)
909         // (s bits must not be all set)
910         //
911         // A pattern is constructed of size bits, where the least significant S+1
912         // bits are set. The pattern is rotated right by R, and repeated across a
913         // 64-bit value.
914 
915         if n == 1 {
916             if s == 0x3f {
917                 return 0;
918             }
919             let bits = (1u64 << (s + 1)) - 1;
920             bits.rotate_right(r)
921         } else {
922             if (s >> 1) == 0x1f {
923                 return 0;
924             }
925             let mut width = 0x20;
926             while width >= 0x2 {
927                 if (s & width) == 0 {
928                     let mask = width - 1;
929                     if (s & mask) == mask {
930                         return 0;
931                     }
932                     let bits = (1u64 << ((s & mask) + 1)) - 1;
933                     return repeat(bits.rotate_right(r & mask), width.into());
934                 }
935                 width >>= 1;
936             }
937             unreachable!();
938         }
939     }
940 }
941