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