xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- AArch64AddressingModes.h - AArch64 Addressing Modes ------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the AArch64 addressing mode implementation stuff.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H
140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ADT/APFloat.h"
170b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
180b57cec5SDimitry Andric #include "llvm/ADT/bit.h"
190b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
200b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
210b57cec5SDimitry Andric #include <cassert>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric /// AArch64_AM - AArch64 Addressing Mode Stuff
260b57cec5SDimitry Andric namespace AArch64_AM {
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
290b57cec5SDimitry Andric // Shifts
300b57cec5SDimitry Andric //
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric enum ShiftExtendType {
330b57cec5SDimitry Andric   InvalidShiftExtend = -1,
340b57cec5SDimitry Andric   LSL = 0,
350b57cec5SDimitry Andric   LSR,
360b57cec5SDimitry Andric   ASR,
370b57cec5SDimitry Andric   ROR,
380b57cec5SDimitry Andric   MSL,
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   UXTB,
410b57cec5SDimitry Andric   UXTH,
420b57cec5SDimitry Andric   UXTW,
430b57cec5SDimitry Andric   UXTX,
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   SXTB,
460b57cec5SDimitry Andric   SXTH,
470b57cec5SDimitry Andric   SXTW,
480b57cec5SDimitry Andric   SXTX,
490b57cec5SDimitry Andric };
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric /// getShiftName - Get the string encoding for the shift type.
520b57cec5SDimitry Andric static inline const char *getShiftExtendName(AArch64_AM::ShiftExtendType ST) {
530b57cec5SDimitry Andric   switch (ST) {
540b57cec5SDimitry Andric   default: llvm_unreachable("unhandled shift type!");
550b57cec5SDimitry Andric   case AArch64_AM::LSL: return "lsl";
560b57cec5SDimitry Andric   case AArch64_AM::LSR: return "lsr";
570b57cec5SDimitry Andric   case AArch64_AM::ASR: return "asr";
580b57cec5SDimitry Andric   case AArch64_AM::ROR: return "ror";
590b57cec5SDimitry Andric   case AArch64_AM::MSL: return "msl";
600b57cec5SDimitry Andric   case AArch64_AM::UXTB: return "uxtb";
610b57cec5SDimitry Andric   case AArch64_AM::UXTH: return "uxth";
620b57cec5SDimitry Andric   case AArch64_AM::UXTW: return "uxtw";
630b57cec5SDimitry Andric   case AArch64_AM::UXTX: return "uxtx";
640b57cec5SDimitry Andric   case AArch64_AM::SXTB: return "sxtb";
650b57cec5SDimitry Andric   case AArch64_AM::SXTH: return "sxth";
660b57cec5SDimitry Andric   case AArch64_AM::SXTW: return "sxtw";
670b57cec5SDimitry Andric   case AArch64_AM::SXTX: return "sxtx";
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric   return nullptr;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric /// getShiftType - Extract the shift type.
730b57cec5SDimitry Andric static inline AArch64_AM::ShiftExtendType getShiftType(unsigned Imm) {
740b57cec5SDimitry Andric   switch ((Imm >> 6) & 0x7) {
750b57cec5SDimitry Andric   default: return AArch64_AM::InvalidShiftExtend;
760b57cec5SDimitry Andric   case 0: return AArch64_AM::LSL;
770b57cec5SDimitry Andric   case 1: return AArch64_AM::LSR;
780b57cec5SDimitry Andric   case 2: return AArch64_AM::ASR;
790b57cec5SDimitry Andric   case 3: return AArch64_AM::ROR;
800b57cec5SDimitry Andric   case 4: return AArch64_AM::MSL;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric /// getShiftValue - Extract the shift value.
850b57cec5SDimitry Andric static inline unsigned getShiftValue(unsigned Imm) {
860b57cec5SDimitry Andric   return Imm & 0x3f;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric /// getShifterImm - Encode the shift type and amount:
900b57cec5SDimitry Andric ///   imm:     6-bit shift amount
910b57cec5SDimitry Andric ///   shifter: 000 ==> lsl
920b57cec5SDimitry Andric ///            001 ==> lsr
930b57cec5SDimitry Andric ///            010 ==> asr
940b57cec5SDimitry Andric ///            011 ==> ror
950b57cec5SDimitry Andric ///            100 ==> msl
960b57cec5SDimitry Andric ///   {8-6}  = shifter
970b57cec5SDimitry Andric ///   {5-0}  = imm
980b57cec5SDimitry Andric static inline unsigned getShifterImm(AArch64_AM::ShiftExtendType ST,
990b57cec5SDimitry Andric                                      unsigned Imm) {
1000b57cec5SDimitry Andric   assert((Imm & 0x3f) == Imm && "Illegal shifted immedate value!");
1010b57cec5SDimitry Andric   unsigned STEnc = 0;
1020b57cec5SDimitry Andric   switch (ST) {
1030b57cec5SDimitry Andric   default:  llvm_unreachable("Invalid shift requested");
1040b57cec5SDimitry Andric   case AArch64_AM::LSL: STEnc = 0; break;
1050b57cec5SDimitry Andric   case AArch64_AM::LSR: STEnc = 1; break;
1060b57cec5SDimitry Andric   case AArch64_AM::ASR: STEnc = 2; break;
1070b57cec5SDimitry Andric   case AArch64_AM::ROR: STEnc = 3; break;
1080b57cec5SDimitry Andric   case AArch64_AM::MSL: STEnc = 4; break;
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric   return (STEnc << 6) | (Imm & 0x3f);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1140b57cec5SDimitry Andric // Extends
1150b57cec5SDimitry Andric //
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric /// getArithShiftValue - get the arithmetic shift value.
1180b57cec5SDimitry Andric static inline unsigned getArithShiftValue(unsigned Imm) {
1190b57cec5SDimitry Andric   return Imm & 0x7;
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric /// getExtendType - Extract the extend type for operands of arithmetic ops.
1230b57cec5SDimitry Andric static inline AArch64_AM::ShiftExtendType getExtendType(unsigned Imm) {
1240b57cec5SDimitry Andric   assert((Imm & 0x7) == Imm && "invalid immediate!");
1250b57cec5SDimitry Andric   switch (Imm) {
1260b57cec5SDimitry Andric   default: llvm_unreachable("Compiler bug!");
1270b57cec5SDimitry Andric   case 0: return AArch64_AM::UXTB;
1280b57cec5SDimitry Andric   case 1: return AArch64_AM::UXTH;
1290b57cec5SDimitry Andric   case 2: return AArch64_AM::UXTW;
1300b57cec5SDimitry Andric   case 3: return AArch64_AM::UXTX;
1310b57cec5SDimitry Andric   case 4: return AArch64_AM::SXTB;
1320b57cec5SDimitry Andric   case 5: return AArch64_AM::SXTH;
1330b57cec5SDimitry Andric   case 6: return AArch64_AM::SXTW;
1340b57cec5SDimitry Andric   case 7: return AArch64_AM::SXTX;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric static inline AArch64_AM::ShiftExtendType getArithExtendType(unsigned Imm) {
1390b57cec5SDimitry Andric   return getExtendType((Imm >> 3) & 0x7);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric /// Mapping from extend bits to required operation:
1430b57cec5SDimitry Andric ///   shifter: 000 ==> uxtb
1440b57cec5SDimitry Andric ///            001 ==> uxth
1450b57cec5SDimitry Andric ///            010 ==> uxtw
1460b57cec5SDimitry Andric ///            011 ==> uxtx
1470b57cec5SDimitry Andric ///            100 ==> sxtb
1480b57cec5SDimitry Andric ///            101 ==> sxth
1490b57cec5SDimitry Andric ///            110 ==> sxtw
1500b57cec5SDimitry Andric ///            111 ==> sxtx
1510b57cec5SDimitry Andric inline unsigned getExtendEncoding(AArch64_AM::ShiftExtendType ET) {
1520b57cec5SDimitry Andric   switch (ET) {
1530b57cec5SDimitry Andric   default: llvm_unreachable("Invalid extend type requested");
1540b57cec5SDimitry Andric   case AArch64_AM::UXTB: return 0; break;
1550b57cec5SDimitry Andric   case AArch64_AM::UXTH: return 1; break;
1560b57cec5SDimitry Andric   case AArch64_AM::UXTW: return 2; break;
1570b57cec5SDimitry Andric   case AArch64_AM::UXTX: return 3; break;
1580b57cec5SDimitry Andric   case AArch64_AM::SXTB: return 4; break;
1590b57cec5SDimitry Andric   case AArch64_AM::SXTH: return 5; break;
1600b57cec5SDimitry Andric   case AArch64_AM::SXTW: return 6; break;
1610b57cec5SDimitry Andric   case AArch64_AM::SXTX: return 7; break;
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric /// getArithExtendImm - Encode the extend type and shift amount for an
1660b57cec5SDimitry Andric ///                     arithmetic instruction:
1670b57cec5SDimitry Andric ///   imm:     3-bit extend amount
1680b57cec5SDimitry Andric ///   {5-3}  = shifter
1690b57cec5SDimitry Andric ///   {2-0}  = imm3
1700b57cec5SDimitry Andric static inline unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET,
1710b57cec5SDimitry Andric                                          unsigned Imm) {
1720b57cec5SDimitry Andric   assert((Imm & 0x7) == Imm && "Illegal shifted immedate value!");
1730b57cec5SDimitry Andric   return (getExtendEncoding(ET) << 3) | (Imm & 0x7);
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric /// getMemDoShift - Extract the "do shift" flag value for load/store
1770b57cec5SDimitry Andric /// instructions.
1780b57cec5SDimitry Andric static inline bool getMemDoShift(unsigned Imm) {
1790b57cec5SDimitry Andric   return (Imm & 0x1) != 0;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric /// getExtendType - Extract the extend type for the offset operand of
1830b57cec5SDimitry Andric /// loads/stores.
1840b57cec5SDimitry Andric static inline AArch64_AM::ShiftExtendType getMemExtendType(unsigned Imm) {
1850b57cec5SDimitry Andric   return getExtendType((Imm >> 1) & 0x7);
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric /// getExtendImm - Encode the extend type and amount for a load/store inst:
1890b57cec5SDimitry Andric ///   doshift:     should the offset be scaled by the access size
1900b57cec5SDimitry Andric ///   shifter: 000 ==> uxtb
1910b57cec5SDimitry Andric ///            001 ==> uxth
1920b57cec5SDimitry Andric ///            010 ==> uxtw
1930b57cec5SDimitry Andric ///            011 ==> uxtx
1940b57cec5SDimitry Andric ///            100 ==> sxtb
1950b57cec5SDimitry Andric ///            101 ==> sxth
1960b57cec5SDimitry Andric ///            110 ==> sxtw
1970b57cec5SDimitry Andric ///            111 ==> sxtx
1980b57cec5SDimitry Andric ///   {3-1}  = shifter
1990b57cec5SDimitry Andric ///   {0}  = doshift
2000b57cec5SDimitry Andric static inline unsigned getMemExtendImm(AArch64_AM::ShiftExtendType ET,
2010b57cec5SDimitry Andric                                        bool DoShift) {
2020b57cec5SDimitry Andric   return (getExtendEncoding(ET) << 1) | unsigned(DoShift);
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric static inline uint64_t ror(uint64_t elt, unsigned size) {
2060b57cec5SDimitry Andric   return ((elt & 1) << (size-1)) | (elt >> 1);
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric /// processLogicalImmediate - Determine if an immediate value can be encoded
2100b57cec5SDimitry Andric /// as the immediate operand of a logical instruction for the given register
2110b57cec5SDimitry Andric /// size.  If so, return true with "encoding" set to the encoded value in
2120b57cec5SDimitry Andric /// the form N:immr:imms.
2130b57cec5SDimitry Andric static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize,
2140b57cec5SDimitry Andric                                            uint64_t &Encoding) {
2150b57cec5SDimitry Andric   if (Imm == 0ULL || Imm == ~0ULL ||
2160b57cec5SDimitry Andric       (RegSize != 64 &&
2170b57cec5SDimitry Andric         (Imm >> RegSize != 0 || Imm == (~0ULL >> (64 - RegSize)))))
2180b57cec5SDimitry Andric     return false;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // First, determine the element size.
2210b57cec5SDimitry Andric   unsigned Size = RegSize;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   do {
2240b57cec5SDimitry Andric     Size /= 2;
2250b57cec5SDimitry Andric     uint64_t Mask = (1ULL << Size) - 1;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     if ((Imm & Mask) != ((Imm >> Size) & Mask)) {
2280b57cec5SDimitry Andric       Size *= 2;
2290b57cec5SDimitry Andric       break;
2300b57cec5SDimitry Andric     }
2310b57cec5SDimitry Andric   } while (Size > 2);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   // Second, determine the rotation to make the element be: 0^m 1^n.
2340b57cec5SDimitry Andric   uint32_t CTO, I;
2350b57cec5SDimitry Andric   uint64_t Mask = ((uint64_t)-1LL) >> (64 - Size);
2360b57cec5SDimitry Andric   Imm &= Mask;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   if (isShiftedMask_64(Imm)) {
23906c3fb27SDimitry Andric     I = llvm::countr_zero(Imm);
2400b57cec5SDimitry Andric     assert(I < 64 && "undefined behavior");
24106c3fb27SDimitry Andric     CTO = llvm::countr_one(Imm >> I);
2420b57cec5SDimitry Andric   } else {
2430b57cec5SDimitry Andric     Imm |= ~Mask;
2440b57cec5SDimitry Andric     if (!isShiftedMask_64(~Imm))
2450b57cec5SDimitry Andric       return false;
2460b57cec5SDimitry Andric 
24706c3fb27SDimitry Andric     unsigned CLO = llvm::countl_one(Imm);
2480b57cec5SDimitry Andric     I = 64 - CLO;
24906c3fb27SDimitry Andric     CTO = CLO + llvm::countr_one(Imm) - (64 - Size);
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   // Encode in Immr the number of RORs it would take to get *from* 0^m 1^n
2530b57cec5SDimitry Andric   // to our target value, where I is the number of RORs to go the opposite
2540b57cec5SDimitry Andric   // direction.
2550b57cec5SDimitry Andric   assert(Size > I && "I should be smaller than element size");
2560b57cec5SDimitry Andric   unsigned Immr = (Size - I) & (Size - 1);
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   // If size has a 1 in the n'th bit, create a value that has zeroes in
2590b57cec5SDimitry Andric   // bits [0, n] and ones above that.
2600b57cec5SDimitry Andric   uint64_t NImms = ~(Size-1) << 1;
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // Or the CTO value into the low bits, which must be below the Nth bit
2630b57cec5SDimitry Andric   // bit mentioned above.
2640b57cec5SDimitry Andric   NImms |= (CTO-1);
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   // Extract the seventh bit and toggle it to create the N field.
2670b57cec5SDimitry Andric   unsigned N = ((NImms >> 6) & 1) ^ 1;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   Encoding = (N << 12) | (Immr << 6) | (NImms & 0x3f);
2700b57cec5SDimitry Andric   return true;
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric /// isLogicalImmediate - Return true if the immediate is valid for a logical
2740b57cec5SDimitry Andric /// immediate instruction of the given register size. Return false otherwise.
2750b57cec5SDimitry Andric static inline bool isLogicalImmediate(uint64_t imm, unsigned regSize) {
2760b57cec5SDimitry Andric   uint64_t encoding;
2770b57cec5SDimitry Andric   return processLogicalImmediate(imm, regSize, encoding);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric /// encodeLogicalImmediate - Return the encoded immediate value for a logical
2810b57cec5SDimitry Andric /// immediate instruction of the given register size.
2820b57cec5SDimitry Andric static inline uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize) {
2830b57cec5SDimitry Andric   uint64_t encoding = 0;
2840b57cec5SDimitry Andric   bool res = processLogicalImmediate(imm, regSize, encoding);
2850b57cec5SDimitry Andric   assert(res && "invalid logical immediate");
2860b57cec5SDimitry Andric   (void)res;
2870b57cec5SDimitry Andric   return encoding;
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric /// decodeLogicalImmediate - Decode a logical immediate value in the form
2910b57cec5SDimitry Andric /// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the
2920b57cec5SDimitry Andric /// integer value it represents with regSize bits.
2930b57cec5SDimitry Andric static inline uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize) {
2940b57cec5SDimitry Andric   // Extract the N, imms, and immr fields.
2950b57cec5SDimitry Andric   unsigned N = (val >> 12) & 1;
2960b57cec5SDimitry Andric   unsigned immr = (val >> 6) & 0x3f;
2970b57cec5SDimitry Andric   unsigned imms = val & 0x3f;
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   assert((regSize == 64 || N == 0) && "undefined logical immediate encoding");
30006c3fb27SDimitry Andric   int len = 31 - llvm::countl_zero((N << 6) | (~imms & 0x3f));
3010b57cec5SDimitry Andric   assert(len >= 0 && "undefined logical immediate encoding");
3020b57cec5SDimitry Andric   unsigned size = (1 << len);
3030b57cec5SDimitry Andric   unsigned R = immr & (size - 1);
3040b57cec5SDimitry Andric   unsigned S = imms & (size - 1);
3050b57cec5SDimitry Andric   assert(S != size - 1 && "undefined logical immediate encoding");
3060b57cec5SDimitry Andric   uint64_t pattern = (1ULL << (S + 1)) - 1;
3070b57cec5SDimitry Andric   for (unsigned i = 0; i < R; ++i)
3080b57cec5SDimitry Andric     pattern = ror(pattern, size);
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   // Replicate the pattern to fill the regSize.
3110b57cec5SDimitry Andric   while (size != regSize) {
3120b57cec5SDimitry Andric     pattern |= (pattern << size);
3130b57cec5SDimitry Andric     size *= 2;
3140b57cec5SDimitry Andric   }
3150b57cec5SDimitry Andric   return pattern;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric /// isValidDecodeLogicalImmediate - Check to see if the logical immediate value
3190b57cec5SDimitry Andric /// in the form "N:immr:imms" (where the immr and imms fields are each 6 bits)
3200b57cec5SDimitry Andric /// is a valid encoding for an integer value with regSize bits.
3210b57cec5SDimitry Andric static inline bool isValidDecodeLogicalImmediate(uint64_t val,
3220b57cec5SDimitry Andric                                                  unsigned regSize) {
3230b57cec5SDimitry Andric   // Extract the N and imms fields needed for checking.
3240b57cec5SDimitry Andric   unsigned N = (val >> 12) & 1;
3250b57cec5SDimitry Andric   unsigned imms = val & 0x3f;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   if (regSize == 32 && N != 0) // undefined logical immediate encoding
3280b57cec5SDimitry Andric     return false;
32906c3fb27SDimitry Andric   int len = 31 - llvm::countl_zero((N << 6) | (~imms & 0x3f));
3300b57cec5SDimitry Andric   if (len < 0) // undefined logical immediate encoding
3310b57cec5SDimitry Andric     return false;
3320b57cec5SDimitry Andric   unsigned size = (1 << len);
3330b57cec5SDimitry Andric   unsigned S = imms & (size - 1);
3340b57cec5SDimitry Andric   if (S == size - 1) // undefined logical immediate encoding
3350b57cec5SDimitry Andric     return false;
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   return true;
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3410b57cec5SDimitry Andric // Floating-point Immediates
3420b57cec5SDimitry Andric //
3430b57cec5SDimitry Andric static inline float getFPImmFloat(unsigned Imm) {
3440b57cec5SDimitry Andric   // We expect an 8-bit binary encoding of a floating-point number here.
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   uint8_t Sign = (Imm >> 7) & 0x1;
3470b57cec5SDimitry Andric   uint8_t Exp = (Imm >> 4) & 0x7;
3480b57cec5SDimitry Andric   uint8_t Mantissa = Imm & 0xf;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   //   8-bit FP    IEEE Float Encoding
3510b57cec5SDimitry Andric   //   abcd efgh   aBbbbbbc defgh000 00000000 00000000
3520b57cec5SDimitry Andric   //
3530b57cec5SDimitry Andric   // where B = NOT(b);
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   uint32_t I = 0;
3560b57cec5SDimitry Andric   I |= Sign << 31;
3570b57cec5SDimitry Andric   I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30;
3580b57cec5SDimitry Andric   I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25;
3590b57cec5SDimitry Andric   I |= (Exp & 0x3) << 23;
3600b57cec5SDimitry Andric   I |= Mantissa << 19;
3610b57cec5SDimitry Andric   return bit_cast<float>(I);
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit
3650b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit
3660b57cec5SDimitry Andric /// floating-point value, then return -1.
3670b57cec5SDimitry Andric static inline int getFP16Imm(const APInt &Imm) {
3680b57cec5SDimitry Andric   uint32_t Sign = Imm.lshr(15).getZExtValue() & 1;
3690b57cec5SDimitry Andric   int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15;  // -14 to 15
3700b57cec5SDimitry Andric   int32_t Mantissa = Imm.getZExtValue() & 0x3ff;  // 10 bits
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   // We can handle 4 bits of mantissa.
3730b57cec5SDimitry Andric   // mantissa = (16+UInt(e:f:g:h))/16.
3740b57cec5SDimitry Andric   if (Mantissa & 0x3f)
3750b57cec5SDimitry Andric     return -1;
3760b57cec5SDimitry Andric   Mantissa >>= 6;
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
3790b57cec5SDimitry Andric   if (Exp < -3 || Exp > 4)
3800b57cec5SDimitry Andric     return -1;
3810b57cec5SDimitry Andric   Exp = ((Exp+3) & 0x7) ^ 4;
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   return ((int)Sign << 7) | (Exp << 4) | Mantissa;
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric static inline int getFP16Imm(const APFloat &FPImm) {
3870b57cec5SDimitry Andric   return getFP16Imm(FPImm.bitcastToAPInt());
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit
3910b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit
3920b57cec5SDimitry Andric /// floating-point value, then return -1.
3930b57cec5SDimitry Andric static inline int getFP32Imm(const APInt &Imm) {
3940b57cec5SDimitry Andric   uint32_t Sign = Imm.lshr(31).getZExtValue() & 1;
3950b57cec5SDimitry Andric   int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127;  // -126 to 127
3960b57cec5SDimitry Andric   int64_t Mantissa = Imm.getZExtValue() & 0x7fffff;  // 23 bits
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // We can handle 4 bits of mantissa.
3990b57cec5SDimitry Andric   // mantissa = (16+UInt(e:f:g:h))/16.
4000b57cec5SDimitry Andric   if (Mantissa & 0x7ffff)
4010b57cec5SDimitry Andric     return -1;
4020b57cec5SDimitry Andric   Mantissa >>= 19;
4030b57cec5SDimitry Andric   if ((Mantissa & 0xf) != Mantissa)
4040b57cec5SDimitry Andric     return -1;
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
4070b57cec5SDimitry Andric   if (Exp < -3 || Exp > 4)
4080b57cec5SDimitry Andric     return -1;
4090b57cec5SDimitry Andric   Exp = ((Exp+3) & 0x7) ^ 4;
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   return ((int)Sign << 7) | (Exp << 4) | Mantissa;
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric static inline int getFP32Imm(const APFloat &FPImm) {
4150b57cec5SDimitry Andric   return getFP32Imm(FPImm.bitcastToAPInt());
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit
4190b57cec5SDimitry Andric /// floating-point value. If the value cannot be represented as an 8-bit
4200b57cec5SDimitry Andric /// floating-point value, then return -1.
4210b57cec5SDimitry Andric static inline int getFP64Imm(const APInt &Imm) {
4220b57cec5SDimitry Andric   uint64_t Sign = Imm.lshr(63).getZExtValue() & 1;
4230b57cec5SDimitry Andric   int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023;   // -1022 to 1023
4240b57cec5SDimitry Andric   uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL;
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric   // We can handle 4 bits of mantissa.
4270b57cec5SDimitry Andric   // mantissa = (16+UInt(e:f:g:h))/16.
4280b57cec5SDimitry Andric   if (Mantissa & 0xffffffffffffULL)
4290b57cec5SDimitry Andric     return -1;
4300b57cec5SDimitry Andric   Mantissa >>= 48;
4310b57cec5SDimitry Andric   if ((Mantissa & 0xf) != Mantissa)
4320b57cec5SDimitry Andric     return -1;
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric   // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3
4350b57cec5SDimitry Andric   if (Exp < -3 || Exp > 4)
4360b57cec5SDimitry Andric     return -1;
4370b57cec5SDimitry Andric   Exp = ((Exp+3) & 0x7) ^ 4;
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   return ((int)Sign << 7) | (Exp << 4) | Mantissa;
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric static inline int getFP64Imm(const APFloat &FPImm) {
4430b57cec5SDimitry Andric   return getFP64Imm(FPImm.bitcastToAPInt());
4440b57cec5SDimitry Andric }
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric //===--------------------------------------------------------------------===//
4470b57cec5SDimitry Andric // AdvSIMD Modified Immediates
4480b57cec5SDimitry Andric //===--------------------------------------------------------------------===//
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric // 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh
4510b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType1(uint64_t Imm) {
4520b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
4530b57cec5SDimitry Andric          ((Imm & 0xffffff00ffffff00ULL) == 0);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType1(uint64_t Imm) {
4570b57cec5SDimitry Andric   return (Imm & 0xffULL);
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType1(uint8_t Imm) {
4610b57cec5SDimitry Andric   uint64_t EncVal = Imm;
4620b57cec5SDimitry Andric   return (EncVal << 32) | EncVal;
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric // 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00
4660b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType2(uint64_t Imm) {
4670b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
4680b57cec5SDimitry Andric          ((Imm & 0xffff00ffffff00ffULL) == 0);
4690b57cec5SDimitry Andric }
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType2(uint64_t Imm) {
4720b57cec5SDimitry Andric   return (Imm & 0xff00ULL) >> 8;
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType2(uint8_t Imm) {
4760b57cec5SDimitry Andric   uint64_t EncVal = Imm;
4770b57cec5SDimitry Andric   return (EncVal << 40) | (EncVal << 8);
4780b57cec5SDimitry Andric }
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric // 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00
4810b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType3(uint64_t Imm) {
4820b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
4830b57cec5SDimitry Andric          ((Imm & 0xff00ffffff00ffffULL) == 0);
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType3(uint64_t Imm) {
4870b57cec5SDimitry Andric   return (Imm & 0xff0000ULL) >> 16;
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType3(uint8_t Imm) {
4910b57cec5SDimitry Andric   uint64_t EncVal = Imm;
4920b57cec5SDimitry Andric   return (EncVal << 48) | (EncVal << 16);
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric // abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00
4960b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType4(uint64_t Imm) {
4970b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
4980b57cec5SDimitry Andric          ((Imm & 0x00ffffff00ffffffULL) == 0);
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType4(uint64_t Imm) {
5020b57cec5SDimitry Andric   return (Imm & 0xff000000ULL) >> 24;
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType4(uint8_t Imm) {
5060b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5070b57cec5SDimitry Andric   return (EncVal << 56) | (EncVal << 24);
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric // 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh
5110b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType5(uint64_t Imm) {
5120b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
5130b57cec5SDimitry Andric          (((Imm & 0x00ff0000ULL) >> 16) == (Imm & 0x000000ffULL)) &&
5140b57cec5SDimitry Andric          ((Imm & 0xff00ff00ff00ff00ULL) == 0);
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType5(uint64_t Imm) {
5180b57cec5SDimitry Andric   return (Imm & 0xffULL);
5190b57cec5SDimitry Andric }
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType5(uint8_t Imm) {
5220b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5230b57cec5SDimitry Andric   return (EncVal << 48) | (EncVal << 32) | (EncVal << 16) | EncVal;
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric // abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00
5270b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType6(uint64_t Imm) {
5280b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
5290b57cec5SDimitry Andric          (((Imm & 0xff000000ULL) >> 16) == (Imm & 0x0000ff00ULL)) &&
5300b57cec5SDimitry Andric          ((Imm & 0x00ff00ff00ff00ffULL) == 0);
5310b57cec5SDimitry Andric }
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType6(uint64_t Imm) {
5340b57cec5SDimitry Andric   return (Imm & 0xff00ULL) >> 8;
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType6(uint8_t Imm) {
5380b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5390b57cec5SDimitry Andric   return (EncVal << 56) | (EncVal << 40) | (EncVal << 24) | (EncVal << 8);
5400b57cec5SDimitry Andric }
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric // 0x00 0x00 abcdefgh 0xFF 0x00 0x00 abcdefgh 0xFF
5430b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType7(uint64_t Imm) {
5440b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
5450b57cec5SDimitry Andric          ((Imm & 0xffff00ffffff00ffULL) == 0x000000ff000000ffULL);
5460b57cec5SDimitry Andric }
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType7(uint64_t Imm) {
5490b57cec5SDimitry Andric   return (Imm & 0xff00ULL) >> 8;
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType7(uint8_t Imm) {
5530b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5540b57cec5SDimitry Andric   return (EncVal << 40) | (EncVal << 8) | 0x000000ff000000ffULL;
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric // 0x00 abcdefgh 0xFF 0xFF 0x00 abcdefgh 0xFF 0xFF
5580b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType8(uint64_t Imm) {
5590b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
5600b57cec5SDimitry Andric          ((Imm & 0xff00ffffff00ffffULL) == 0x0000ffff0000ffffULL);
5610b57cec5SDimitry Andric }
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType8(uint8_t Imm) {
5640b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5650b57cec5SDimitry Andric   return (EncVal << 48) | (EncVal << 16) | 0x0000ffff0000ffffULL;
5660b57cec5SDimitry Andric }
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType8(uint64_t Imm) {
5690b57cec5SDimitry Andric   return (Imm & 0x00ff0000ULL) >> 16;
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric // abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh
5730b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType9(uint64_t Imm) {
5740b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
5750b57cec5SDimitry Andric          ((Imm >> 48) == (Imm & 0x0000ffffULL)) &&
5760b57cec5SDimitry Andric          ((Imm >> 56) == (Imm & 0x000000ffULL));
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType9(uint64_t Imm) {
5800b57cec5SDimitry Andric   return (Imm & 0xffULL);
5810b57cec5SDimitry Andric }
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType9(uint8_t Imm) {
5840b57cec5SDimitry Andric   uint64_t EncVal = Imm;
5850b57cec5SDimitry Andric   EncVal |= (EncVal << 8);
5860b57cec5SDimitry Andric   EncVal |= (EncVal << 16);
5870b57cec5SDimitry Andric   EncVal |= (EncVal << 32);
5880b57cec5SDimitry Andric   return EncVal;
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric // aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
5920b57cec5SDimitry Andric // cmode: 1110, op: 1
5930b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType10(uint64_t Imm) {
594*5f757f3fSDimitry Andric #if defined(_MSC_VER) && _MSC_VER == 1937 && !defined(__clang__) &&            \
595*5f757f3fSDimitry Andric     defined(_M_ARM64)
596*5f757f3fSDimitry Andric   // The MSVC compiler 19.37 for ARM64 has an optimization bug that
597*5f757f3fSDimitry Andric   // causes an incorrect behavior with the orignal version. Work around
598*5f757f3fSDimitry Andric   // by using a slightly different variation.
599*5f757f3fSDimitry Andric   // https://developercommunity.visualstudio.com/t/C-ARM64-compiler-optimization-bug/10481261
600*5f757f3fSDimitry Andric   constexpr uint64_t Mask = 0xFFULL;
601*5f757f3fSDimitry Andric   uint64_t ByteA = (Imm >> 56) & Mask;
602*5f757f3fSDimitry Andric   uint64_t ByteB = (Imm >> 48) & Mask;
603*5f757f3fSDimitry Andric   uint64_t ByteC = (Imm >> 40) & Mask;
604*5f757f3fSDimitry Andric   uint64_t ByteD = (Imm >> 32) & Mask;
605*5f757f3fSDimitry Andric   uint64_t ByteE = (Imm >> 24) & Mask;
606*5f757f3fSDimitry Andric   uint64_t ByteF = (Imm >> 16) & Mask;
607*5f757f3fSDimitry Andric   uint64_t ByteG = (Imm >> 8) & Mask;
608*5f757f3fSDimitry Andric   uint64_t ByteH = Imm & Mask;
609*5f757f3fSDimitry Andric 
610*5f757f3fSDimitry Andric   return (ByteA == 0ULL || ByteA == Mask) && (ByteB == 0ULL || ByteB == Mask) &&
611*5f757f3fSDimitry Andric          (ByteC == 0ULL || ByteC == Mask) && (ByteD == 0ULL || ByteD == Mask) &&
612*5f757f3fSDimitry Andric          (ByteE == 0ULL || ByteE == Mask) && (ByteF == 0ULL || ByteF == Mask) &&
613*5f757f3fSDimitry Andric          (ByteG == 0ULL || ByteG == Mask) && (ByteH == 0ULL || ByteH == Mask);
614*5f757f3fSDimitry Andric #else
6150b57cec5SDimitry Andric   uint64_t ByteA = Imm & 0xff00000000000000ULL;
6160b57cec5SDimitry Andric   uint64_t ByteB = Imm & 0x00ff000000000000ULL;
6170b57cec5SDimitry Andric   uint64_t ByteC = Imm & 0x0000ff0000000000ULL;
6180b57cec5SDimitry Andric   uint64_t ByteD = Imm & 0x000000ff00000000ULL;
6190b57cec5SDimitry Andric   uint64_t ByteE = Imm & 0x00000000ff000000ULL;
6200b57cec5SDimitry Andric   uint64_t ByteF = Imm & 0x0000000000ff0000ULL;
6210b57cec5SDimitry Andric   uint64_t ByteG = Imm & 0x000000000000ff00ULL;
6220b57cec5SDimitry Andric   uint64_t ByteH = Imm & 0x00000000000000ffULL;
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric   return (ByteA == 0ULL || ByteA == 0xff00000000000000ULL) &&
6250b57cec5SDimitry Andric          (ByteB == 0ULL || ByteB == 0x00ff000000000000ULL) &&
6260b57cec5SDimitry Andric          (ByteC == 0ULL || ByteC == 0x0000ff0000000000ULL) &&
6270b57cec5SDimitry Andric          (ByteD == 0ULL || ByteD == 0x000000ff00000000ULL) &&
6280b57cec5SDimitry Andric          (ByteE == 0ULL || ByteE == 0x00000000ff000000ULL) &&
6290b57cec5SDimitry Andric          (ByteF == 0ULL || ByteF == 0x0000000000ff0000ULL) &&
6300b57cec5SDimitry Andric          (ByteG == 0ULL || ByteG == 0x000000000000ff00ULL) &&
6310b57cec5SDimitry Andric          (ByteH == 0ULL || ByteH == 0x00000000000000ffULL);
632*5f757f3fSDimitry Andric #endif
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType10(uint64_t Imm) {
6360b57cec5SDimitry Andric   uint8_t BitA = (Imm & 0xff00000000000000ULL) != 0;
6370b57cec5SDimitry Andric   uint8_t BitB = (Imm & 0x00ff000000000000ULL) != 0;
6380b57cec5SDimitry Andric   uint8_t BitC = (Imm & 0x0000ff0000000000ULL) != 0;
6390b57cec5SDimitry Andric   uint8_t BitD = (Imm & 0x000000ff00000000ULL) != 0;
6400b57cec5SDimitry Andric   uint8_t BitE = (Imm & 0x00000000ff000000ULL) != 0;
6410b57cec5SDimitry Andric   uint8_t BitF = (Imm & 0x0000000000ff0000ULL) != 0;
6420b57cec5SDimitry Andric   uint8_t BitG = (Imm & 0x000000000000ff00ULL) != 0;
6430b57cec5SDimitry Andric   uint8_t BitH = (Imm & 0x00000000000000ffULL) != 0;
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   uint8_t EncVal = BitA;
6460b57cec5SDimitry Andric   EncVal <<= 1;
6470b57cec5SDimitry Andric   EncVal |= BitB;
6480b57cec5SDimitry Andric   EncVal <<= 1;
6490b57cec5SDimitry Andric   EncVal |= BitC;
6500b57cec5SDimitry Andric   EncVal <<= 1;
6510b57cec5SDimitry Andric   EncVal |= BitD;
6520b57cec5SDimitry Andric   EncVal <<= 1;
6530b57cec5SDimitry Andric   EncVal |= BitE;
6540b57cec5SDimitry Andric   EncVal <<= 1;
6550b57cec5SDimitry Andric   EncVal |= BitF;
6560b57cec5SDimitry Andric   EncVal <<= 1;
6570b57cec5SDimitry Andric   EncVal |= BitG;
6580b57cec5SDimitry Andric   EncVal <<= 1;
6590b57cec5SDimitry Andric   EncVal |= BitH;
6600b57cec5SDimitry Andric   return EncVal;
6610b57cec5SDimitry Andric }
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType10(uint8_t Imm) {
6640b57cec5SDimitry Andric   uint64_t EncVal = 0;
6650b57cec5SDimitry Andric   if (Imm & 0x80) EncVal |= 0xff00000000000000ULL;
6660b57cec5SDimitry Andric   if (Imm & 0x40) EncVal |= 0x00ff000000000000ULL;
6670b57cec5SDimitry Andric   if (Imm & 0x20) EncVal |= 0x0000ff0000000000ULL;
6680b57cec5SDimitry Andric   if (Imm & 0x10) EncVal |= 0x000000ff00000000ULL;
6690b57cec5SDimitry Andric   if (Imm & 0x08) EncVal |= 0x00000000ff000000ULL;
6700b57cec5SDimitry Andric   if (Imm & 0x04) EncVal |= 0x0000000000ff0000ULL;
6710b57cec5SDimitry Andric   if (Imm & 0x02) EncVal |= 0x000000000000ff00ULL;
6720b57cec5SDimitry Andric   if (Imm & 0x01) EncVal |= 0x00000000000000ffULL;
6730b57cec5SDimitry Andric   return EncVal;
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric // aBbbbbbc defgh000 0x00 0x00 aBbbbbbc defgh000 0x00 0x00
6770b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType11(uint64_t Imm) {
6780b57cec5SDimitry Andric   uint64_t BString = (Imm & 0x7E000000ULL) >> 25;
6790b57cec5SDimitry Andric   return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
6800b57cec5SDimitry Andric          (BString == 0x1f || BString == 0x20) &&
6810b57cec5SDimitry Andric          ((Imm & 0x0007ffff0007ffffULL) == 0);
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType11(uint64_t Imm) {
6850b57cec5SDimitry Andric   uint8_t BitA = (Imm & 0x80000000ULL) != 0;
6860b57cec5SDimitry Andric   uint8_t BitB = (Imm & 0x20000000ULL) != 0;
6870b57cec5SDimitry Andric   uint8_t BitC = (Imm & 0x01000000ULL) != 0;
6880b57cec5SDimitry Andric   uint8_t BitD = (Imm & 0x00800000ULL) != 0;
6890b57cec5SDimitry Andric   uint8_t BitE = (Imm & 0x00400000ULL) != 0;
6900b57cec5SDimitry Andric   uint8_t BitF = (Imm & 0x00200000ULL) != 0;
6910b57cec5SDimitry Andric   uint8_t BitG = (Imm & 0x00100000ULL) != 0;
6920b57cec5SDimitry Andric   uint8_t BitH = (Imm & 0x00080000ULL) != 0;
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric   uint8_t EncVal = BitA;
6950b57cec5SDimitry Andric   EncVal <<= 1;
6960b57cec5SDimitry Andric   EncVal |= BitB;
6970b57cec5SDimitry Andric   EncVal <<= 1;
6980b57cec5SDimitry Andric   EncVal |= BitC;
6990b57cec5SDimitry Andric   EncVal <<= 1;
7000b57cec5SDimitry Andric   EncVal |= BitD;
7010b57cec5SDimitry Andric   EncVal <<= 1;
7020b57cec5SDimitry Andric   EncVal |= BitE;
7030b57cec5SDimitry Andric   EncVal <<= 1;
7040b57cec5SDimitry Andric   EncVal |= BitF;
7050b57cec5SDimitry Andric   EncVal <<= 1;
7060b57cec5SDimitry Andric   EncVal |= BitG;
7070b57cec5SDimitry Andric   EncVal <<= 1;
7080b57cec5SDimitry Andric   EncVal |= BitH;
7090b57cec5SDimitry Andric   return EncVal;
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType11(uint8_t Imm) {
7130b57cec5SDimitry Andric   uint64_t EncVal = 0;
7140b57cec5SDimitry Andric   if (Imm & 0x80) EncVal |= 0x80000000ULL;
7150b57cec5SDimitry Andric   if (Imm & 0x40) EncVal |= 0x3e000000ULL;
7160b57cec5SDimitry Andric   else            EncVal |= 0x40000000ULL;
7170b57cec5SDimitry Andric   if (Imm & 0x20) EncVal |= 0x01000000ULL;
7180b57cec5SDimitry Andric   if (Imm & 0x10) EncVal |= 0x00800000ULL;
7190b57cec5SDimitry Andric   if (Imm & 0x08) EncVal |= 0x00400000ULL;
7200b57cec5SDimitry Andric   if (Imm & 0x04) EncVal |= 0x00200000ULL;
7210b57cec5SDimitry Andric   if (Imm & 0x02) EncVal |= 0x00100000ULL;
7220b57cec5SDimitry Andric   if (Imm & 0x01) EncVal |= 0x00080000ULL;
7230b57cec5SDimitry Andric   return (EncVal << 32) | EncVal;
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric // aBbbbbbb bbcdefgh 0x00 0x00 0x00 0x00 0x00 0x00
7270b57cec5SDimitry Andric static inline bool isAdvSIMDModImmType12(uint64_t Imm) {
7280b57cec5SDimitry Andric   uint64_t BString = (Imm & 0x7fc0000000000000ULL) >> 54;
7290b57cec5SDimitry Andric   return ((BString == 0xff || BString == 0x100) &&
7300b57cec5SDimitry Andric          ((Imm & 0x0000ffffffffffffULL) == 0));
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric static inline uint8_t encodeAdvSIMDModImmType12(uint64_t Imm) {
7340b57cec5SDimitry Andric   uint8_t BitA = (Imm & 0x8000000000000000ULL) != 0;
7350b57cec5SDimitry Andric   uint8_t BitB = (Imm & 0x0040000000000000ULL) != 0;
7360b57cec5SDimitry Andric   uint8_t BitC = (Imm & 0x0020000000000000ULL) != 0;
7370b57cec5SDimitry Andric   uint8_t BitD = (Imm & 0x0010000000000000ULL) != 0;
7380b57cec5SDimitry Andric   uint8_t BitE = (Imm & 0x0008000000000000ULL) != 0;
7390b57cec5SDimitry Andric   uint8_t BitF = (Imm & 0x0004000000000000ULL) != 0;
7400b57cec5SDimitry Andric   uint8_t BitG = (Imm & 0x0002000000000000ULL) != 0;
7410b57cec5SDimitry Andric   uint8_t BitH = (Imm & 0x0001000000000000ULL) != 0;
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric   uint8_t EncVal = BitA;
7440b57cec5SDimitry Andric   EncVal <<= 1;
7450b57cec5SDimitry Andric   EncVal |= BitB;
7460b57cec5SDimitry Andric   EncVal <<= 1;
7470b57cec5SDimitry Andric   EncVal |= BitC;
7480b57cec5SDimitry Andric   EncVal <<= 1;
7490b57cec5SDimitry Andric   EncVal |= BitD;
7500b57cec5SDimitry Andric   EncVal <<= 1;
7510b57cec5SDimitry Andric   EncVal |= BitE;
7520b57cec5SDimitry Andric   EncVal <<= 1;
7530b57cec5SDimitry Andric   EncVal |= BitF;
7540b57cec5SDimitry Andric   EncVal <<= 1;
7550b57cec5SDimitry Andric   EncVal |= BitG;
7560b57cec5SDimitry Andric   EncVal <<= 1;
7570b57cec5SDimitry Andric   EncVal |= BitH;
7580b57cec5SDimitry Andric   return EncVal;
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric static inline uint64_t decodeAdvSIMDModImmType12(uint8_t Imm) {
7620b57cec5SDimitry Andric   uint64_t EncVal = 0;
7630b57cec5SDimitry Andric   if (Imm & 0x80) EncVal |= 0x8000000000000000ULL;
7640b57cec5SDimitry Andric   if (Imm & 0x40) EncVal |= 0x3fc0000000000000ULL;
7650b57cec5SDimitry Andric   else            EncVal |= 0x4000000000000000ULL;
7660b57cec5SDimitry Andric   if (Imm & 0x20) EncVal |= 0x0020000000000000ULL;
7670b57cec5SDimitry Andric   if (Imm & 0x10) EncVal |= 0x0010000000000000ULL;
7680b57cec5SDimitry Andric   if (Imm & 0x08) EncVal |= 0x0008000000000000ULL;
7690b57cec5SDimitry Andric   if (Imm & 0x04) EncVal |= 0x0004000000000000ULL;
7700b57cec5SDimitry Andric   if (Imm & 0x02) EncVal |= 0x0002000000000000ULL;
7710b57cec5SDimitry Andric   if (Imm & 0x01) EncVal |= 0x0001000000000000ULL;
7720b57cec5SDimitry Andric   return (EncVal << 32) | EncVal;
7730b57cec5SDimitry Andric }
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric /// Returns true if Imm is the concatenation of a repeating pattern of type T.
7760b57cec5SDimitry Andric template <typename T>
7770b57cec5SDimitry Andric static inline bool isSVEMaskOfIdenticalElements(int64_t Imm) {
7780b57cec5SDimitry Andric   auto Parts = bit_cast<std::array<T, sizeof(int64_t) / sizeof(T)>>(Imm);
779bdd1243dSDimitry Andric   return llvm::all_equal(Parts);
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric /// Returns true if Imm is valid for CPY/DUP.
7830b57cec5SDimitry Andric template <typename T>
7840b57cec5SDimitry Andric static inline bool isSVECpyImm(int64_t Imm) {
785fe6060f1SDimitry Andric   // Imm is interpreted as a signed value, which means top bits must be all ones
786fe6060f1SDimitry Andric   // (sign bits if the immediate value is negative and passed in a larger
787fe6060f1SDimitry Andric   // container), or all zeroes.
788fe6060f1SDimitry Andric   int64_t Mask = ~int64_t(std::numeric_limits<std::make_unsigned_t<T>>::max());
789fe6060f1SDimitry Andric   if ((Imm & Mask) != 0 && (Imm & Mask) != Mask)
790fe6060f1SDimitry Andric     return false;
7910b57cec5SDimitry Andric 
792fe6060f1SDimitry Andric   // Imm is a signed 8-bit value.
793fe6060f1SDimitry Andric   // Top bits must be zeroes or sign bits.
794fe6060f1SDimitry Andric   if (Imm & 0xff)
795fe6060f1SDimitry Andric     return int8_t(Imm) == T(Imm);
7960b57cec5SDimitry Andric 
797fe6060f1SDimitry Andric   // Imm is a signed 16-bit value and multiple of 256.
798fe6060f1SDimitry Andric   // Top bits must be zeroes or sign bits.
799fe6060f1SDimitry Andric   if (Imm & 0xff00)
800fe6060f1SDimitry Andric     return int16_t(Imm) == T(Imm);
8010b57cec5SDimitry Andric 
802fe6060f1SDimitry Andric   return Imm == 0;
8030b57cec5SDimitry Andric }
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric /// Returns true if Imm is valid for ADD/SUB.
8060b57cec5SDimitry Andric template <typename T>
8070b57cec5SDimitry Andric static inline bool isSVEAddSubImm(int64_t Imm) {
808e8d8bef9SDimitry Andric   bool IsInt8t = std::is_same<int8_t, std::make_signed_t<T>>::value ||
809e8d8bef9SDimitry Andric                  std::is_same<int8_t, T>::value;
8100b57cec5SDimitry Andric   return uint8_t(Imm) == Imm || (!IsInt8t && uint16_t(Imm & ~0xff) == Imm);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric /// Return true if Imm is valid for DUPM and has no single CPY/DUP equivalent.
8140b57cec5SDimitry Andric static inline bool isSVEMoveMaskPreferredLogicalImmediate(int64_t Imm) {
8150b57cec5SDimitry Andric   if (isSVECpyImm<int64_t>(Imm))
8160b57cec5SDimitry Andric     return false;
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric   auto S = bit_cast<std::array<int32_t, 2>>(Imm);
8190b57cec5SDimitry Andric   auto H = bit_cast<std::array<int16_t, 4>>(Imm);
8200b57cec5SDimitry Andric   auto B = bit_cast<std::array<int8_t, 8>>(Imm);
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   if (isSVEMaskOfIdenticalElements<int32_t>(Imm) && isSVECpyImm<int32_t>(S[0]))
8230b57cec5SDimitry Andric     return false;
8240b57cec5SDimitry Andric   if (isSVEMaskOfIdenticalElements<int16_t>(Imm) && isSVECpyImm<int16_t>(H[0]))
8250b57cec5SDimitry Andric     return false;
8260b57cec5SDimitry Andric   if (isSVEMaskOfIdenticalElements<int8_t>(Imm) && isSVECpyImm<int8_t>(B[0]))
8270b57cec5SDimitry Andric     return false;
8280b57cec5SDimitry Andric   return isLogicalImmediate(Imm, 64);
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric inline static bool isAnyMOVZMovAlias(uint64_t Value, int RegWidth) {
8320b57cec5SDimitry Andric   for (int Shift = 0; Shift <= RegWidth - 16; Shift += 16)
8330b57cec5SDimitry Andric     if ((Value & ~(0xffffULL << Shift)) == 0)
8340b57cec5SDimitry Andric       return true;
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   return false;
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric inline static bool isMOVZMovAlias(uint64_t Value, int Shift, int RegWidth) {
8400b57cec5SDimitry Andric   if (RegWidth == 32)
8410b57cec5SDimitry Andric     Value &= 0xffffffffULL;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   // "lsl #0" takes precedence: in practice this only affects "#0, lsl #0".
8440b57cec5SDimitry Andric   if (Value == 0 && Shift != 0)
8450b57cec5SDimitry Andric     return false;
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric   return (Value & ~(0xffffULL << Shift)) == 0;
8480b57cec5SDimitry Andric }
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric inline static bool isMOVNMovAlias(uint64_t Value, int Shift, int RegWidth) {
8510b57cec5SDimitry Andric   // MOVZ takes precedence over MOVN.
8520b57cec5SDimitry Andric   if (isAnyMOVZMovAlias(Value, RegWidth))
8530b57cec5SDimitry Andric     return false;
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   Value = ~Value;
8560b57cec5SDimitry Andric   if (RegWidth == 32)
8570b57cec5SDimitry Andric     Value &= 0xffffffffULL;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   return isMOVZMovAlias(Value, Shift, RegWidth);
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric inline static bool isAnyMOVWMovAlias(uint64_t Value, int RegWidth) {
8630b57cec5SDimitry Andric   if (isAnyMOVZMovAlias(Value, RegWidth))
8640b57cec5SDimitry Andric     return true;
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric   // It's not a MOVZ, but it might be a MOVN.
8670b57cec5SDimitry Andric   Value = ~Value;
8680b57cec5SDimitry Andric   if (RegWidth == 32)
8690b57cec5SDimitry Andric     Value &= 0xffffffffULL;
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric   return isAnyMOVZMovAlias(Value, RegWidth);
8720b57cec5SDimitry Andric }
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric } // end namespace AArch64_AM
8750b57cec5SDimitry Andric 
8760b57cec5SDimitry Andric } // end namespace llvm
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric #endif
879