909 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the AArch64 addressing mode implementation stuff.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H14#define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H15 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 23namespace llvm {24 25/// AArch64_AM - AArch64 Addressing Mode Stuff26namespace AArch64_AM {27 28//===----------------------------------------------------------------------===//29// Shifts30//31 32enum 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.52static 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.73static 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.85static inline unsigned getShiftValue(unsigned Imm) {86 return Imm & 0x3f;87}88 89/// getShifterImm - Encode the shift type and amount:90/// imm: 6-bit shift amount91/// shifter: 000 ==> lsl92/// 001 ==> lsr93/// 010 ==> asr94/// 011 ==> ror95/// 100 ==> msl96/// {8-6} = shifter97/// {5-0} = imm98static inline unsigned getShifterImm(AArch64_AM::ShiftExtendType ST,99 unsigned Imm) {100 assert((Imm & 0x3f) == Imm && "Illegal shifted immediate 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// Extends115//116 117/// getArithShiftValue - get the arithmetic shift value.118static inline unsigned getArithShiftValue(unsigned Imm) {119 return Imm & 0x7;120}121 122/// getExtendType - Extract the extend type for operands of arithmetic ops.123static 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 138static 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 ==> uxtb144/// 001 ==> uxth145/// 010 ==> uxtw146/// 011 ==> uxtx147/// 100 ==> sxtb148/// 101 ==> sxth149/// 110 ==> sxtw150/// 111 ==> sxtx151inline 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 an166/// arithmetic instruction:167/// imm: 3-bit extend amount168/// {5-3} = shifter169/// {2-0} = imm3170static inline unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET,171 unsigned Imm) {172 assert((Imm & 0x7) == Imm && "Illegal shifted immediate value!");173 return (getExtendEncoding(ET) << 3) | (Imm & 0x7);174}175 176/// getMemDoShift - Extract the "do shift" flag value for load/store177/// instructions.178static inline bool getMemDoShift(unsigned Imm) {179 return (Imm & 0x1) != 0;180}181 182/// getExtendType - Extract the extend type for the offset operand of183/// loads/stores.184static 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 size190/// shifter: 000 ==> uxtb191/// 001 ==> uxth192/// 010 ==> uxtw193/// 011 ==> uxtx194/// 100 ==> sxtb195/// 101 ==> sxth196/// 110 ==> sxtw197/// 111 ==> sxtx198/// {3-1} = shifter199/// {0} = doshift200static inline unsigned getMemExtendImm(AArch64_AM::ShiftExtendType ET,201 bool DoShift) {202 return (getExtendEncoding(ET) << 1) | unsigned(DoShift);203}204 205static 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 encoded210/// as the immediate operand of a logical instruction for the given register211/// size. If so, return true with "encoding" set to the encoded value in212/// the form N:immr:imms.213static 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^n253 // to our target value, where I is the number of RORs to go the opposite254 // 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 in259 // 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 bit263 // 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 logical274/// immediate instruction of the given register size. Return false otherwise.275static 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 logical281/// immediate instruction of the given register size.282static 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 form291/// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the292/// integer value it represents with regSize bits.293static 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 value319/// 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.321static 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 encoding328 return false;329 int len = 31 - llvm::countl_zero((N << 6) | (~imms & 0x3f));330 if (len < 0) // undefined logical immediate encoding331 return false;332 unsigned size = (1 << len);333 unsigned S = imms & (size - 1);334 if (S == size - 1) // undefined logical immediate encoding335 return false;336 337 return true;338}339 340//===----------------------------------------------------------------------===//341// Floating-point Immediates342//343static 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 Encoding351 // abcd efgh aBbbbbbc defgh000 00000000 00000000352 //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-bit365/// floating-point value. If the value cannot be represented as an 8-bit366/// floating-point value, then return -1.367static 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 15370 int32_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits371 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)-3379 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 386static 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-bit391/// floating-point value. If the value cannot be represented as an 8-bit392/// floating-point value, then return -1.393static 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 127396 int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits397 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)-3407 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 414static 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-bit419/// floating-point value. If the value cannot be represented as an 8-bit420/// floating-point value, then return -1.421static 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 1023424 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)-3435 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 442static inline int getFP64Imm(const APFloat &FPImm) {443 return getFP64Imm(FPImm.bitcastToAPInt());444}445 446//===--------------------------------------------------------------------===//447// AdvSIMD Modified Immediates448//===--------------------------------------------------------------------===//449 450// 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh451static inline bool isAdvSIMDModImmType1(uint64_t Imm) {452 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&453 ((Imm & 0xffffff00ffffff00ULL) == 0);454}455 456static inline uint8_t encodeAdvSIMDModImmType1(uint64_t Imm) {457 return (Imm & 0xffULL);458}459 460static 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 0x00466static inline bool isAdvSIMDModImmType2(uint64_t Imm) {467 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&468 ((Imm & 0xffff00ffffff00ffULL) == 0);469}470 471static inline uint8_t encodeAdvSIMDModImmType2(uint64_t Imm) {472 return (Imm & 0xff00ULL) >> 8;473}474 475static 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 0x00481static inline bool isAdvSIMDModImmType3(uint64_t Imm) {482 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&483 ((Imm & 0xff00ffffff00ffffULL) == 0);484}485 486static inline uint8_t encodeAdvSIMDModImmType3(uint64_t Imm) {487 return (Imm & 0xff0000ULL) >> 16;488}489 490static 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 0x00496static inline bool isAdvSIMDModImmType4(uint64_t Imm) {497 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&498 ((Imm & 0x00ffffff00ffffffULL) == 0);499}500 501static inline uint8_t encodeAdvSIMDModImmType4(uint64_t Imm) {502 return (Imm & 0xff000000ULL) >> 24;503}504 505static 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 abcdefgh511static inline bool isAdvSIMDModImmType5(uint64_t Imm) {512 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&513 (((Imm & 0x00ff0000ULL) >> 16) == (Imm & 0x000000ffULL)) &&514 ((Imm & 0xff00ff00ff00ff00ULL) == 0);515}516 517static inline uint8_t encodeAdvSIMDModImmType5(uint64_t Imm) {518 return (Imm & 0xffULL);519}520 521static 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 0x00527static inline bool isAdvSIMDModImmType6(uint64_t Imm) {528 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&529 (((Imm & 0xff000000ULL) >> 16) == (Imm & 0x0000ff00ULL)) &&530 ((Imm & 0x00ff00ff00ff00ffULL) == 0);531}532 533static inline uint8_t encodeAdvSIMDModImmType6(uint64_t Imm) {534 return (Imm & 0xff00ULL) >> 8;535}536 537static 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 0xFF543static inline bool isAdvSIMDModImmType7(uint64_t Imm) {544 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&545 ((Imm & 0xffff00ffffff00ffULL) == 0x000000ff000000ffULL);546}547 548static inline uint8_t encodeAdvSIMDModImmType7(uint64_t Imm) {549 return (Imm & 0xff00ULL) >> 8;550}551 552static 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 0xFF558static inline bool isAdvSIMDModImmType8(uint64_t Imm) {559 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&560 ((Imm & 0xff00ffffff00ffffULL) == 0x0000ffff0000ffffULL);561}562 563static inline uint64_t decodeAdvSIMDModImmType8(uint8_t Imm) {564 uint64_t EncVal = Imm;565 return (EncVal << 48) | (EncVal << 16) | 0x0000ffff0000ffffULL;566}567 568static inline uint8_t encodeAdvSIMDModImmType8(uint64_t Imm) {569 return (Imm & 0x00ff0000ULL) >> 16;570}571 572// abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh573static inline bool isAdvSIMDModImmType9(uint64_t Imm) {574 return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&575 ((Imm >> 48) == (Imm & 0x0000ffffULL)) &&576 ((Imm >> 56) == (Imm & 0x000000ffULL));577}578 579static inline uint8_t encodeAdvSIMDModImmType9(uint64_t Imm) {580 return (Imm & 0xffULL);581}582 583static 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 hhhhhhhh592// cmode: 1110, op: 1593static 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 that597 // causes an incorrect behavior with the original version. Work around598 // by using a slightly different variation.599 // https://developercommunity.visualstudio.com/t/C-ARM64-compiler-optimization-bug/10481261600 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#else615 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#endif633}634 635static 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 663static 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 0x00677static 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 684static 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 712static 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 0x00727static 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 733static 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 761static 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.776template <typename T>777static 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.783template <typename T>784static inline bool isSVECpyImm(int64_t Imm) {785 // Imm is interpreted as a signed value, which means top bits must be all ones786 // (sign bits if the immediate value is negative and passed in a larger787 // 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.806template <typename T>807static 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.814static 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 831inline 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 839inline 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 850inline 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 862inline 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 874static inline bool isSVECpyDupImm(int SizeInBits, int64_t Val, int32_t &Imm,875 int32_t &Shift) {876 switch (SizeInBits) {877 case 8:878 // All immediates are supported.879 Shift = 0;880 Imm = Val & 0xFF;881 return true;882 case 16:883 case 32:884 case 64:885 // Support 8bit signed immediates.886 if (Val >= -128 && Val <= 127) {887 Shift = 0;888 Imm = Val & 0xFF;889 return true;890 }891 // Support 16bit signed immediates that are a multiple of 256.892 if (Val >= -32768 && Val <= 32512 && Val % 256 == 0) {893 Shift = 8;894 Imm = (Val >> 8) & 0xFF;895 return true;896 }897 break;898 default:899 break;900 }901 return false;902}903 904} // end namespace AArch64_AM905 906} // end namespace llvm907 908#endif909