1 //===- AArch64AddressingModes.h - AArch64 Addressing Modes ------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains the AArch64 addressing mode implementation stuff. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H 14 #define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H 15 16 #include "llvm/ADT/APFloat.h" 17 #include "llvm/ADT/APInt.h" 18 #include "llvm/ADT/bit.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include "llvm/Support/MathExtras.h" 21 #include <cassert> 22 23 namespace llvm { 24 25 /// AArch64_AM - AArch64 Addressing Mode Stuff 26 namespace AArch64_AM { 27 28 //===----------------------------------------------------------------------===// 29 // Shifts 30 // 31 32 enum ShiftExtendType { 33 InvalidShiftExtend = -1, 34 LSL = 0, 35 LSR, 36 ASR, 37 ROR, 38 MSL, 39 40 UXTB, 41 UXTH, 42 UXTW, 43 UXTX, 44 45 SXTB, 46 SXTH, 47 SXTW, 48 SXTX, 49 }; 50 51 /// getShiftName - Get the string encoding for the shift type. 52 static inline const char *getShiftExtendName(AArch64_AM::ShiftExtendType ST) { 53 switch (ST) { 54 default: llvm_unreachable("unhandled shift type!"); 55 case AArch64_AM::LSL: return "lsl"; 56 case AArch64_AM::LSR: return "lsr"; 57 case AArch64_AM::ASR: return "asr"; 58 case AArch64_AM::ROR: return "ror"; 59 case AArch64_AM::MSL: return "msl"; 60 case AArch64_AM::UXTB: return "uxtb"; 61 case AArch64_AM::UXTH: return "uxth"; 62 case AArch64_AM::UXTW: return "uxtw"; 63 case AArch64_AM::UXTX: return "uxtx"; 64 case AArch64_AM::SXTB: return "sxtb"; 65 case AArch64_AM::SXTH: return "sxth"; 66 case AArch64_AM::SXTW: return "sxtw"; 67 case AArch64_AM::SXTX: return "sxtx"; 68 } 69 return nullptr; 70 } 71 72 /// getShiftType - Extract the shift type. 73 static inline AArch64_AM::ShiftExtendType getShiftType(unsigned Imm) { 74 switch ((Imm >> 6) & 0x7) { 75 default: return AArch64_AM::InvalidShiftExtend; 76 case 0: return AArch64_AM::LSL; 77 case 1: return AArch64_AM::LSR; 78 case 2: return AArch64_AM::ASR; 79 case 3: return AArch64_AM::ROR; 80 case 4: return AArch64_AM::MSL; 81 } 82 } 83 84 /// getShiftValue - Extract the shift value. 85 static inline unsigned getShiftValue(unsigned Imm) { 86 return Imm & 0x3f; 87 } 88 89 /// getShifterImm - Encode the shift type and amount: 90 /// imm: 6-bit shift amount 91 /// shifter: 000 ==> lsl 92 /// 001 ==> lsr 93 /// 010 ==> asr 94 /// 011 ==> ror 95 /// 100 ==> msl 96 /// {8-6} = shifter 97 /// {5-0} = imm 98 static inline unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, 99 unsigned Imm) { 100 assert((Imm & 0x3f) == Imm && "Illegal shifted immedate value!"); 101 unsigned STEnc = 0; 102 switch (ST) { 103 default: llvm_unreachable("Invalid shift requested"); 104 case AArch64_AM::LSL: STEnc = 0; break; 105 case AArch64_AM::LSR: STEnc = 1; break; 106 case AArch64_AM::ASR: STEnc = 2; break; 107 case AArch64_AM::ROR: STEnc = 3; break; 108 case AArch64_AM::MSL: STEnc = 4; break; 109 } 110 return (STEnc << 6) | (Imm & 0x3f); 111 } 112 113 //===----------------------------------------------------------------------===// 114 // Extends 115 // 116 117 /// getArithShiftValue - get the arithmetic shift value. 118 static inline unsigned getArithShiftValue(unsigned Imm) { 119 return Imm & 0x7; 120 } 121 122 /// getExtendType - Extract the extend type for operands of arithmetic ops. 123 static inline AArch64_AM::ShiftExtendType getExtendType(unsigned Imm) { 124 assert((Imm & 0x7) == Imm && "invalid immediate!"); 125 switch (Imm) { 126 default: llvm_unreachable("Compiler bug!"); 127 case 0: return AArch64_AM::UXTB; 128 case 1: return AArch64_AM::UXTH; 129 case 2: return AArch64_AM::UXTW; 130 case 3: return AArch64_AM::UXTX; 131 case 4: return AArch64_AM::SXTB; 132 case 5: return AArch64_AM::SXTH; 133 case 6: return AArch64_AM::SXTW; 134 case 7: return AArch64_AM::SXTX; 135 } 136 } 137 138 static inline AArch64_AM::ShiftExtendType getArithExtendType(unsigned Imm) { 139 return getExtendType((Imm >> 3) & 0x7); 140 } 141 142 /// Mapping from extend bits to required operation: 143 /// shifter: 000 ==> uxtb 144 /// 001 ==> uxth 145 /// 010 ==> uxtw 146 /// 011 ==> uxtx 147 /// 100 ==> sxtb 148 /// 101 ==> sxth 149 /// 110 ==> sxtw 150 /// 111 ==> sxtx 151 inline unsigned getExtendEncoding(AArch64_AM::ShiftExtendType ET) { 152 switch (ET) { 153 default: llvm_unreachable("Invalid extend type requested"); 154 case AArch64_AM::UXTB: return 0; break; 155 case AArch64_AM::UXTH: return 1; break; 156 case AArch64_AM::UXTW: return 2; break; 157 case AArch64_AM::UXTX: return 3; break; 158 case AArch64_AM::SXTB: return 4; break; 159 case AArch64_AM::SXTH: return 5; break; 160 case AArch64_AM::SXTW: return 6; break; 161 case AArch64_AM::SXTX: return 7; break; 162 } 163 } 164 165 /// getArithExtendImm - Encode the extend type and shift amount for an 166 /// arithmetic instruction: 167 /// imm: 3-bit extend amount 168 /// {5-3} = shifter 169 /// {2-0} = imm3 170 static inline unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, 171 unsigned Imm) { 172 assert((Imm & 0x7) == Imm && "Illegal shifted immedate value!"); 173 return (getExtendEncoding(ET) << 3) | (Imm & 0x7); 174 } 175 176 /// getMemDoShift - Extract the "do shift" flag value for load/store 177 /// instructions. 178 static inline bool getMemDoShift(unsigned Imm) { 179 return (Imm & 0x1) != 0; 180 } 181 182 /// getExtendType - Extract the extend type for the offset operand of 183 /// loads/stores. 184 static inline AArch64_AM::ShiftExtendType getMemExtendType(unsigned Imm) { 185 return getExtendType((Imm >> 1) & 0x7); 186 } 187 188 /// getExtendImm - Encode the extend type and amount for a load/store inst: 189 /// doshift: should the offset be scaled by the access size 190 /// shifter: 000 ==> uxtb 191 /// 001 ==> uxth 192 /// 010 ==> uxtw 193 /// 011 ==> uxtx 194 /// 100 ==> sxtb 195 /// 101 ==> sxth 196 /// 110 ==> sxtw 197 /// 111 ==> sxtx 198 /// {3-1} = shifter 199 /// {0} = doshift 200 static inline unsigned getMemExtendImm(AArch64_AM::ShiftExtendType ET, 201 bool DoShift) { 202 return (getExtendEncoding(ET) << 1) | unsigned(DoShift); 203 } 204 205 static inline uint64_t ror(uint64_t elt, unsigned size) { 206 return ((elt & 1) << (size-1)) | (elt >> 1); 207 } 208 209 /// processLogicalImmediate - Determine if an immediate value can be encoded 210 /// as the immediate operand of a logical instruction for the given register 211 /// size. If so, return true with "encoding" set to the encoded value in 212 /// the form N:immr:imms. 213 static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, 214 uint64_t &Encoding) { 215 if (Imm == 0ULL || Imm == ~0ULL || 216 (RegSize != 64 && 217 (Imm >> RegSize != 0 || Imm == (~0ULL >> (64 - RegSize))))) 218 return false; 219 220 // First, determine the element size. 221 unsigned Size = RegSize; 222 223 do { 224 Size /= 2; 225 uint64_t Mask = (1ULL << Size) - 1; 226 227 if ((Imm & Mask) != ((Imm >> Size) & Mask)) { 228 Size *= 2; 229 break; 230 } 231 } while (Size > 2); 232 233 // Second, determine the rotation to make the element be: 0^m 1^n. 234 uint32_t CTO, I; 235 uint64_t Mask = ((uint64_t)-1LL) >> (64 - Size); 236 Imm &= Mask; 237 238 if (isShiftedMask_64(Imm)) { 239 I = llvm::countr_zero(Imm); 240 assert(I < 64 && "undefined behavior"); 241 CTO = llvm::countr_one(Imm >> I); 242 } else { 243 Imm |= ~Mask; 244 if (!isShiftedMask_64(~Imm)) 245 return false; 246 247 unsigned CLO = llvm::countl_one(Imm); 248 I = 64 - CLO; 249 CTO = CLO + llvm::countr_one(Imm) - (64 - Size); 250 } 251 252 // Encode in Immr the number of RORs it would take to get *from* 0^m 1^n 253 // to our target value, where I is the number of RORs to go the opposite 254 // direction. 255 assert(Size > I && "I should be smaller than element size"); 256 unsigned Immr = (Size - I) & (Size - 1); 257 258 // If size has a 1 in the n'th bit, create a value that has zeroes in 259 // bits [0, n] and ones above that. 260 uint64_t NImms = ~(Size-1) << 1; 261 262 // Or the CTO value into the low bits, which must be below the Nth bit 263 // bit mentioned above. 264 NImms |= (CTO-1); 265 266 // Extract the seventh bit and toggle it to create the N field. 267 unsigned N = ((NImms >> 6) & 1) ^ 1; 268 269 Encoding = (N << 12) | (Immr << 6) | (NImms & 0x3f); 270 return true; 271 } 272 273 /// isLogicalImmediate - Return true if the immediate is valid for a logical 274 /// immediate instruction of the given register size. Return false otherwise. 275 static inline bool isLogicalImmediate(uint64_t imm, unsigned regSize) { 276 uint64_t encoding; 277 return processLogicalImmediate(imm, regSize, encoding); 278 } 279 280 /// encodeLogicalImmediate - Return the encoded immediate value for a logical 281 /// immediate instruction of the given register size. 282 static inline uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize) { 283 uint64_t encoding = 0; 284 bool res = processLogicalImmediate(imm, regSize, encoding); 285 assert(res && "invalid logical immediate"); 286 (void)res; 287 return encoding; 288 } 289 290 /// decodeLogicalImmediate - Decode a logical immediate value in the form 291 /// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the 292 /// integer value it represents with regSize bits. 293 static inline uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize) { 294 // Extract the N, imms, and immr fields. 295 unsigned N = (val >> 12) & 1; 296 unsigned immr = (val >> 6) & 0x3f; 297 unsigned imms = val & 0x3f; 298 299 assert((regSize == 64 || N == 0) && "undefined logical immediate encoding"); 300 int len = 31 - llvm::countl_zero((N << 6) | (~imms & 0x3f)); 301 assert(len >= 0 && "undefined logical immediate encoding"); 302 unsigned size = (1 << len); 303 unsigned R = immr & (size - 1); 304 unsigned S = imms & (size - 1); 305 assert(S != size - 1 && "undefined logical immediate encoding"); 306 uint64_t pattern = (1ULL << (S + 1)) - 1; 307 for (unsigned i = 0; i < R; ++i) 308 pattern = ror(pattern, size); 309 310 // Replicate the pattern to fill the regSize. 311 while (size != regSize) { 312 pattern |= (pattern << size); 313 size *= 2; 314 } 315 return pattern; 316 } 317 318 /// isValidDecodeLogicalImmediate - Check to see if the logical immediate value 319 /// in the form "N:immr:imms" (where the immr and imms fields are each 6 bits) 320 /// is a valid encoding for an integer value with regSize bits. 321 static inline bool isValidDecodeLogicalImmediate(uint64_t val, 322 unsigned regSize) { 323 // Extract the N and imms fields needed for checking. 324 unsigned N = (val >> 12) & 1; 325 unsigned imms = val & 0x3f; 326 327 if (regSize == 32 && N != 0) // undefined logical immediate encoding 328 return false; 329 int len = 31 - llvm::countl_zero((N << 6) | (~imms & 0x3f)); 330 if (len < 0) // undefined logical immediate encoding 331 return false; 332 unsigned size = (1 << len); 333 unsigned S = imms & (size - 1); 334 if (S == size - 1) // undefined logical immediate encoding 335 return false; 336 337 return true; 338 } 339 340 //===----------------------------------------------------------------------===// 341 // Floating-point Immediates 342 // 343 static inline float getFPImmFloat(unsigned Imm) { 344 // We expect an 8-bit binary encoding of a floating-point number here. 345 346 uint8_t Sign = (Imm >> 7) & 0x1; 347 uint8_t Exp = (Imm >> 4) & 0x7; 348 uint8_t Mantissa = Imm & 0xf; 349 350 // 8-bit FP IEEE Float Encoding 351 // abcd efgh aBbbbbbc defgh000 00000000 00000000 352 // 353 // where B = NOT(b); 354 355 uint32_t I = 0; 356 I |= Sign << 31; 357 I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; 358 I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; 359 I |= (Exp & 0x3) << 23; 360 I |= Mantissa << 19; 361 return bit_cast<float>(I); 362 } 363 364 /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit 365 /// floating-point value. If the value cannot be represented as an 8-bit 366 /// floating-point value, then return -1. 367 static inline int getFP16Imm(const APInt &Imm) { 368 uint32_t Sign = Imm.lshr(15).getZExtValue() & 1; 369 int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15; // -14 to 15 370 int32_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits 371 372 // We can handle 4 bits of mantissa. 373 // mantissa = (16+UInt(e:f:g:h))/16. 374 if (Mantissa & 0x3f) 375 return -1; 376 Mantissa >>= 6; 377 378 // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 379 if (Exp < -3 || Exp > 4) 380 return -1; 381 Exp = ((Exp+3) & 0x7) ^ 4; 382 383 return ((int)Sign << 7) | (Exp << 4) | Mantissa; 384 } 385 386 static inline int getFP16Imm(const APFloat &FPImm) { 387 return getFP16Imm(FPImm.bitcastToAPInt()); 388 } 389 390 /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit 391 /// floating-point value. If the value cannot be represented as an 8-bit 392 /// floating-point value, then return -1. 393 static inline int getFP32Imm(const APInt &Imm) { 394 uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; 395 int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 396 int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits 397 398 // We can handle 4 bits of mantissa. 399 // mantissa = (16+UInt(e:f:g:h))/16. 400 if (Mantissa & 0x7ffff) 401 return -1; 402 Mantissa >>= 19; 403 if ((Mantissa & 0xf) != Mantissa) 404 return -1; 405 406 // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 407 if (Exp < -3 || Exp > 4) 408 return -1; 409 Exp = ((Exp+3) & 0x7) ^ 4; 410 411 return ((int)Sign << 7) | (Exp << 4) | Mantissa; 412 } 413 414 static inline int getFP32Imm(const APFloat &FPImm) { 415 return getFP32Imm(FPImm.bitcastToAPInt()); 416 } 417 418 /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit 419 /// floating-point value. If the value cannot be represented as an 8-bit 420 /// floating-point value, then return -1. 421 static inline int getFP64Imm(const APInt &Imm) { 422 uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; 423 int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 424 uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; 425 426 // We can handle 4 bits of mantissa. 427 // mantissa = (16+UInt(e:f:g:h))/16. 428 if (Mantissa & 0xffffffffffffULL) 429 return -1; 430 Mantissa >>= 48; 431 if ((Mantissa & 0xf) != Mantissa) 432 return -1; 433 434 // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 435 if (Exp < -3 || Exp > 4) 436 return -1; 437 Exp = ((Exp+3) & 0x7) ^ 4; 438 439 return ((int)Sign << 7) | (Exp << 4) | Mantissa; 440 } 441 442 static inline int getFP64Imm(const APFloat &FPImm) { 443 return getFP64Imm(FPImm.bitcastToAPInt()); 444 } 445 446 //===--------------------------------------------------------------------===// 447 // AdvSIMD Modified Immediates 448 //===--------------------------------------------------------------------===// 449 450 // 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 451 static inline bool isAdvSIMDModImmType1(uint64_t Imm) { 452 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 453 ((Imm & 0xffffff00ffffff00ULL) == 0); 454 } 455 456 static inline uint8_t encodeAdvSIMDModImmType1(uint64_t Imm) { 457 return (Imm & 0xffULL); 458 } 459 460 static inline uint64_t decodeAdvSIMDModImmType1(uint8_t Imm) { 461 uint64_t EncVal = Imm; 462 return (EncVal << 32) | EncVal; 463 } 464 465 // 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 466 static inline bool isAdvSIMDModImmType2(uint64_t Imm) { 467 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 468 ((Imm & 0xffff00ffffff00ffULL) == 0); 469 } 470 471 static inline uint8_t encodeAdvSIMDModImmType2(uint64_t Imm) { 472 return (Imm & 0xff00ULL) >> 8; 473 } 474 475 static inline uint64_t decodeAdvSIMDModImmType2(uint8_t Imm) { 476 uint64_t EncVal = Imm; 477 return (EncVal << 40) | (EncVal << 8); 478 } 479 480 // 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 481 static inline bool isAdvSIMDModImmType3(uint64_t Imm) { 482 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 483 ((Imm & 0xff00ffffff00ffffULL) == 0); 484 } 485 486 static inline uint8_t encodeAdvSIMDModImmType3(uint64_t Imm) { 487 return (Imm & 0xff0000ULL) >> 16; 488 } 489 490 static inline uint64_t decodeAdvSIMDModImmType3(uint8_t Imm) { 491 uint64_t EncVal = Imm; 492 return (EncVal << 48) | (EncVal << 16); 493 } 494 495 // abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 496 static inline bool isAdvSIMDModImmType4(uint64_t Imm) { 497 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 498 ((Imm & 0x00ffffff00ffffffULL) == 0); 499 } 500 501 static inline uint8_t encodeAdvSIMDModImmType4(uint64_t Imm) { 502 return (Imm & 0xff000000ULL) >> 24; 503 } 504 505 static inline uint64_t decodeAdvSIMDModImmType4(uint8_t Imm) { 506 uint64_t EncVal = Imm; 507 return (EncVal << 56) | (EncVal << 24); 508 } 509 510 // 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 511 static inline bool isAdvSIMDModImmType5(uint64_t Imm) { 512 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 513 (((Imm & 0x00ff0000ULL) >> 16) == (Imm & 0x000000ffULL)) && 514 ((Imm & 0xff00ff00ff00ff00ULL) == 0); 515 } 516 517 static inline uint8_t encodeAdvSIMDModImmType5(uint64_t Imm) { 518 return (Imm & 0xffULL); 519 } 520 521 static inline uint64_t decodeAdvSIMDModImmType5(uint8_t Imm) { 522 uint64_t EncVal = Imm; 523 return (EncVal << 48) | (EncVal << 32) | (EncVal << 16) | EncVal; 524 } 525 526 // abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 527 static inline bool isAdvSIMDModImmType6(uint64_t Imm) { 528 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 529 (((Imm & 0xff000000ULL) >> 16) == (Imm & 0x0000ff00ULL)) && 530 ((Imm & 0x00ff00ff00ff00ffULL) == 0); 531 } 532 533 static inline uint8_t encodeAdvSIMDModImmType6(uint64_t Imm) { 534 return (Imm & 0xff00ULL) >> 8; 535 } 536 537 static inline uint64_t decodeAdvSIMDModImmType6(uint8_t Imm) { 538 uint64_t EncVal = Imm; 539 return (EncVal << 56) | (EncVal << 40) | (EncVal << 24) | (EncVal << 8); 540 } 541 542 // 0x00 0x00 abcdefgh 0xFF 0x00 0x00 abcdefgh 0xFF 543 static inline bool isAdvSIMDModImmType7(uint64_t Imm) { 544 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 545 ((Imm & 0xffff00ffffff00ffULL) == 0x000000ff000000ffULL); 546 } 547 548 static inline uint8_t encodeAdvSIMDModImmType7(uint64_t Imm) { 549 return (Imm & 0xff00ULL) >> 8; 550 } 551 552 static inline uint64_t decodeAdvSIMDModImmType7(uint8_t Imm) { 553 uint64_t EncVal = Imm; 554 return (EncVal << 40) | (EncVal << 8) | 0x000000ff000000ffULL; 555 } 556 557 // 0x00 abcdefgh 0xFF 0xFF 0x00 abcdefgh 0xFF 0xFF 558 static inline bool isAdvSIMDModImmType8(uint64_t Imm) { 559 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 560 ((Imm & 0xff00ffffff00ffffULL) == 0x0000ffff0000ffffULL); 561 } 562 563 static inline uint64_t decodeAdvSIMDModImmType8(uint8_t Imm) { 564 uint64_t EncVal = Imm; 565 return (EncVal << 48) | (EncVal << 16) | 0x0000ffff0000ffffULL; 566 } 567 568 static inline uint8_t encodeAdvSIMDModImmType8(uint64_t Imm) { 569 return (Imm & 0x00ff0000ULL) >> 16; 570 } 571 572 // abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh 573 static inline bool isAdvSIMDModImmType9(uint64_t Imm) { 574 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 575 ((Imm >> 48) == (Imm & 0x0000ffffULL)) && 576 ((Imm >> 56) == (Imm & 0x000000ffULL)); 577 } 578 579 static inline uint8_t encodeAdvSIMDModImmType9(uint64_t Imm) { 580 return (Imm & 0xffULL); 581 } 582 583 static inline uint64_t decodeAdvSIMDModImmType9(uint8_t Imm) { 584 uint64_t EncVal = Imm; 585 EncVal |= (EncVal << 8); 586 EncVal |= (EncVal << 16); 587 EncVal |= (EncVal << 32); 588 return EncVal; 589 } 590 591 // aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh 592 // cmode: 1110, op: 1 593 static inline bool isAdvSIMDModImmType10(uint64_t Imm) { 594 #if defined(_MSC_VER) && _MSC_VER == 1937 && !defined(__clang__) && \ 595 defined(_M_ARM64) 596 // The MSVC compiler 19.37 for ARM64 has an optimization bug that 597 // causes an incorrect behavior with the orignal version. Work around 598 // by using a slightly different variation. 599 // https://developercommunity.visualstudio.com/t/C-ARM64-compiler-optimization-bug/10481261 600 constexpr uint64_t Mask = 0xFFULL; 601 uint64_t ByteA = (Imm >> 56) & Mask; 602 uint64_t ByteB = (Imm >> 48) & Mask; 603 uint64_t ByteC = (Imm >> 40) & Mask; 604 uint64_t ByteD = (Imm >> 32) & Mask; 605 uint64_t ByteE = (Imm >> 24) & Mask; 606 uint64_t ByteF = (Imm >> 16) & Mask; 607 uint64_t ByteG = (Imm >> 8) & Mask; 608 uint64_t ByteH = Imm & Mask; 609 610 return (ByteA == 0ULL || ByteA == Mask) && (ByteB == 0ULL || ByteB == Mask) && 611 (ByteC == 0ULL || ByteC == Mask) && (ByteD == 0ULL || ByteD == Mask) && 612 (ByteE == 0ULL || ByteE == Mask) && (ByteF == 0ULL || ByteF == Mask) && 613 (ByteG == 0ULL || ByteG == Mask) && (ByteH == 0ULL || ByteH == Mask); 614 #else 615 uint64_t ByteA = Imm & 0xff00000000000000ULL; 616 uint64_t ByteB = Imm & 0x00ff000000000000ULL; 617 uint64_t ByteC = Imm & 0x0000ff0000000000ULL; 618 uint64_t ByteD = Imm & 0x000000ff00000000ULL; 619 uint64_t ByteE = Imm & 0x00000000ff000000ULL; 620 uint64_t ByteF = Imm & 0x0000000000ff0000ULL; 621 uint64_t ByteG = Imm & 0x000000000000ff00ULL; 622 uint64_t ByteH = Imm & 0x00000000000000ffULL; 623 624 return (ByteA == 0ULL || ByteA == 0xff00000000000000ULL) && 625 (ByteB == 0ULL || ByteB == 0x00ff000000000000ULL) && 626 (ByteC == 0ULL || ByteC == 0x0000ff0000000000ULL) && 627 (ByteD == 0ULL || ByteD == 0x000000ff00000000ULL) && 628 (ByteE == 0ULL || ByteE == 0x00000000ff000000ULL) && 629 (ByteF == 0ULL || ByteF == 0x0000000000ff0000ULL) && 630 (ByteG == 0ULL || ByteG == 0x000000000000ff00ULL) && 631 (ByteH == 0ULL || ByteH == 0x00000000000000ffULL); 632 #endif 633 } 634 635 static inline uint8_t encodeAdvSIMDModImmType10(uint64_t Imm) { 636 uint8_t BitA = (Imm & 0xff00000000000000ULL) != 0; 637 uint8_t BitB = (Imm & 0x00ff000000000000ULL) != 0; 638 uint8_t BitC = (Imm & 0x0000ff0000000000ULL) != 0; 639 uint8_t BitD = (Imm & 0x000000ff00000000ULL) != 0; 640 uint8_t BitE = (Imm & 0x00000000ff000000ULL) != 0; 641 uint8_t BitF = (Imm & 0x0000000000ff0000ULL) != 0; 642 uint8_t BitG = (Imm & 0x000000000000ff00ULL) != 0; 643 uint8_t BitH = (Imm & 0x00000000000000ffULL) != 0; 644 645 uint8_t EncVal = BitA; 646 EncVal <<= 1; 647 EncVal |= BitB; 648 EncVal <<= 1; 649 EncVal |= BitC; 650 EncVal <<= 1; 651 EncVal |= BitD; 652 EncVal <<= 1; 653 EncVal |= BitE; 654 EncVal <<= 1; 655 EncVal |= BitF; 656 EncVal <<= 1; 657 EncVal |= BitG; 658 EncVal <<= 1; 659 EncVal |= BitH; 660 return EncVal; 661 } 662 663 static inline uint64_t decodeAdvSIMDModImmType10(uint8_t Imm) { 664 uint64_t EncVal = 0; 665 if (Imm & 0x80) EncVal |= 0xff00000000000000ULL; 666 if (Imm & 0x40) EncVal |= 0x00ff000000000000ULL; 667 if (Imm & 0x20) EncVal |= 0x0000ff0000000000ULL; 668 if (Imm & 0x10) EncVal |= 0x000000ff00000000ULL; 669 if (Imm & 0x08) EncVal |= 0x00000000ff000000ULL; 670 if (Imm & 0x04) EncVal |= 0x0000000000ff0000ULL; 671 if (Imm & 0x02) EncVal |= 0x000000000000ff00ULL; 672 if (Imm & 0x01) EncVal |= 0x00000000000000ffULL; 673 return EncVal; 674 } 675 676 // aBbbbbbc defgh000 0x00 0x00 aBbbbbbc defgh000 0x00 0x00 677 static inline bool isAdvSIMDModImmType11(uint64_t Imm) { 678 uint64_t BString = (Imm & 0x7E000000ULL) >> 25; 679 return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 680 (BString == 0x1f || BString == 0x20) && 681 ((Imm & 0x0007ffff0007ffffULL) == 0); 682 } 683 684 static inline uint8_t encodeAdvSIMDModImmType11(uint64_t Imm) { 685 uint8_t BitA = (Imm & 0x80000000ULL) != 0; 686 uint8_t BitB = (Imm & 0x20000000ULL) != 0; 687 uint8_t BitC = (Imm & 0x01000000ULL) != 0; 688 uint8_t BitD = (Imm & 0x00800000ULL) != 0; 689 uint8_t BitE = (Imm & 0x00400000ULL) != 0; 690 uint8_t BitF = (Imm & 0x00200000ULL) != 0; 691 uint8_t BitG = (Imm & 0x00100000ULL) != 0; 692 uint8_t BitH = (Imm & 0x00080000ULL) != 0; 693 694 uint8_t EncVal = BitA; 695 EncVal <<= 1; 696 EncVal |= BitB; 697 EncVal <<= 1; 698 EncVal |= BitC; 699 EncVal <<= 1; 700 EncVal |= BitD; 701 EncVal <<= 1; 702 EncVal |= BitE; 703 EncVal <<= 1; 704 EncVal |= BitF; 705 EncVal <<= 1; 706 EncVal |= BitG; 707 EncVal <<= 1; 708 EncVal |= BitH; 709 return EncVal; 710 } 711 712 static inline uint64_t decodeAdvSIMDModImmType11(uint8_t Imm) { 713 uint64_t EncVal = 0; 714 if (Imm & 0x80) EncVal |= 0x80000000ULL; 715 if (Imm & 0x40) EncVal |= 0x3e000000ULL; 716 else EncVal |= 0x40000000ULL; 717 if (Imm & 0x20) EncVal |= 0x01000000ULL; 718 if (Imm & 0x10) EncVal |= 0x00800000ULL; 719 if (Imm & 0x08) EncVal |= 0x00400000ULL; 720 if (Imm & 0x04) EncVal |= 0x00200000ULL; 721 if (Imm & 0x02) EncVal |= 0x00100000ULL; 722 if (Imm & 0x01) EncVal |= 0x00080000ULL; 723 return (EncVal << 32) | EncVal; 724 } 725 726 // aBbbbbbb bbcdefgh 0x00 0x00 0x00 0x00 0x00 0x00 727 static inline bool isAdvSIMDModImmType12(uint64_t Imm) { 728 uint64_t BString = (Imm & 0x7fc0000000000000ULL) >> 54; 729 return ((BString == 0xff || BString == 0x100) && 730 ((Imm & 0x0000ffffffffffffULL) == 0)); 731 } 732 733 static inline uint8_t encodeAdvSIMDModImmType12(uint64_t Imm) { 734 uint8_t BitA = (Imm & 0x8000000000000000ULL) != 0; 735 uint8_t BitB = (Imm & 0x0040000000000000ULL) != 0; 736 uint8_t BitC = (Imm & 0x0020000000000000ULL) != 0; 737 uint8_t BitD = (Imm & 0x0010000000000000ULL) != 0; 738 uint8_t BitE = (Imm & 0x0008000000000000ULL) != 0; 739 uint8_t BitF = (Imm & 0x0004000000000000ULL) != 0; 740 uint8_t BitG = (Imm & 0x0002000000000000ULL) != 0; 741 uint8_t BitH = (Imm & 0x0001000000000000ULL) != 0; 742 743 uint8_t EncVal = BitA; 744 EncVal <<= 1; 745 EncVal |= BitB; 746 EncVal <<= 1; 747 EncVal |= BitC; 748 EncVal <<= 1; 749 EncVal |= BitD; 750 EncVal <<= 1; 751 EncVal |= BitE; 752 EncVal <<= 1; 753 EncVal |= BitF; 754 EncVal <<= 1; 755 EncVal |= BitG; 756 EncVal <<= 1; 757 EncVal |= BitH; 758 return EncVal; 759 } 760 761 static inline uint64_t decodeAdvSIMDModImmType12(uint8_t Imm) { 762 uint64_t EncVal = 0; 763 if (Imm & 0x80) EncVal |= 0x8000000000000000ULL; 764 if (Imm & 0x40) EncVal |= 0x3fc0000000000000ULL; 765 else EncVal |= 0x4000000000000000ULL; 766 if (Imm & 0x20) EncVal |= 0x0020000000000000ULL; 767 if (Imm & 0x10) EncVal |= 0x0010000000000000ULL; 768 if (Imm & 0x08) EncVal |= 0x0008000000000000ULL; 769 if (Imm & 0x04) EncVal |= 0x0004000000000000ULL; 770 if (Imm & 0x02) EncVal |= 0x0002000000000000ULL; 771 if (Imm & 0x01) EncVal |= 0x0001000000000000ULL; 772 return (EncVal << 32) | EncVal; 773 } 774 775 /// Returns true if Imm is the concatenation of a repeating pattern of type T. 776 template <typename T> 777 static inline bool isSVEMaskOfIdenticalElements(int64_t Imm) { 778 auto Parts = bit_cast<std::array<T, sizeof(int64_t) / sizeof(T)>>(Imm); 779 return llvm::all_equal(Parts); 780 } 781 782 /// Returns true if Imm is valid for CPY/DUP. 783 template <typename T> 784 static inline bool isSVECpyImm(int64_t Imm) { 785 // Imm is interpreted as a signed value, which means top bits must be all ones 786 // (sign bits if the immediate value is negative and passed in a larger 787 // container), or all zeroes. 788 int64_t Mask = ~int64_t(std::numeric_limits<std::make_unsigned_t<T>>::max()); 789 if ((Imm & Mask) != 0 && (Imm & Mask) != Mask) 790 return false; 791 792 // Imm is a signed 8-bit value. 793 // Top bits must be zeroes or sign bits. 794 if (Imm & 0xff) 795 return int8_t(Imm) == T(Imm); 796 797 // Imm is a signed 16-bit value and multiple of 256. 798 // Top bits must be zeroes or sign bits. 799 if (Imm & 0xff00) 800 return int16_t(Imm) == T(Imm); 801 802 return Imm == 0; 803 } 804 805 /// Returns true if Imm is valid for ADD/SUB. 806 template <typename T> 807 static inline bool isSVEAddSubImm(int64_t Imm) { 808 bool IsInt8t = std::is_same<int8_t, std::make_signed_t<T>>::value || 809 std::is_same<int8_t, T>::value; 810 return uint8_t(Imm) == Imm || (!IsInt8t && uint16_t(Imm & ~0xff) == Imm); 811 } 812 813 /// Return true if Imm is valid for DUPM and has no single CPY/DUP equivalent. 814 static inline bool isSVEMoveMaskPreferredLogicalImmediate(int64_t Imm) { 815 if (isSVECpyImm<int64_t>(Imm)) 816 return false; 817 818 auto S = bit_cast<std::array<int32_t, 2>>(Imm); 819 auto H = bit_cast<std::array<int16_t, 4>>(Imm); 820 auto B = bit_cast<std::array<int8_t, 8>>(Imm); 821 822 if (isSVEMaskOfIdenticalElements<int32_t>(Imm) && isSVECpyImm<int32_t>(S[0])) 823 return false; 824 if (isSVEMaskOfIdenticalElements<int16_t>(Imm) && isSVECpyImm<int16_t>(H[0])) 825 return false; 826 if (isSVEMaskOfIdenticalElements<int8_t>(Imm) && isSVECpyImm<int8_t>(B[0])) 827 return false; 828 return isLogicalImmediate(Imm, 64); 829 } 830 831 inline static bool isAnyMOVZMovAlias(uint64_t Value, int RegWidth) { 832 for (int Shift = 0; Shift <= RegWidth - 16; Shift += 16) 833 if ((Value & ~(0xffffULL << Shift)) == 0) 834 return true; 835 836 return false; 837 } 838 839 inline static bool isMOVZMovAlias(uint64_t Value, int Shift, int RegWidth) { 840 if (RegWidth == 32) 841 Value &= 0xffffffffULL; 842 843 // "lsl #0" takes precedence: in practice this only affects "#0, lsl #0". 844 if (Value == 0 && Shift != 0) 845 return false; 846 847 return (Value & ~(0xffffULL << Shift)) == 0; 848 } 849 850 inline static bool isMOVNMovAlias(uint64_t Value, int Shift, int RegWidth) { 851 // MOVZ takes precedence over MOVN. 852 if (isAnyMOVZMovAlias(Value, RegWidth)) 853 return false; 854 855 Value = ~Value; 856 if (RegWidth == 32) 857 Value &= 0xffffffffULL; 858 859 return isMOVZMovAlias(Value, Shift, RegWidth); 860 } 861 862 inline static bool isAnyMOVWMovAlias(uint64_t Value, int RegWidth) { 863 if (isAnyMOVZMovAlias(Value, RegWidth)) 864 return true; 865 866 // It's not a MOVZ, but it might be a MOVN. 867 Value = ~Value; 868 if (RegWidth == 32) 869 Value &= 0xffffffffULL; 870 871 return isAnyMOVZMovAlias(Value, RegWidth); 872 } 873 874 } // end namespace AArch64_AM 875 876 } // end namespace llvm 877 878 #endif 879