1274955Ssvnmir//===- AArch64AddressingModes.h - AArch64 Addressing Modes ------*- C++ -*-===// 2274955Ssvnmir// 3274955Ssvnmir// The LLVM Compiler Infrastructure 4274955Ssvnmir// 5274955Ssvnmir// This file is distributed under the University of Illinois Open Source 6274955Ssvnmir// License. See LICENSE.TXT for details. 7274955Ssvnmir// 8274955Ssvnmir//===----------------------------------------------------------------------===// 9274955Ssvnmir// 10274955Ssvnmir// This file contains the AArch64 addressing mode implementation stuff. 11274955Ssvnmir// 12274955Ssvnmir//===----------------------------------------------------------------------===// 13274955Ssvnmir 14280031Sdim#ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H 15280031Sdim#define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H 16274955Ssvnmir 17274955Ssvnmir#include "llvm/ADT/APFloat.h" 18274955Ssvnmir#include "llvm/ADT/APInt.h" 19274955Ssvnmir#include "llvm/Support/ErrorHandling.h" 20274955Ssvnmir#include "llvm/Support/MathExtras.h" 21274955Ssvnmir#include <cassert> 22274955Ssvnmir 23274955Ssvnmirnamespace llvm { 24274955Ssvnmir 25274955Ssvnmir/// AArch64_AM - AArch64 Addressing Mode Stuff 26274955Ssvnmirnamespace AArch64_AM { 27274955Ssvnmir 28274955Ssvnmir//===----------------------------------------------------------------------===// 29274955Ssvnmir// Shifts 30274955Ssvnmir// 31274955Ssvnmir 32274955Ssvnmirenum ShiftExtendType { 33274955Ssvnmir InvalidShiftExtend = -1, 34274955Ssvnmir LSL = 0, 35274955Ssvnmir LSR, 36274955Ssvnmir ASR, 37274955Ssvnmir ROR, 38274955Ssvnmir MSL, 39274955Ssvnmir 40274955Ssvnmir UXTB, 41274955Ssvnmir UXTH, 42274955Ssvnmir UXTW, 43274955Ssvnmir UXTX, 44274955Ssvnmir 45274955Ssvnmir SXTB, 46274955Ssvnmir SXTH, 47274955Ssvnmir SXTW, 48274955Ssvnmir SXTX, 49274955Ssvnmir}; 50274955Ssvnmir 51274955Ssvnmir/// getShiftName - Get the string encoding for the shift type. 52274955Ssvnmirstatic inline const char *getShiftExtendName(AArch64_AM::ShiftExtendType ST) { 53274955Ssvnmir switch (ST) { 54280031Sdim default: llvm_unreachable("unhandled shift type!"); 55274955Ssvnmir case AArch64_AM::LSL: return "lsl"; 56274955Ssvnmir case AArch64_AM::LSR: return "lsr"; 57274955Ssvnmir case AArch64_AM::ASR: return "asr"; 58274955Ssvnmir case AArch64_AM::ROR: return "ror"; 59274955Ssvnmir case AArch64_AM::MSL: return "msl"; 60274955Ssvnmir case AArch64_AM::UXTB: return "uxtb"; 61274955Ssvnmir case AArch64_AM::UXTH: return "uxth"; 62274955Ssvnmir case AArch64_AM::UXTW: return "uxtw"; 63274955Ssvnmir case AArch64_AM::UXTX: return "uxtx"; 64274955Ssvnmir case AArch64_AM::SXTB: return "sxtb"; 65274955Ssvnmir case AArch64_AM::SXTH: return "sxth"; 66274955Ssvnmir case AArch64_AM::SXTW: return "sxtw"; 67274955Ssvnmir case AArch64_AM::SXTX: return "sxtx"; 68274955Ssvnmir } 69274955Ssvnmir return nullptr; 70274955Ssvnmir} 71274955Ssvnmir 72274955Ssvnmir/// getShiftType - Extract the shift type. 73274955Ssvnmirstatic inline AArch64_AM::ShiftExtendType getShiftType(unsigned Imm) { 74274955Ssvnmir switch ((Imm >> 6) & 0x7) { 75274955Ssvnmir default: return AArch64_AM::InvalidShiftExtend; 76274955Ssvnmir case 0: return AArch64_AM::LSL; 77274955Ssvnmir case 1: return AArch64_AM::LSR; 78274955Ssvnmir case 2: return AArch64_AM::ASR; 79274955Ssvnmir case 3: return AArch64_AM::ROR; 80274955Ssvnmir case 4: return AArch64_AM::MSL; 81274955Ssvnmir } 82274955Ssvnmir} 83274955Ssvnmir 84274955Ssvnmir/// getShiftValue - Extract the shift value. 85274955Ssvnmirstatic inline unsigned getShiftValue(unsigned Imm) { 86274955Ssvnmir return Imm & 0x3f; 87274955Ssvnmir} 88274955Ssvnmir 89274955Ssvnmir/// getShifterImm - Encode the shift type and amount: 90274955Ssvnmir/// imm: 6-bit shift amount 91274955Ssvnmir/// shifter: 000 ==> lsl 92274955Ssvnmir/// 001 ==> lsr 93274955Ssvnmir/// 010 ==> asr 94274955Ssvnmir/// 011 ==> ror 95274955Ssvnmir/// 100 ==> msl 96274955Ssvnmir/// {8-6} = shifter 97274955Ssvnmir/// {5-0} = imm 98274955Ssvnmirstatic inline unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, 99274955Ssvnmir unsigned Imm) { 100274955Ssvnmir assert((Imm & 0x3f) == Imm && "Illegal shifted immedate value!"); 101274955Ssvnmir unsigned STEnc = 0; 102274955Ssvnmir switch (ST) { 103274955Ssvnmir default: llvm_unreachable("Invalid shift requested"); 104274955Ssvnmir case AArch64_AM::LSL: STEnc = 0; break; 105274955Ssvnmir case AArch64_AM::LSR: STEnc = 1; break; 106274955Ssvnmir case AArch64_AM::ASR: STEnc = 2; break; 107274955Ssvnmir case AArch64_AM::ROR: STEnc = 3; break; 108274955Ssvnmir case AArch64_AM::MSL: STEnc = 4; break; 109274955Ssvnmir } 110274955Ssvnmir return (STEnc << 6) | (Imm & 0x3f); 111274955Ssvnmir} 112274955Ssvnmir 113274955Ssvnmir//===----------------------------------------------------------------------===// 114274955Ssvnmir// Extends 115274955Ssvnmir// 116274955Ssvnmir 117274955Ssvnmir/// getArithShiftValue - get the arithmetic shift value. 118274955Ssvnmirstatic inline unsigned getArithShiftValue(unsigned Imm) { 119274955Ssvnmir return Imm & 0x7; 120274955Ssvnmir} 121274955Ssvnmir 122274955Ssvnmir/// getExtendType - Extract the extend type for operands of arithmetic ops. 123274955Ssvnmirstatic inline AArch64_AM::ShiftExtendType getExtendType(unsigned Imm) { 124274955Ssvnmir assert((Imm & 0x7) == Imm && "invalid immediate!"); 125274955Ssvnmir switch (Imm) { 126274955Ssvnmir default: llvm_unreachable("Compiler bug!"); 127274955Ssvnmir case 0: return AArch64_AM::UXTB; 128274955Ssvnmir case 1: return AArch64_AM::UXTH; 129274955Ssvnmir case 2: return AArch64_AM::UXTW; 130274955Ssvnmir case 3: return AArch64_AM::UXTX; 131274955Ssvnmir case 4: return AArch64_AM::SXTB; 132274955Ssvnmir case 5: return AArch64_AM::SXTH; 133274955Ssvnmir case 6: return AArch64_AM::SXTW; 134274955Ssvnmir case 7: return AArch64_AM::SXTX; 135274955Ssvnmir } 136274955Ssvnmir} 137274955Ssvnmir 138274955Ssvnmirstatic inline AArch64_AM::ShiftExtendType getArithExtendType(unsigned Imm) { 139274955Ssvnmir return getExtendType((Imm >> 3) & 0x7); 140274955Ssvnmir} 141274955Ssvnmir 142274955Ssvnmir/// Mapping from extend bits to required operation: 143274955Ssvnmir/// shifter: 000 ==> uxtb 144274955Ssvnmir/// 001 ==> uxth 145274955Ssvnmir/// 010 ==> uxtw 146274955Ssvnmir/// 011 ==> uxtx 147274955Ssvnmir/// 100 ==> sxtb 148274955Ssvnmir/// 101 ==> sxth 149274955Ssvnmir/// 110 ==> sxtw 150274955Ssvnmir/// 111 ==> sxtx 151274955Ssvnmirinline unsigned getExtendEncoding(AArch64_AM::ShiftExtendType ET) { 152274955Ssvnmir switch (ET) { 153274955Ssvnmir default: llvm_unreachable("Invalid extend type requested"); 154274955Ssvnmir case AArch64_AM::UXTB: return 0; break; 155274955Ssvnmir case AArch64_AM::UXTH: return 1; break; 156274955Ssvnmir case AArch64_AM::UXTW: return 2; break; 157274955Ssvnmir case AArch64_AM::UXTX: return 3; break; 158274955Ssvnmir case AArch64_AM::SXTB: return 4; break; 159274955Ssvnmir case AArch64_AM::SXTH: return 5; break; 160274955Ssvnmir case AArch64_AM::SXTW: return 6; break; 161274955Ssvnmir case AArch64_AM::SXTX: return 7; break; 162274955Ssvnmir } 163274955Ssvnmir} 164274955Ssvnmir 165274955Ssvnmir/// getArithExtendImm - Encode the extend type and shift amount for an 166274955Ssvnmir/// arithmetic instruction: 167274955Ssvnmir/// imm: 3-bit extend amount 168274955Ssvnmir/// {5-3} = shifter 169274955Ssvnmir/// {2-0} = imm3 170274955Ssvnmirstatic inline unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, 171274955Ssvnmir unsigned Imm) { 172274955Ssvnmir assert((Imm & 0x7) == Imm && "Illegal shifted immedate value!"); 173274955Ssvnmir return (getExtendEncoding(ET) << 3) | (Imm & 0x7); 174274955Ssvnmir} 175274955Ssvnmir 176274955Ssvnmir/// getMemDoShift - Extract the "do shift" flag value for load/store 177274955Ssvnmir/// instructions. 178274955Ssvnmirstatic inline bool getMemDoShift(unsigned Imm) { 179274955Ssvnmir return (Imm & 0x1) != 0; 180274955Ssvnmir} 181274955Ssvnmir 182274955Ssvnmir/// getExtendType - Extract the extend type for the offset operand of 183274955Ssvnmir/// loads/stores. 184274955Ssvnmirstatic inline AArch64_AM::ShiftExtendType getMemExtendType(unsigned Imm) { 185274955Ssvnmir return getExtendType((Imm >> 1) & 0x7); 186274955Ssvnmir} 187274955Ssvnmir 188274955Ssvnmir/// getExtendImm - Encode the extend type and amount for a load/store inst: 189274955Ssvnmir/// doshift: should the offset be scaled by the access size 190274955Ssvnmir/// shifter: 000 ==> uxtb 191274955Ssvnmir/// 001 ==> uxth 192274955Ssvnmir/// 010 ==> uxtw 193274955Ssvnmir/// 011 ==> uxtx 194274955Ssvnmir/// 100 ==> sxtb 195274955Ssvnmir/// 101 ==> sxth 196274955Ssvnmir/// 110 ==> sxtw 197274955Ssvnmir/// 111 ==> sxtx 198274955Ssvnmir/// {3-1} = shifter 199274955Ssvnmir/// {0} = doshift 200274955Ssvnmirstatic inline unsigned getMemExtendImm(AArch64_AM::ShiftExtendType ET, 201274955Ssvnmir bool DoShift) { 202274955Ssvnmir return (getExtendEncoding(ET) << 1) | unsigned(DoShift); 203274955Ssvnmir} 204274955Ssvnmir 205274955Ssvnmirstatic inline uint64_t ror(uint64_t elt, unsigned size) { 206274955Ssvnmir return ((elt & 1) << (size-1)) | (elt >> 1); 207274955Ssvnmir} 208274955Ssvnmir 209274955Ssvnmir/// processLogicalImmediate - Determine if an immediate value can be encoded 210274955Ssvnmir/// as the immediate operand of a logical instruction for the given register 211274955Ssvnmir/// size. If so, return true with "encoding" set to the encoded value in 212274955Ssvnmir/// the form N:immr:imms. 213280031Sdimstatic inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, 214280031Sdim uint64_t &Encoding) { 215280031Sdim if (Imm == 0ULL || Imm == ~0ULL || 216280031Sdim (RegSize != 64 && (Imm >> RegSize != 0 || Imm == ~0U))) 217274955Ssvnmir return false; 218274955Ssvnmir 219274955Ssvnmir // First, determine the element size. 220280031Sdim unsigned Size = RegSize; 221274955Ssvnmir 222280031Sdim do { 223280031Sdim Size /= 2; 224280031Sdim uint64_t Mask = (1ULL << Size) - 1; 225274955Ssvnmir 226280031Sdim if ((Imm & Mask) != ((Imm >> Size) & Mask)) { 227280031Sdim Size *= 2; 228274955Ssvnmir break; 229274955Ssvnmir } 230280031Sdim } while (Size > 2); 231274955Ssvnmir 232274955Ssvnmir // Second, determine the rotation to make the element be: 0^m 1^n. 233280031Sdim uint32_t CTO, I; 234280031Sdim uint64_t Mask = ((uint64_t)-1LL) >> (64 - Size); 235280031Sdim Imm &= Mask; 236274955Ssvnmir 237280031Sdim if (isShiftedMask_64(Imm)) { 238280031Sdim I = countTrailingZeros(Imm); 239280031Sdim assert(I < 64 && "undefined behavior"); 240288943Sdim CTO = countTrailingOnes(Imm >> I); 241280031Sdim } else { 242280031Sdim Imm |= ~Mask; 243280031Sdim if (!isShiftedMask_64(~Imm)) 244280031Sdim return false; 245274955Ssvnmir 246288943Sdim unsigned CLO = countLeadingOnes(Imm); 247280031Sdim I = 64 - CLO; 248288943Sdim CTO = CLO + countTrailingOnes(Imm) - (64 - Size); 249280031Sdim } 250274955Ssvnmir 251280031Sdim // Encode in Immr the number of RORs it would take to get *from* 0^m 1^n 252280031Sdim // to our target value, where I is the number of RORs to go the opposite 253280031Sdim // direction. 254280031Sdim assert(Size > I && "I should be smaller than element size"); 255280031Sdim unsigned Immr = (Size - I) & (Size - 1); 256274955Ssvnmir 257280031Sdim // If size has a 1 in the n'th bit, create a value that has zeroes in 258280031Sdim // bits [0, n] and ones above that. 259280031Sdim uint64_t NImms = ~(Size-1) << 1; 260274955Ssvnmir 261280031Sdim // Or the CTO value into the low bits, which must be below the Nth bit 262280031Sdim // bit mentioned above. 263280031Sdim NImms |= (CTO-1); 264274955Ssvnmir 265280031Sdim // Extract the seventh bit and toggle it to create the N field. 266280031Sdim unsigned N = ((NImms >> 6) & 1) ^ 1; 267280031Sdim 268280031Sdim Encoding = (N << 12) | (Immr << 6) | (NImms & 0x3f); 269280031Sdim return true; 270274955Ssvnmir} 271274955Ssvnmir 272274955Ssvnmir/// isLogicalImmediate - Return true if the immediate is valid for a logical 273274955Ssvnmir/// immediate instruction of the given register size. Return false otherwise. 274274955Ssvnmirstatic inline bool isLogicalImmediate(uint64_t imm, unsigned regSize) { 275274955Ssvnmir uint64_t encoding; 276274955Ssvnmir return processLogicalImmediate(imm, regSize, encoding); 277274955Ssvnmir} 278274955Ssvnmir 279274955Ssvnmir/// encodeLogicalImmediate - Return the encoded immediate value for a logical 280274955Ssvnmir/// immediate instruction of the given register size. 281274955Ssvnmirstatic inline uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize) { 282274955Ssvnmir uint64_t encoding = 0; 283274955Ssvnmir bool res = processLogicalImmediate(imm, regSize, encoding); 284274955Ssvnmir assert(res && "invalid logical immediate"); 285274955Ssvnmir (void)res; 286274955Ssvnmir return encoding; 287274955Ssvnmir} 288274955Ssvnmir 289274955Ssvnmir/// decodeLogicalImmediate - Decode a logical immediate value in the form 290274955Ssvnmir/// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the 291274955Ssvnmir/// integer value it represents with regSize bits. 292274955Ssvnmirstatic inline uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize) { 293274955Ssvnmir // Extract the N, imms, and immr fields. 294274955Ssvnmir unsigned N = (val >> 12) & 1; 295274955Ssvnmir unsigned immr = (val >> 6) & 0x3f; 296274955Ssvnmir unsigned imms = val & 0x3f; 297274955Ssvnmir 298274955Ssvnmir assert((regSize == 64 || N == 0) && "undefined logical immediate encoding"); 299274955Ssvnmir int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); 300274955Ssvnmir assert(len >= 0 && "undefined logical immediate encoding"); 301274955Ssvnmir unsigned size = (1 << len); 302274955Ssvnmir unsigned R = immr & (size - 1); 303274955Ssvnmir unsigned S = imms & (size - 1); 304274955Ssvnmir assert(S != size - 1 && "undefined logical immediate encoding"); 305274955Ssvnmir uint64_t pattern = (1ULL << (S + 1)) - 1; 306274955Ssvnmir for (unsigned i = 0; i < R; ++i) 307274955Ssvnmir pattern = ror(pattern, size); 308274955Ssvnmir 309274955Ssvnmir // Replicate the pattern to fill the regSize. 310274955Ssvnmir while (size != regSize) { 311274955Ssvnmir pattern |= (pattern << size); 312274955Ssvnmir size *= 2; 313274955Ssvnmir } 314274955Ssvnmir return pattern; 315274955Ssvnmir} 316274955Ssvnmir 317274955Ssvnmir/// isValidDecodeLogicalImmediate - Check to see if the logical immediate value 318274955Ssvnmir/// in the form "N:immr:imms" (where the immr and imms fields are each 6 bits) 319274955Ssvnmir/// is a valid encoding for an integer value with regSize bits. 320274955Ssvnmirstatic inline bool isValidDecodeLogicalImmediate(uint64_t val, 321274955Ssvnmir unsigned regSize) { 322274955Ssvnmir // Extract the N and imms fields needed for checking. 323274955Ssvnmir unsigned N = (val >> 12) & 1; 324274955Ssvnmir unsigned imms = val & 0x3f; 325274955Ssvnmir 326274955Ssvnmir if (regSize == 32 && N != 0) // undefined logical immediate encoding 327274955Ssvnmir return false; 328274955Ssvnmir int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); 329274955Ssvnmir if (len < 0) // undefined logical immediate encoding 330274955Ssvnmir return false; 331274955Ssvnmir unsigned size = (1 << len); 332274955Ssvnmir unsigned S = imms & (size - 1); 333274955Ssvnmir if (S == size - 1) // undefined logical immediate encoding 334274955Ssvnmir return false; 335274955Ssvnmir 336274955Ssvnmir return true; 337274955Ssvnmir} 338274955Ssvnmir 339274955Ssvnmir//===----------------------------------------------------------------------===// 340274955Ssvnmir// Floating-point Immediates 341274955Ssvnmir// 342274955Ssvnmirstatic inline float getFPImmFloat(unsigned Imm) { 343274955Ssvnmir // We expect an 8-bit binary encoding of a floating-point number here. 344274955Ssvnmir union { 345274955Ssvnmir uint32_t I; 346274955Ssvnmir float F; 347274955Ssvnmir } FPUnion; 348274955Ssvnmir 349274955Ssvnmir uint8_t Sign = (Imm >> 7) & 0x1; 350274955Ssvnmir uint8_t Exp = (Imm >> 4) & 0x7; 351274955Ssvnmir uint8_t Mantissa = Imm & 0xf; 352274955Ssvnmir 353274955Ssvnmir // 8-bit FP iEEEE Float Encoding 354274955Ssvnmir // abcd efgh aBbbbbbc defgh000 00000000 00000000 355274955Ssvnmir // 356274955Ssvnmir // where B = NOT(b); 357274955Ssvnmir 358274955Ssvnmir FPUnion.I = 0; 359274955Ssvnmir FPUnion.I |= Sign << 31; 360274955Ssvnmir FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; 361274955Ssvnmir FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; 362274955Ssvnmir FPUnion.I |= (Exp & 0x3) << 23; 363274955Ssvnmir FPUnion.I |= Mantissa << 19; 364274955Ssvnmir return FPUnion.F; 365274955Ssvnmir} 366274955Ssvnmir 367296417Sdim/// getFP16Imm - Return an 8-bit floating-point version of the 16-bit 368296417Sdim/// floating-point value. If the value cannot be represented as an 8-bit 369296417Sdim/// floating-point value, then return -1. 370296417Sdimstatic inline int getFP16Imm(const APInt &Imm) { 371296417Sdim uint32_t Sign = Imm.lshr(15).getZExtValue() & 1; 372296417Sdim int32_t Exp = (Imm.lshr(10).getSExtValue() & 0x1f) - 15; // -14 to 15 373296417Sdim int32_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits 374296417Sdim 375296417Sdim // We can handle 4 bits of mantissa. 376296417Sdim // mantissa = (16+UInt(e:f:g:h))/16. 377296417Sdim if (Mantissa & 0x3f) 378296417Sdim return -1; 379296417Sdim Mantissa >>= 6; 380296417Sdim 381296417Sdim // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 382296417Sdim if (Exp < -3 || Exp > 4) 383296417Sdim return -1; 384296417Sdim Exp = ((Exp+3) & 0x7) ^ 4; 385296417Sdim 386296417Sdim return ((int)Sign << 7) | (Exp << 4) | Mantissa; 387296417Sdim} 388296417Sdim 389296417Sdimstatic inline int getFP16Imm(const APFloat &FPImm) { 390296417Sdim return getFP16Imm(FPImm.bitcastToAPInt()); 391296417Sdim} 392296417Sdim 393274955Ssvnmir/// getFP32Imm - Return an 8-bit floating-point version of the 32-bit 394274955Ssvnmir/// floating-point value. If the value cannot be represented as an 8-bit 395274955Ssvnmir/// floating-point value, then return -1. 396274955Ssvnmirstatic inline int getFP32Imm(const APInt &Imm) { 397274955Ssvnmir uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; 398274955Ssvnmir int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 399274955Ssvnmir int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits 400274955Ssvnmir 401274955Ssvnmir // We can handle 4 bits of mantissa. 402274955Ssvnmir // mantissa = (16+UInt(e:f:g:h))/16. 403274955Ssvnmir if (Mantissa & 0x7ffff) 404274955Ssvnmir return -1; 405274955Ssvnmir Mantissa >>= 19; 406274955Ssvnmir if ((Mantissa & 0xf) != Mantissa) 407274955Ssvnmir return -1; 408274955Ssvnmir 409274955Ssvnmir // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 410274955Ssvnmir if (Exp < -3 || Exp > 4) 411274955Ssvnmir return -1; 412274955Ssvnmir Exp = ((Exp+3) & 0x7) ^ 4; 413274955Ssvnmir 414274955Ssvnmir return ((int)Sign << 7) | (Exp << 4) | Mantissa; 415274955Ssvnmir} 416274955Ssvnmir 417274955Ssvnmirstatic inline int getFP32Imm(const APFloat &FPImm) { 418274955Ssvnmir return getFP32Imm(FPImm.bitcastToAPInt()); 419274955Ssvnmir} 420274955Ssvnmir 421274955Ssvnmir/// getFP64Imm - Return an 8-bit floating-point version of the 64-bit 422274955Ssvnmir/// floating-point value. If the value cannot be represented as an 8-bit 423274955Ssvnmir/// floating-point value, then return -1. 424274955Ssvnmirstatic inline int getFP64Imm(const APInt &Imm) { 425274955Ssvnmir uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; 426274955Ssvnmir int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 427274955Ssvnmir uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; 428274955Ssvnmir 429274955Ssvnmir // We can handle 4 bits of mantissa. 430274955Ssvnmir // mantissa = (16+UInt(e:f:g:h))/16. 431274955Ssvnmir if (Mantissa & 0xffffffffffffULL) 432274955Ssvnmir return -1; 433274955Ssvnmir Mantissa >>= 48; 434274955Ssvnmir if ((Mantissa & 0xf) != Mantissa) 435274955Ssvnmir return -1; 436274955Ssvnmir 437274955Ssvnmir // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 438274955Ssvnmir if (Exp < -3 || Exp > 4) 439274955Ssvnmir return -1; 440274955Ssvnmir Exp = ((Exp+3) & 0x7) ^ 4; 441274955Ssvnmir 442274955Ssvnmir return ((int)Sign << 7) | (Exp << 4) | Mantissa; 443274955Ssvnmir} 444274955Ssvnmir 445274955Ssvnmirstatic inline int getFP64Imm(const APFloat &FPImm) { 446274955Ssvnmir return getFP64Imm(FPImm.bitcastToAPInt()); 447274955Ssvnmir} 448274955Ssvnmir 449274955Ssvnmir//===--------------------------------------------------------------------===// 450274955Ssvnmir// AdvSIMD Modified Immediates 451274955Ssvnmir//===--------------------------------------------------------------------===// 452274955Ssvnmir 453274955Ssvnmir// 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 454274955Ssvnmirstatic inline bool isAdvSIMDModImmType1(uint64_t Imm) { 455274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 456274955Ssvnmir ((Imm & 0xffffff00ffffff00ULL) == 0); 457274955Ssvnmir} 458274955Ssvnmir 459274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType1(uint64_t Imm) { 460274955Ssvnmir return (Imm & 0xffULL); 461274955Ssvnmir} 462274955Ssvnmir 463274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType1(uint8_t Imm) { 464274955Ssvnmir uint64_t EncVal = Imm; 465274955Ssvnmir return (EncVal << 32) | EncVal; 466274955Ssvnmir} 467274955Ssvnmir 468274955Ssvnmir// 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 469274955Ssvnmirstatic inline bool isAdvSIMDModImmType2(uint64_t Imm) { 470274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 471274955Ssvnmir ((Imm & 0xffff00ffffff00ffULL) == 0); 472274955Ssvnmir} 473274955Ssvnmir 474274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType2(uint64_t Imm) { 475274955Ssvnmir return (Imm & 0xff00ULL) >> 8; 476274955Ssvnmir} 477274955Ssvnmir 478274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType2(uint8_t Imm) { 479274955Ssvnmir uint64_t EncVal = Imm; 480274955Ssvnmir return (EncVal << 40) | (EncVal << 8); 481274955Ssvnmir} 482274955Ssvnmir 483274955Ssvnmir// 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 484274955Ssvnmirstatic inline bool isAdvSIMDModImmType3(uint64_t Imm) { 485274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 486274955Ssvnmir ((Imm & 0xff00ffffff00ffffULL) == 0); 487274955Ssvnmir} 488274955Ssvnmir 489274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType3(uint64_t Imm) { 490274955Ssvnmir return (Imm & 0xff0000ULL) >> 16; 491274955Ssvnmir} 492274955Ssvnmir 493274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType3(uint8_t Imm) { 494274955Ssvnmir uint64_t EncVal = Imm; 495274955Ssvnmir return (EncVal << 48) | (EncVal << 16); 496274955Ssvnmir} 497274955Ssvnmir 498274955Ssvnmir// abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 499274955Ssvnmirstatic inline bool isAdvSIMDModImmType4(uint64_t Imm) { 500274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 501274955Ssvnmir ((Imm & 0x00ffffff00ffffffULL) == 0); 502274955Ssvnmir} 503274955Ssvnmir 504274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType4(uint64_t Imm) { 505274955Ssvnmir return (Imm & 0xff000000ULL) >> 24; 506274955Ssvnmir} 507274955Ssvnmir 508274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType4(uint8_t Imm) { 509274955Ssvnmir uint64_t EncVal = Imm; 510274955Ssvnmir return (EncVal << 56) | (EncVal << 24); 511274955Ssvnmir} 512274955Ssvnmir 513274955Ssvnmir// 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 514274955Ssvnmirstatic inline bool isAdvSIMDModImmType5(uint64_t Imm) { 515274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 516274955Ssvnmir (((Imm & 0x00ff0000ULL) >> 16) == (Imm & 0x000000ffULL)) && 517274955Ssvnmir ((Imm & 0xff00ff00ff00ff00ULL) == 0); 518274955Ssvnmir} 519274955Ssvnmir 520274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType5(uint64_t Imm) { 521274955Ssvnmir return (Imm & 0xffULL); 522274955Ssvnmir} 523274955Ssvnmir 524274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType5(uint8_t Imm) { 525274955Ssvnmir uint64_t EncVal = Imm; 526274955Ssvnmir return (EncVal << 48) | (EncVal << 32) | (EncVal << 16) | EncVal; 527274955Ssvnmir} 528274955Ssvnmir 529274955Ssvnmir// abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 530274955Ssvnmirstatic inline bool isAdvSIMDModImmType6(uint64_t Imm) { 531274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 532274955Ssvnmir (((Imm & 0xff000000ULL) >> 16) == (Imm & 0x0000ff00ULL)) && 533274955Ssvnmir ((Imm & 0x00ff00ff00ff00ffULL) == 0); 534274955Ssvnmir} 535274955Ssvnmir 536274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType6(uint64_t Imm) { 537274955Ssvnmir return (Imm & 0xff00ULL) >> 8; 538274955Ssvnmir} 539274955Ssvnmir 540274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType6(uint8_t Imm) { 541274955Ssvnmir uint64_t EncVal = Imm; 542274955Ssvnmir return (EncVal << 56) | (EncVal << 40) | (EncVal << 24) | (EncVal << 8); 543274955Ssvnmir} 544274955Ssvnmir 545274955Ssvnmir// 0x00 0x00 abcdefgh 0xFF 0x00 0x00 abcdefgh 0xFF 546274955Ssvnmirstatic inline bool isAdvSIMDModImmType7(uint64_t Imm) { 547274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 548274955Ssvnmir ((Imm & 0xffff00ffffff00ffULL) == 0x000000ff000000ffULL); 549274955Ssvnmir} 550274955Ssvnmir 551274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType7(uint64_t Imm) { 552274955Ssvnmir return (Imm & 0xff00ULL) >> 8; 553274955Ssvnmir} 554274955Ssvnmir 555274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType7(uint8_t Imm) { 556274955Ssvnmir uint64_t EncVal = Imm; 557274955Ssvnmir return (EncVal << 40) | (EncVal << 8) | 0x000000ff000000ffULL; 558274955Ssvnmir} 559274955Ssvnmir 560274955Ssvnmir// 0x00 abcdefgh 0xFF 0xFF 0x00 abcdefgh 0xFF 0xFF 561274955Ssvnmirstatic inline bool isAdvSIMDModImmType8(uint64_t Imm) { 562274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 563274955Ssvnmir ((Imm & 0xff00ffffff00ffffULL) == 0x0000ffff0000ffffULL); 564274955Ssvnmir} 565274955Ssvnmir 566274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType8(uint8_t Imm) { 567274955Ssvnmir uint64_t EncVal = Imm; 568274955Ssvnmir return (EncVal << 48) | (EncVal << 16) | 0x0000ffff0000ffffULL; 569274955Ssvnmir} 570274955Ssvnmir 571274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType8(uint64_t Imm) { 572274955Ssvnmir return (Imm & 0x00ff0000ULL) >> 16; 573274955Ssvnmir} 574274955Ssvnmir 575274955Ssvnmir// abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh 576274955Ssvnmirstatic inline bool isAdvSIMDModImmType9(uint64_t Imm) { 577274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 578274955Ssvnmir ((Imm >> 48) == (Imm & 0x0000ffffULL)) && 579274955Ssvnmir ((Imm >> 56) == (Imm & 0x000000ffULL)); 580274955Ssvnmir} 581274955Ssvnmir 582274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType9(uint64_t Imm) { 583274955Ssvnmir return (Imm & 0xffULL); 584274955Ssvnmir} 585274955Ssvnmir 586274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType9(uint8_t Imm) { 587274955Ssvnmir uint64_t EncVal = Imm; 588274955Ssvnmir EncVal |= (EncVal << 8); 589274955Ssvnmir EncVal |= (EncVal << 16); 590274955Ssvnmir EncVal |= (EncVal << 32); 591274955Ssvnmir return EncVal; 592274955Ssvnmir} 593274955Ssvnmir 594274955Ssvnmir// aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh 595274955Ssvnmir// cmode: 1110, op: 1 596274955Ssvnmirstatic inline bool isAdvSIMDModImmType10(uint64_t Imm) { 597274955Ssvnmir uint64_t ByteA = Imm & 0xff00000000000000ULL; 598274955Ssvnmir uint64_t ByteB = Imm & 0x00ff000000000000ULL; 599274955Ssvnmir uint64_t ByteC = Imm & 0x0000ff0000000000ULL; 600274955Ssvnmir uint64_t ByteD = Imm & 0x000000ff00000000ULL; 601274955Ssvnmir uint64_t ByteE = Imm & 0x00000000ff000000ULL; 602274955Ssvnmir uint64_t ByteF = Imm & 0x0000000000ff0000ULL; 603274955Ssvnmir uint64_t ByteG = Imm & 0x000000000000ff00ULL; 604274955Ssvnmir uint64_t ByteH = Imm & 0x00000000000000ffULL; 605274955Ssvnmir 606274955Ssvnmir return (ByteA == 0ULL || ByteA == 0xff00000000000000ULL) && 607274955Ssvnmir (ByteB == 0ULL || ByteB == 0x00ff000000000000ULL) && 608274955Ssvnmir (ByteC == 0ULL || ByteC == 0x0000ff0000000000ULL) && 609274955Ssvnmir (ByteD == 0ULL || ByteD == 0x000000ff00000000ULL) && 610274955Ssvnmir (ByteE == 0ULL || ByteE == 0x00000000ff000000ULL) && 611274955Ssvnmir (ByteF == 0ULL || ByteF == 0x0000000000ff0000ULL) && 612274955Ssvnmir (ByteG == 0ULL || ByteG == 0x000000000000ff00ULL) && 613274955Ssvnmir (ByteH == 0ULL || ByteH == 0x00000000000000ffULL); 614274955Ssvnmir} 615274955Ssvnmir 616274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType10(uint64_t Imm) { 617274955Ssvnmir uint8_t BitA = (Imm & 0xff00000000000000ULL) != 0; 618274955Ssvnmir uint8_t BitB = (Imm & 0x00ff000000000000ULL) != 0; 619274955Ssvnmir uint8_t BitC = (Imm & 0x0000ff0000000000ULL) != 0; 620274955Ssvnmir uint8_t BitD = (Imm & 0x000000ff00000000ULL) != 0; 621274955Ssvnmir uint8_t BitE = (Imm & 0x00000000ff000000ULL) != 0; 622274955Ssvnmir uint8_t BitF = (Imm & 0x0000000000ff0000ULL) != 0; 623274955Ssvnmir uint8_t BitG = (Imm & 0x000000000000ff00ULL) != 0; 624274955Ssvnmir uint8_t BitH = (Imm & 0x00000000000000ffULL) != 0; 625274955Ssvnmir 626274955Ssvnmir uint8_t EncVal = BitA; 627274955Ssvnmir EncVal <<= 1; 628274955Ssvnmir EncVal |= BitB; 629274955Ssvnmir EncVal <<= 1; 630274955Ssvnmir EncVal |= BitC; 631274955Ssvnmir EncVal <<= 1; 632274955Ssvnmir EncVal |= BitD; 633274955Ssvnmir EncVal <<= 1; 634274955Ssvnmir EncVal |= BitE; 635274955Ssvnmir EncVal <<= 1; 636274955Ssvnmir EncVal |= BitF; 637274955Ssvnmir EncVal <<= 1; 638274955Ssvnmir EncVal |= BitG; 639274955Ssvnmir EncVal <<= 1; 640274955Ssvnmir EncVal |= BitH; 641274955Ssvnmir return EncVal; 642274955Ssvnmir} 643274955Ssvnmir 644274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType10(uint8_t Imm) { 645274955Ssvnmir uint64_t EncVal = 0; 646274955Ssvnmir if (Imm & 0x80) EncVal |= 0xff00000000000000ULL; 647274955Ssvnmir if (Imm & 0x40) EncVal |= 0x00ff000000000000ULL; 648274955Ssvnmir if (Imm & 0x20) EncVal |= 0x0000ff0000000000ULL; 649274955Ssvnmir if (Imm & 0x10) EncVal |= 0x000000ff00000000ULL; 650274955Ssvnmir if (Imm & 0x08) EncVal |= 0x00000000ff000000ULL; 651274955Ssvnmir if (Imm & 0x04) EncVal |= 0x0000000000ff0000ULL; 652274955Ssvnmir if (Imm & 0x02) EncVal |= 0x000000000000ff00ULL; 653274955Ssvnmir if (Imm & 0x01) EncVal |= 0x00000000000000ffULL; 654274955Ssvnmir return EncVal; 655274955Ssvnmir} 656274955Ssvnmir 657274955Ssvnmir// aBbbbbbc defgh000 0x00 0x00 aBbbbbbc defgh000 0x00 0x00 658274955Ssvnmirstatic inline bool isAdvSIMDModImmType11(uint64_t Imm) { 659274955Ssvnmir uint64_t BString = (Imm & 0x7E000000ULL) >> 25; 660274955Ssvnmir return ((Imm >> 32) == (Imm & 0xffffffffULL)) && 661274955Ssvnmir (BString == 0x1f || BString == 0x20) && 662274955Ssvnmir ((Imm & 0x0007ffff0007ffffULL) == 0); 663274955Ssvnmir} 664274955Ssvnmir 665274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType11(uint64_t Imm) { 666274955Ssvnmir uint8_t BitA = (Imm & 0x80000000ULL) != 0; 667274955Ssvnmir uint8_t BitB = (Imm & 0x20000000ULL) != 0; 668274955Ssvnmir uint8_t BitC = (Imm & 0x01000000ULL) != 0; 669274955Ssvnmir uint8_t BitD = (Imm & 0x00800000ULL) != 0; 670274955Ssvnmir uint8_t BitE = (Imm & 0x00400000ULL) != 0; 671274955Ssvnmir uint8_t BitF = (Imm & 0x00200000ULL) != 0; 672274955Ssvnmir uint8_t BitG = (Imm & 0x00100000ULL) != 0; 673274955Ssvnmir uint8_t BitH = (Imm & 0x00080000ULL) != 0; 674274955Ssvnmir 675274955Ssvnmir uint8_t EncVal = BitA; 676274955Ssvnmir EncVal <<= 1; 677274955Ssvnmir EncVal |= BitB; 678274955Ssvnmir EncVal <<= 1; 679274955Ssvnmir EncVal |= BitC; 680274955Ssvnmir EncVal <<= 1; 681274955Ssvnmir EncVal |= BitD; 682274955Ssvnmir EncVal <<= 1; 683274955Ssvnmir EncVal |= BitE; 684274955Ssvnmir EncVal <<= 1; 685274955Ssvnmir EncVal |= BitF; 686274955Ssvnmir EncVal <<= 1; 687274955Ssvnmir EncVal |= BitG; 688274955Ssvnmir EncVal <<= 1; 689274955Ssvnmir EncVal |= BitH; 690274955Ssvnmir return EncVal; 691274955Ssvnmir} 692274955Ssvnmir 693274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType11(uint8_t Imm) { 694274955Ssvnmir uint64_t EncVal = 0; 695274955Ssvnmir if (Imm & 0x80) EncVal |= 0x80000000ULL; 696274955Ssvnmir if (Imm & 0x40) EncVal |= 0x3e000000ULL; 697274955Ssvnmir else EncVal |= 0x40000000ULL; 698274955Ssvnmir if (Imm & 0x20) EncVal |= 0x01000000ULL; 699274955Ssvnmir if (Imm & 0x10) EncVal |= 0x00800000ULL; 700274955Ssvnmir if (Imm & 0x08) EncVal |= 0x00400000ULL; 701274955Ssvnmir if (Imm & 0x04) EncVal |= 0x00200000ULL; 702274955Ssvnmir if (Imm & 0x02) EncVal |= 0x00100000ULL; 703274955Ssvnmir if (Imm & 0x01) EncVal |= 0x00080000ULL; 704274955Ssvnmir return (EncVal << 32) | EncVal; 705274955Ssvnmir} 706274955Ssvnmir 707274955Ssvnmir// aBbbbbbb bbcdefgh 0x00 0x00 0x00 0x00 0x00 0x00 708274955Ssvnmirstatic inline bool isAdvSIMDModImmType12(uint64_t Imm) { 709274955Ssvnmir uint64_t BString = (Imm & 0x7fc0000000000000ULL) >> 54; 710274955Ssvnmir return ((BString == 0xff || BString == 0x100) && 711274955Ssvnmir ((Imm & 0x0000ffffffffffffULL) == 0)); 712274955Ssvnmir} 713274955Ssvnmir 714274955Ssvnmirstatic inline uint8_t encodeAdvSIMDModImmType12(uint64_t Imm) { 715274955Ssvnmir uint8_t BitA = (Imm & 0x8000000000000000ULL) != 0; 716274955Ssvnmir uint8_t BitB = (Imm & 0x0040000000000000ULL) != 0; 717274955Ssvnmir uint8_t BitC = (Imm & 0x0020000000000000ULL) != 0; 718274955Ssvnmir uint8_t BitD = (Imm & 0x0010000000000000ULL) != 0; 719274955Ssvnmir uint8_t BitE = (Imm & 0x0008000000000000ULL) != 0; 720274955Ssvnmir uint8_t BitF = (Imm & 0x0004000000000000ULL) != 0; 721274955Ssvnmir uint8_t BitG = (Imm & 0x0002000000000000ULL) != 0; 722274955Ssvnmir uint8_t BitH = (Imm & 0x0001000000000000ULL) != 0; 723274955Ssvnmir 724274955Ssvnmir uint8_t EncVal = BitA; 725274955Ssvnmir EncVal <<= 1; 726274955Ssvnmir EncVal |= BitB; 727274955Ssvnmir EncVal <<= 1; 728274955Ssvnmir EncVal |= BitC; 729274955Ssvnmir EncVal <<= 1; 730274955Ssvnmir EncVal |= BitD; 731274955Ssvnmir EncVal <<= 1; 732274955Ssvnmir EncVal |= BitE; 733274955Ssvnmir EncVal <<= 1; 734274955Ssvnmir EncVal |= BitF; 735274955Ssvnmir EncVal <<= 1; 736274955Ssvnmir EncVal |= BitG; 737274955Ssvnmir EncVal <<= 1; 738274955Ssvnmir EncVal |= BitH; 739274955Ssvnmir return EncVal; 740274955Ssvnmir} 741274955Ssvnmir 742274955Ssvnmirstatic inline uint64_t decodeAdvSIMDModImmType12(uint8_t Imm) { 743274955Ssvnmir uint64_t EncVal = 0; 744274955Ssvnmir if (Imm & 0x80) EncVal |= 0x8000000000000000ULL; 745274955Ssvnmir if (Imm & 0x40) EncVal |= 0x3fc0000000000000ULL; 746274955Ssvnmir else EncVal |= 0x4000000000000000ULL; 747274955Ssvnmir if (Imm & 0x20) EncVal |= 0x0020000000000000ULL; 748274955Ssvnmir if (Imm & 0x10) EncVal |= 0x0010000000000000ULL; 749274955Ssvnmir if (Imm & 0x08) EncVal |= 0x0008000000000000ULL; 750274955Ssvnmir if (Imm & 0x04) EncVal |= 0x0004000000000000ULL; 751274955Ssvnmir if (Imm & 0x02) EncVal |= 0x0002000000000000ULL; 752274955Ssvnmir if (Imm & 0x01) EncVal |= 0x0001000000000000ULL; 753274955Ssvnmir return (EncVal << 32) | EncVal; 754274955Ssvnmir} 755274955Ssvnmir 756274955Ssvnmir} // end namespace AArch64_AM 757274955Ssvnmir 758274955Ssvnmir} // end namespace llvm 759274955Ssvnmir 760274955Ssvnmir#endif 761