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