Instructions-vixl.h (44188B)
1 // Copyright 2015, VIXL authors 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #ifndef VIXL_A64_INSTRUCTIONS_A64_H_ 28 #define VIXL_A64_INSTRUCTIONS_A64_H_ 29 30 #include "jit/arm64/vixl/Constants-vixl.h" 31 #include "jit/arm64/vixl/Globals-vixl.h" 32 #include "jit/arm64/vixl/Utils-vixl.h" 33 34 namespace vixl { 35 // ISA constants. -------------------------------------------------------------- 36 37 typedef uint32_t Instr; 38 const unsigned kInstructionSize = 4; 39 const unsigned kInstructionSizeLog2 = 2; 40 const unsigned kLiteralEntrySize = 4; 41 const unsigned kLiteralEntrySizeLog2 = 2; 42 const unsigned kMaxLoadLiteralRange = 1 * MBytes; 43 44 // This is the nominal page size (as used by the adrp instruction); the actual 45 // size of the memory pages allocated by the kernel is likely to differ. 46 const unsigned kPageSize = 4 * KBytes; 47 const unsigned kPageSizeLog2 = 12; 48 49 const unsigned kBRegSize = 8; 50 const unsigned kBRegSizeLog2 = 3; 51 const unsigned kBRegSizeInBytes = kBRegSize / 8; 52 const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3; 53 const unsigned kHRegSize = 16; 54 const unsigned kHRegSizeLog2 = 4; 55 const unsigned kHRegSizeInBytes = kHRegSize / 8; 56 const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3; 57 const unsigned kWRegSize = 32; 58 const unsigned kWRegSizeLog2 = 5; 59 const unsigned kWRegSizeInBytes = kWRegSize / 8; 60 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; 61 const unsigned kXRegSize = 64; 62 const unsigned kXRegSizeLog2 = 6; 63 const unsigned kXRegSizeInBytes = kXRegSize / 8; 64 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; 65 const unsigned kSRegSize = 32; 66 const unsigned kSRegSizeLog2 = 5; 67 const unsigned kSRegSizeInBytes = kSRegSize / 8; 68 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; 69 const unsigned kDRegSize = 64; 70 const unsigned kDRegSizeLog2 = 6; 71 const unsigned kDRegSizeInBytes = kDRegSize / 8; 72 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; 73 const unsigned kQRegSize = 128; 74 const unsigned kQRegSizeLog2 = 7; 75 const unsigned kQRegSizeInBytes = kQRegSize / 8; 76 const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3; 77 const uint64_t kWRegMask = UINT64_C(0xffffffff); 78 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); 79 const uint64_t kHRegMask = UINT64_C(0xffff); 80 const uint64_t kSRegMask = UINT64_C(0xffffffff); 81 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); 82 const uint64_t kHSignMask = UINT64_C(0x8000); 83 const uint64_t kSSignMask = UINT64_C(0x80000000); 84 const uint64_t kDSignMask = UINT64_C(0x8000000000000000); 85 const uint64_t kWSignMask = UINT64_C(0x80000000); 86 const uint64_t kXSignMask = UINT64_C(0x8000000000000000); 87 const uint64_t kByteMask = UINT64_C(0xff); 88 const uint64_t kHalfWordMask = UINT64_C(0xffff); 89 const uint64_t kWordMask = UINT64_C(0xffffffff); 90 const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); 91 const uint64_t kXMaxExactUInt = UINT64_C(0xfffffffffffff800); 92 const uint64_t kWMaxUInt = UINT64_C(0xffffffff); 93 const uint64_t kHMaxUInt = UINT64_C(0xffff); 94 // Define k*MinInt with "-k*MaxInt - 1", because the hexadecimal representation 95 // (e.g. "INT32_C(0x80000000)") has implementation-defined behaviour. 96 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); 97 const int64_t kXMaxExactInt = UINT64_C(0x7ffffffffffffc00); 98 const int64_t kXMinInt = -kXMaxInt - 1; 99 const int32_t kWMaxInt = INT32_C(0x7fffffff); 100 const int32_t kWMinInt = -kWMaxInt - 1; 101 const int16_t kHMaxInt = INT16_C(0x7fff); 102 const int16_t kHMinInt = -kHMaxInt - 1; 103 const unsigned kFpRegCode = 29; 104 const unsigned kLinkRegCode = 30; 105 const unsigned kSpRegCode = 31; 106 const unsigned kZeroRegCode = 31; 107 const unsigned kSPRegInternalCode = 63; 108 const unsigned kRegCodeMask = 0x1f; 109 110 const unsigned kAtomicAccessGranule = 16; 111 112 const unsigned kAddressTagOffset = 56; 113 const unsigned kAddressTagWidth = 8; 114 const uint64_t kAddressTagMask = ((UINT64_C(1) << kAddressTagWidth) - 1) 115 << kAddressTagOffset; 116 VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); 117 118 const uint64_t kTTBRMask = UINT64_C(1) << 55; 119 120 // We can't define a static kZRegSize because the size depends on the 121 // implementation. However, it is sometimes useful to know the minimum and 122 // maximum possible sizes. 123 const unsigned kZRegMinSize = 128; 124 const unsigned kZRegMinSizeLog2 = 7; 125 const unsigned kZRegMinSizeInBytes = kZRegMinSize / 8; 126 const unsigned kZRegMinSizeInBytesLog2 = kZRegMinSizeLog2 - 3; 127 const unsigned kZRegMaxSize = 2048; 128 const unsigned kZRegMaxSizeLog2 = 11; 129 const unsigned kZRegMaxSizeInBytes = kZRegMaxSize / 8; 130 const unsigned kZRegMaxSizeInBytesLog2 = kZRegMaxSizeLog2 - 3; 131 132 // The P register size depends on the Z register size. 133 const unsigned kZRegBitsPerPRegBit = kBitsPerByte; 134 const unsigned kZRegBitsPerPRegBitLog2 = 3; 135 const unsigned kPRegMinSize = kZRegMinSize / kZRegBitsPerPRegBit; 136 const unsigned kPRegMinSizeLog2 = kZRegMinSizeLog2 - 3; 137 const unsigned kPRegMinSizeInBytes = kPRegMinSize / 8; 138 const unsigned kPRegMinSizeInBytesLog2 = kPRegMinSizeLog2 - 3; 139 const unsigned kPRegMaxSize = kZRegMaxSize / kZRegBitsPerPRegBit; 140 const unsigned kPRegMaxSizeLog2 = kZRegMaxSizeLog2 - 3; 141 const unsigned kPRegMaxSizeInBytes = kPRegMaxSize / 8; 142 const unsigned kPRegMaxSizeInBytesLog2 = kPRegMaxSizeLog2 - 3; 143 144 const unsigned kMTETagGranuleInBytes = 16; 145 const unsigned kMTETagGranuleInBytesLog2 = 4; 146 const unsigned kMTETagWidth = 4; 147 148 // Make these moved float constants backwards compatible 149 // with explicit vixl::aarch64:: namespace references. 150 using vixl::kDoubleExponentBits; 151 using vixl::kDoubleMantissaBits; 152 using vixl::kFloat16ExponentBits; 153 using vixl::kFloat16MantissaBits; 154 using vixl::kFloatExponentBits; 155 using vixl::kFloatMantissaBits; 156 157 using vixl::kFP16NegativeInfinity; 158 using vixl::kFP16PositiveInfinity; 159 using vixl::kFP32NegativeInfinity; 160 using vixl::kFP32PositiveInfinity; 161 using vixl::kFP64NegativeInfinity; 162 using vixl::kFP64PositiveInfinity; 163 164 using vixl::kFP16DefaultNaN; 165 using vixl::kFP32DefaultNaN; 166 using vixl::kFP64DefaultNaN; 167 168 // Mozilla change: Inline CalcLSDataSize into header. 169 static inline unsigned CalcLSDataSize(LoadStoreOp op) { 170 VIXL_ASSERT((LSSize_offset + LSSize_width) == (kInstructionSize * 8)); 171 unsigned size = static_cast<Instr>(op) >> LSSize_offset; 172 if ((op & LSVector_mask) != 0) { 173 // Vector register memory operations encode the access size in the "size" 174 // and "opc" fields. 175 if ((size == 0) && ((op & LSOpc_mask) >> LSOpc_offset) >= 2) { 176 size = kQRegSizeInBytesLog2; 177 } 178 } 179 return size; 180 } 181 unsigned CalcLSPairDataSize(LoadStorePairOp op); 182 183 enum ImmBranchType { 184 UnknownBranchType = 0, 185 CondBranchType = 1, 186 UncondBranchType = 2, 187 CompareBranchType = 3, 188 TestBranchType = 4 189 }; 190 191 // Mozilla change: 192 // 193 // The classes of immediate branch ranges, in order of increasing range. 194 // Note that CondBranchType and CompareBranchType have the same range. 195 enum ImmBranchRangeType { 196 TestBranchRangeType, // tbz/tbnz: imm14 = +/- 32KB. 197 CondBranchRangeType, // b.cond/cbz/cbnz: imm19 = +/- 1MB. 198 UncondBranchRangeType, // b/bl: imm26 = +/- 128MB. 199 UnknownBranchRangeType, 200 201 // Number of 'short-range' branch range types. 202 // We don't consider unconditional branches 'short-range'. 203 NumShortBranchRangeTypes = UncondBranchRangeType 204 }; 205 206 enum AddrMode { Offset, PreIndex, PostIndex }; 207 208 enum Reg31Mode { Reg31IsStackPointer, Reg31IsZeroRegister }; 209 210 enum VectorFormat { 211 kFormatUndefined = 0xffffffff, 212 kFormat8B = NEON_8B, 213 kFormat16B = NEON_16B, 214 kFormat4H = NEON_4H, 215 kFormat8H = NEON_8H, 216 kFormat2S = NEON_2S, 217 kFormat4S = NEON_4S, 218 kFormat1D = NEON_1D, 219 kFormat2D = NEON_2D, 220 221 // Scalar formats. We add the scalar bit to distinguish between scalar and 222 // vector enumerations; the bit is always set in the encoding of scalar ops 223 // and always clear for vector ops. Although kFormatD and kFormat1D appear 224 // to be the same, their meaning is subtly different. The first is a scalar 225 // operation, the second a vector operation that only affects one lane. 226 kFormatB = NEON_B | NEONScalar, 227 kFormatH = NEON_H | NEONScalar, 228 kFormatS = NEON_S | NEONScalar, 229 kFormatD = NEON_D | NEONScalar, 230 231 // An artificial value, used to distinguish from NEON format category. 232 kFormatSVE = 0x0000fffd, 233 // Artificial values. Q and O lane sizes aren't encoded in the usual size 234 // field. 235 kFormatSVEQ = 0x00080000, 236 kFormatSVEO = 0x00040000, 237 238 // Vector element width of SVE register with the unknown lane count since 239 // the vector length is implementation dependent. 240 kFormatVnB = SVE_B | kFormatSVE, 241 kFormatVnH = SVE_H | kFormatSVE, 242 kFormatVnS = SVE_S | kFormatSVE, 243 kFormatVnD = SVE_D | kFormatSVE, 244 kFormatVnQ = kFormatSVEQ | kFormatSVE, 245 kFormatVnO = kFormatSVEO | kFormatSVE, 246 247 // Artificial values, used by simulator trace tests and a few oddball 248 // instructions (such as FMLAL). 249 kFormat2H = 0xfffffffe, 250 kFormat1Q = 0xfffffffd 251 }; 252 253 // Instructions. --------------------------------------------------------------- 254 255 class Instruction { 256 public: 257 Instr GetInstructionBits() const { 258 return *(reinterpret_cast<const Instr*>(this)); 259 } 260 Instr InstructionBits() const { 261 return GetInstructionBits(); 262 } 263 264 void SetInstructionBits(Instr new_instr) { 265 *(reinterpret_cast<Instr*>(this)) = new_instr; 266 } 267 268 int ExtractBit(int pos) const { return (GetInstructionBits() >> pos) & 1; } 269 int Bit(int pos) const { 270 return ExtractBit(pos); 271 } 272 273 uint32_t ExtractBits(int msb, int lsb) const { 274 return ExtractUnsignedBitfield32(msb, lsb, GetInstructionBits()); 275 } 276 uint32_t Bits(int msb, int lsb) const { 277 return ExtractBits(msb, lsb); 278 } 279 280 // Compress bit extraction operation from Hacker's Delight. 281 // https://github.com/hcs0/Hackers-Delight/blob/master/compress.c.txt 282 uint32_t Compress(uint32_t mask) const { 283 uint32_t mk, mp, mv, t; 284 uint32_t x = GetInstructionBits() & mask; // Clear irrelevant bits. 285 mk = ~mask << 1; // We will count 0's to right. 286 for (int i = 0; i < 5; i++) { 287 mp = mk ^ (mk << 1); // Parallel suffix. 288 mp = mp ^ (mp << 2); 289 mp = mp ^ (mp << 4); 290 mp = mp ^ (mp << 8); 291 mp = mp ^ (mp << 16); 292 mv = mp & mask; // Bits to move. 293 mask = (mask ^ mv) | (mv >> (1 << i)); // Compress mask. 294 t = x & mv; 295 x = (x ^ t) | (t >> (1 << i)); // Compress x. 296 mk = mk & ~mp; 297 } 298 return x; 299 } 300 301 template <uint32_t M> 302 uint32_t ExtractBits() const { 303 return Compress(M); 304 } 305 306 uint32_t ExtractBitsAbsent() const { 307 VIXL_UNREACHABLE(); 308 return 0; 309 } 310 311 template <uint32_t M, uint32_t V> 312 uint32_t IsMaskedValue() const { 313 return (Mask(M) == V) ? 1 : 0; 314 } 315 316 uint32_t IsMaskedValueAbsent() const { 317 VIXL_UNREACHABLE(); 318 return 0; 319 } 320 321 int32_t ExtractSignedBits(int msb, int lsb) const { 322 int32_t bits = *(reinterpret_cast<const int32_t*>(this)); 323 return ExtractSignedBitfield32(msb, lsb, bits); 324 } 325 int32_t SignedBits(int msb, int lsb) const { 326 return ExtractSignedBits(msb, lsb); 327 } 328 329 Instr Mask(uint32_t mask) const { 330 VIXL_ASSERT(mask != 0); 331 return GetInstructionBits() & mask; 332 } 333 334 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ 335 int32_t Get##Name() const { return this->Func(HighBit, LowBit); } \ 336 int32_t Name() const { return Get##Name(); } 337 INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) 338 #undef DEFINE_GETTER 339 340 template <int msb, int lsb> 341 int32_t GetRx() const { 342 // We don't have any register fields wider than five bits, so the result 343 // will always fit into an int32_t. 344 VIXL_ASSERT((msb - lsb + 1) <= 5); 345 return this->ExtractBits(msb, lsb); 346 } 347 348 VectorFormat GetSVEVectorFormat(int field_lsb = 22) const { 349 VIXL_ASSERT((field_lsb >= 0) && (field_lsb <= 30)); 350 uint32_t instr = ExtractUnsignedBitfield32(field_lsb + 1, 351 field_lsb, 352 GetInstructionBits()) 353 << 22; 354 switch (instr & SVESizeFieldMask) { 355 case SVE_B: 356 return kFormatVnB; 357 case SVE_H: 358 return kFormatVnH; 359 case SVE_S: 360 return kFormatVnS; 361 case SVE_D: 362 return kFormatVnD; 363 } 364 VIXL_UNREACHABLE(); 365 return kFormatUndefined; 366 } 367 368 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), 369 // formed from ImmPCRelLo and ImmPCRelHi. 370 int GetImmPCRel() const { 371 uint32_t hi = static_cast<uint32_t>(GetImmPCRelHi()); 372 uint32_t lo = GetImmPCRelLo(); 373 uint32_t offset = (hi << ImmPCRelLo_width) | lo; 374 int width = ImmPCRelLo_width + ImmPCRelHi_width; 375 return ExtractSignedBitfield32(width - 1, 0, offset); 376 } 377 int ImmPCRel() const { return GetImmPCRel(); } 378 379 // ImmLSPAC is a compound field (not present in INSTRUCTION_FIELDS_LIST), 380 // formed from ImmLSPACLo and ImmLSPACHi. 381 int GetImmLSPAC() const { 382 uint32_t hi = static_cast<uint32_t>(GetImmLSPACHi()); 383 uint32_t lo = GetImmLSPACLo(); 384 uint32_t offset = (hi << ImmLSPACLo_width) | lo; 385 int width = ImmLSPACLo_width + ImmLSPACHi_width; 386 return ExtractSignedBitfield32(width - 1, 0, offset) << 3; 387 } 388 389 uint64_t GetImmLogical() const; 390 uint64_t ImmLogical() const { 391 return GetImmLogical(); 392 } 393 uint64_t GetSVEImmLogical() const; 394 int GetSVEBitwiseImmLaneSizeInBytesLog2() const; 395 uint64_t DecodeImmBitMask(int32_t n, 396 int32_t imm_s, 397 int32_t imm_r, 398 int32_t size) const; 399 400 std::pair<int, int> GetSVEPermuteIndexAndLaneSizeLog2() const; 401 402 std::pair<int, int> GetNEONMulRmAndIndex() const; 403 std::pair<int, int> GetSVEMulZmAndIndex() const; 404 std::pair<int, int> GetSVEMulLongZmAndIndex() const; 405 406 std::pair<int, int> GetSVEImmShiftAndLaneSizeLog2(bool is_predicated) const; 407 408 int GetSVEExtractImmediate() const; 409 410 int GetSVEMsizeFromDtype(bool is_signed, int dtype_h_lsb = 23) const; 411 412 int GetSVEEsizeFromDtype(bool is_signed, int dtype_l_lsb = 21) const; 413 414 415 unsigned GetImmNEONabcdefgh() const; 416 unsigned ImmNEONabcdefgh() const { 417 return GetImmNEONabcdefgh(); 418 } 419 420 Float16 GetImmFP16() const; 421 422 float GetImmFP32() const; 423 float ImmFP32() const { return GetImmFP32(); } 424 425 double GetImmFP64() const; 426 double ImmFP64() const { return GetImmFP64(); } 427 428 Float16 GetImmNEONFP16() const; 429 430 float GetImmNEONFP32() const; 431 float ImmNEONFP32() const { 432 return GetImmNEONFP32(); 433 } 434 435 double GetImmNEONFP64() const; 436 double ImmNEONFP64() const { 437 return GetImmNEONFP64(); 438 } 439 440 Float16 GetSVEImmFP16() const { return Imm8ToFloat16(ExtractBits(12, 5)); } 441 442 float GetSVEImmFP32() const { return Imm8ToFP32(ExtractBits(12, 5)); } 443 444 double GetSVEImmFP64() const { return Imm8ToFP64(ExtractBits(12, 5)); } 445 446 static Float16 Imm8ToFloat16(uint32_t imm8); 447 static float Imm8ToFP32(uint32_t imm8); 448 static double Imm8ToFP64(uint32_t imm8); 449 450 unsigned GetSizeLS() const { 451 return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask))); 452 } 453 unsigned SizeLS() const { return GetSizeLS(); } 454 455 unsigned GetSizeLSPair() const { 456 return CalcLSPairDataSize( 457 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); 458 } 459 unsigned SizeLSPair() const { 460 return GetSizeLSPair(); 461 } 462 463 int GetNEONLSIndex(int access_size_shift) const { 464 int64_t q = GetNEONQ(); 465 int64_t s = GetNEONS(); 466 int64_t size = GetNEONLSSize(); 467 int64_t index = (q << 3) | (s << 2) | size; 468 return static_cast<int>(index >> access_size_shift); 469 } 470 int NEONLSIndex(int access_size_shift) const { 471 return GetNEONLSIndex(access_size_shift); 472 } 473 474 // Helpers. 475 bool IsCondBranchImm() const { 476 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; 477 } 478 479 bool IsUncondBranchImm() const { 480 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; 481 } 482 483 bool IsCompareBranch() const { 484 return Mask(CompareBranchFMask) == CompareBranchFixed; 485 } 486 487 bool IsTestBranch() const { return Mask(TestBranchFMask) == TestBranchFixed; } 488 489 bool IsImmBranch() const { return GetBranchType() != UnknownBranchType; } 490 491 bool IsPCRelAddressing() const { 492 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; 493 } 494 495 bool IsLogicalImmediate() const { 496 return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; 497 } 498 499 bool IsAddSubImmediate() const { 500 return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; 501 } 502 503 bool IsAddSubExtended() const { 504 return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; 505 } 506 507 bool IsLoadOrStore() const { 508 return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; 509 } 510 511 // True if `this` is valid immediately after the provided movprfx instruction. 512 bool CanTakeSVEMovprfx(uint32_t form_hash, Instruction const* movprfx) const; 513 bool CanTakeSVEMovprfx(const char* form, Instruction const* movprfx) const; 514 515 bool IsLoad() const; 516 bool IsStore() const; 517 518 bool IsLoadLiteral() const { 519 // This includes PRFM_lit. 520 return Mask(LoadLiteralFMask) == LoadLiteralFixed; 521 } 522 523 bool IsMovn() const { 524 return (Mask(MoveWideImmediateMask) == MOVN_x) || 525 (Mask(MoveWideImmediateMask) == MOVN_w); 526 } 527 528 bool IsException() const { return Mask(ExceptionFMask) == ExceptionFixed; } 529 530 bool IsPAuth() const { return Mask(SystemPAuthFMask) == SystemPAuthFixed; } 531 532 bool IsBti() const { 533 if (Mask(SystemHintFMask) == SystemHintFixed) { 534 int imm_hint = GetImmHint(); 535 switch (imm_hint) { 536 case BTI: 537 case BTI_c: 538 case BTI_j: 539 case BTI_jc: 540 return true; 541 } 542 } 543 return false; 544 } 545 546 bool IsMOPSPrologueOf(const Instruction* instr, uint32_t mops_type) const { 547 VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) || 548 (mops_type == "cpy"_h)); 549 const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14; 550 return GetInstructionBits() == instr->Mask(~(0x3U << op_lsb)); 551 } 552 553 bool IsMOPSMainOf(const Instruction* instr, uint32_t mops_type) const { 554 VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) || 555 (mops_type == "cpy"_h)); 556 const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14; 557 return GetInstructionBits() == 558 (instr->Mask(~(0x3U << op_lsb)) | (0x1 << op_lsb)); 559 } 560 561 bool IsMOPSEpilogueOf(const Instruction* instr, uint32_t mops_type) const { 562 VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) || 563 (mops_type == "cpy"_h)); 564 const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14; 565 return GetInstructionBits() == 566 (instr->Mask(~(0x3U << op_lsb)) | (0x2 << op_lsb)); 567 } 568 569 template <uint32_t mops_type> 570 bool IsConsistentMOPSTriplet() const { 571 VIXL_STATIC_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) || 572 (mops_type == "cpy"_h)); 573 574 int64_t isize = static_cast<int64_t>(kInstructionSize); 575 const Instruction* prev2 = GetInstructionAtOffset(-2 * isize); 576 const Instruction* prev1 = GetInstructionAtOffset(-1 * isize); 577 const Instruction* next1 = GetInstructionAtOffset(1 * isize); 578 const Instruction* next2 = GetInstructionAtOffset(2 * isize); 579 580 // Use the encoding of the current instruction to determine the expected 581 // adjacent instructions. NB. this doesn't check if the nearby instructions 582 // are MOPS-type, but checks that they form a consistent triplet if they 583 // are. For example, 'mov x0, #0; mov x0, #512; mov x0, #1024' is a 584 // consistent triplet, but they are not MOPS instructions. 585 const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14; 586 const uint32_t kMOPSOpfield = 0x3 << op_lsb; 587 const uint32_t kMOPSPrologue = 0; 588 const uint32_t kMOPSMain = 0x1 << op_lsb; 589 const uint32_t kMOPSEpilogue = 0x2 << op_lsb; 590 switch (Mask(kMOPSOpfield)) { 591 case kMOPSPrologue: 592 return next1->IsMOPSMainOf(this, mops_type) && 593 next2->IsMOPSEpilogueOf(this, mops_type); 594 case kMOPSMain: 595 return prev1->IsMOPSPrologueOf(this, mops_type) && 596 next1->IsMOPSEpilogueOf(this, mops_type); 597 case kMOPSEpilogue: 598 return prev2->IsMOPSPrologueOf(this, mops_type) && 599 prev1->IsMOPSMainOf(this, mops_type); 600 default: 601 VIXL_ABORT_WITH_MSG("Undefined MOPS operation\n"); 602 } 603 } 604 605 // Mozilla modifications. 606 bool IsUncondB() const; 607 bool IsCondB() const; 608 bool IsBL() const; 609 bool IsBR() const; 610 bool IsBLR() const; 611 bool IsTBZ() const; 612 bool IsTBNZ() const; 613 bool IsCBZ() const; 614 bool IsCBNZ() const; 615 bool IsLDR() const; 616 bool IsNOP() const; 617 bool IsCSDB() const; 618 bool IsADR() const; 619 bool IsADRP() const; 620 bool IsMovz() const; 621 bool IsMovk() const; 622 bool IsBranchLinkImm() const; 623 bool IsTargetReachable(const Instruction* target) const; 624 ptrdiff_t ImmPCRawOffset() const; 625 void SetImmPCRawOffset(ptrdiff_t offset); 626 void SetBits32(int msb, int lsb, unsigned value); 627 628 // Is this a stack pointer synchronization instruction as inserted by 629 // MacroAssembler::syncStackPtr()? 630 bool IsStackPtrSync() const; 631 632 static int GetImmBranchRangeBitwidth(ImmBranchType branch_type); 633 static int ImmBranchRangeBitwidth(ImmBranchType branch_type) { 634 return GetImmBranchRangeBitwidth(branch_type); 635 } 636 637 static int32_t GetImmBranchForwardRange(ImmBranchType branch_type); 638 static int32_t ImmBranchForwardRange(ImmBranchType branch_type) { 639 return GetImmBranchForwardRange(branch_type); 640 } 641 642 // Check if offset can be encoded as a RAW offset in a branch_type 643 // instruction. The offset must be encodeable directly as the immediate field 644 // in the instruction, it is not scaled by kInstructionSize first. 645 static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset); 646 647 // Get the range type corresponding to a branch type. 648 static ImmBranchRangeType ImmBranchTypeToRange(ImmBranchType); 649 650 // Get the maximum realizable forward PC offset (in bytes) for an immediate 651 // branch of the given range type. 652 // This is the largest positive multiple of kInstructionSize, offset, such 653 // that: 654 // 655 // IsValidImmPCOffset(xxx, offset / kInstructionSize) 656 // 657 // returns true for the same branch type. 658 static int32_t ImmBranchMaxForwardOffset(ImmBranchRangeType range_type); 659 660 // Get the minimuum realizable backward PC offset (in bytes) for an immediate 661 // branch of the given range type. 662 // This is the smallest (i.e., largest in magnitude) negative multiple of 663 // kInstructionSize, offset, such that: 664 // 665 // IsValidImmPCOffset(xxx, offset / kInstructionSize) 666 // 667 // returns true for the same branch type. 668 static int32_t ImmBranchMinBackwardOffset(ImmBranchRangeType range_type); 669 670 // Indicate whether Rd can be the stack pointer or the zero register. This 671 // does not check that the instruction actually has an Rd field. 672 Reg31Mode GetRdMode() const { 673 // The following instructions use sp or wsp as Rd: 674 // Add/sub (immediate) when not setting the flags. 675 // Add/sub (extended) when not setting the flags. 676 // Logical (immediate) when not setting the flags. 677 // Otherwise, r31 is the zero register. 678 if (IsAddSubImmediate() || IsAddSubExtended()) { 679 if (Mask(AddSubSetFlagsBit)) { 680 return Reg31IsZeroRegister; 681 } else { 682 return Reg31IsStackPointer; 683 } 684 } 685 if (IsLogicalImmediate()) { 686 // Of the logical (immediate) instructions, only ANDS (and its aliases) 687 // can set the flags. The others can all write into sp. 688 // Note that some logical operations are not available to 689 // immediate-operand instructions, so we have to combine two masks here. 690 if (Mask(static_cast<Instr>(LogicalImmediateMask) & LogicalOpMask) == ANDS) { 691 return Reg31IsZeroRegister; 692 } else { 693 return Reg31IsStackPointer; 694 } 695 } 696 return Reg31IsZeroRegister; 697 } 698 Reg31Mode RdMode() const { return GetRdMode(); } 699 700 // Indicate whether Rn can be the stack pointer or the zero register. This 701 // does not check that the instruction actually has an Rn field. 702 Reg31Mode GetRnMode() const { 703 // The following instructions use sp or wsp as Rn: 704 // All loads and stores. 705 // Add/sub (immediate). 706 // Add/sub (extended). 707 // Otherwise, r31 is the zero register. 708 if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { 709 return Reg31IsStackPointer; 710 } 711 return Reg31IsZeroRegister; 712 } 713 Reg31Mode RnMode() const { return GetRnMode(); } 714 715 ImmBranchType GetBranchType() const { 716 if (IsCondBranchImm()) { 717 return CondBranchType; 718 } else if (IsUncondBranchImm()) { 719 return UncondBranchType; 720 } else if (IsCompareBranch()) { 721 return CompareBranchType; 722 } else if (IsTestBranch()) { 723 return TestBranchType; 724 } else { 725 return UnknownBranchType; 726 } 727 } 728 ImmBranchType BranchType() const { 729 return GetBranchType(); 730 } 731 732 // Find the target of this instruction. 'this' may be a branch or a 733 // PC-relative addressing instruction. 734 const Instruction* GetImmPCOffsetTarget() const; 735 const Instruction* ImmPCOffsetTarget() const { 736 return GetImmPCOffsetTarget(); 737 } 738 739 // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or 740 // a PC-relative addressing instruction. 741 void SetImmPCOffsetTarget(const Instruction* target); 742 // Patch a literal load instruction to load from 'source'. 743 void SetImmLLiteral(const Instruction* source); 744 745 // The range of a load literal instruction, expressed as 'instr +- range'. 746 // The range is actually the 'positive' range; the branch instruction can 747 // target [instr - range - kInstructionSize, instr + range]. 748 static const int kLoadLiteralImmBitwidth = 19; 749 static const int kLoadLiteralRange = 750 (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize; 751 752 // Calculate the address of a literal referred to by a load-literal 753 // instruction, and return it as the specified type. 754 // 755 // The literal itself is safely mutable only if the backing buffer is safely 756 // mutable. 757 template <typename T> 758 T GetLiteralAddress() const { 759 uint64_t base_raw = reinterpret_cast<uint64_t>(this); 760 int64_t offset = GetImmLLiteral() * static_cast<int>(kLiteralEntrySize); 761 uint64_t address_raw = base_raw + offset; 762 763 // Cast the address using a C-style cast. A reinterpret_cast would be 764 // appropriate, but it can't cast one integral type to another. 765 T address = (T)(address_raw); 766 767 // Assert that the address can be represented by the specified type. 768 VIXL_ASSERT((uint64_t)(address) == address_raw); 769 770 return address; 771 } 772 template <typename T> 773 T LiteralAddress() const { 774 return GetLiteralAddress<T>(); 775 } 776 777 uint32_t GetLiteral32() const { 778 uint32_t literal; 779 memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal)); 780 return literal; 781 } 782 uint32_t Literal32() const { 783 return GetLiteral32(); 784 } 785 786 uint64_t GetLiteral64() const { 787 uint64_t literal; 788 memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal)); 789 return literal; 790 } 791 uint64_t Literal64() const { 792 return GetLiteral64(); 793 } 794 795 float GetLiteralFP32() const { return RawbitsToFloat(GetLiteral32()); } 796 float LiteralFP32() const { 797 return GetLiteralFP32(); 798 } 799 800 double GetLiteralFP64() const { return RawbitsToDouble(GetLiteral64()); } 801 double LiteralFP64() const { 802 return GetLiteralFP64(); 803 } 804 805 Instruction* GetNextInstruction() { return this + kInstructionSize; } 806 const Instruction* GetNextInstruction() const { 807 return this + kInstructionSize; 808 } 809 const Instruction* NextInstruction() const { 810 return GetNextInstruction(); 811 } 812 813 const Instruction* GetInstructionAtOffset(int64_t offset) const { 814 VIXL_ASSERT(IsWordAligned(this + offset)); 815 return this + offset; 816 } 817 const Instruction* InstructionAtOffset(int64_t offset) const { 818 return GetInstructionAtOffset(offset); 819 } 820 821 template <typename T> 822 static Instruction* Cast(T src) { 823 return reinterpret_cast<Instruction*>(src); 824 } 825 826 template <typename T> 827 static const Instruction* CastConst(T src) { 828 return reinterpret_cast<const Instruction*>(src); 829 } 830 831 // Mozilla change: 832 // 833 // Skip any constant pools with artificial guards at this point. 834 // Return either |this| or the first instruction after the pool. 835 const Instruction* skipPool() const; 836 837 private: 838 int GetImmBranch() const; 839 int ImmBranch() const { 840 return GetImmBranch(); 841 } 842 843 void SetPCRelImmTarget(const Instruction* target); 844 void SetBranchImmTarget(const Instruction* target); 845 }; 846 847 848 // Functions for handling NEON and SVE vector format information. 849 850 const int kMaxLanesPerVector = 16; 851 852 VectorFormat VectorFormatHalfWidth(VectorFormat vform); 853 VectorFormat VectorFormatDoubleWidth(VectorFormat vform); 854 VectorFormat VectorFormatDoubleLanes(VectorFormat vform); 855 VectorFormat VectorFormatHalfLanes(VectorFormat vform); 856 VectorFormat ScalarFormatFromLaneSize(int lane_size_in_bits); 857 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform); 858 VectorFormat VectorFormatFillQ(VectorFormat vform); 859 VectorFormat ScalarFormatFromFormat(VectorFormat vform); 860 VectorFormat SVEFormatFromLaneSizeInBits(int lane_size_in_bits); 861 VectorFormat SVEFormatFromLaneSizeInBytes(int lane_size_in_bytes); 862 VectorFormat SVEFormatFromLaneSizeInBytesLog2(int lane_size_in_bytes_log_2); 863 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); 864 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); 865 bool IsSVEFormat(VectorFormat vform); 866 // TODO: Make the return types of these functions consistent. 867 unsigned LaneSizeInBitsFromFormat(VectorFormat vform); 868 int LaneSizeInBytesFromFormat(VectorFormat vform); 869 int LaneSizeInBytesLog2FromFormat(VectorFormat vform); 870 int LaneCountFromFormat(VectorFormat vform); 871 int MaxLaneCountFromFormat(VectorFormat vform); 872 bool IsVectorFormat(VectorFormat vform); 873 int64_t MaxIntFromFormat(VectorFormat vform); 874 int64_t MinIntFromFormat(VectorFormat vform); 875 uint64_t MaxUintFromFormat(VectorFormat vform); 876 877 878 // clang-format off 879 enum NEONFormat { 880 NF_UNDEF = 0, 881 NF_8B = 1, 882 NF_16B = 2, 883 NF_4H = 3, 884 NF_8H = 4, 885 NF_2S = 5, 886 NF_4S = 6, 887 NF_1D = 7, 888 NF_2D = 8, 889 NF_B = 9, 890 NF_H = 10, 891 NF_S = 11, 892 NF_D = 12 893 }; 894 // clang-format on 895 896 static const unsigned kNEONFormatMaxBits = 6; 897 898 struct NEONFormatMap { 899 // The bit positions in the instruction to consider. 900 uint8_t bits[kNEONFormatMaxBits]; 901 902 // Mapping from concatenated bits to format. 903 NEONFormat map[1 << kNEONFormatMaxBits]; 904 }; 905 906 class NEONFormatDecoder { 907 public: 908 enum SubstitutionMode { kPlaceholder, kFormat }; 909 910 // Construct a format decoder with increasingly specific format maps for each 911 // substitution. If no format map is specified, the default is the integer 912 // format map. 913 explicit NEONFormatDecoder(const Instruction* instr) { 914 instrbits_ = instr->GetInstructionBits(); 915 SetFormatMaps(IntegerFormatMap()); 916 } 917 NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format) { 918 instrbits_ = instr->GetInstructionBits(); 919 SetFormatMaps(format); 920 } 921 NEONFormatDecoder(const Instruction* instr, 922 const NEONFormatMap* format0, 923 const NEONFormatMap* format1) { 924 instrbits_ = instr->GetInstructionBits(); 925 SetFormatMaps(format0, format1); 926 } 927 NEONFormatDecoder(const Instruction* instr, 928 const NEONFormatMap* format0, 929 const NEONFormatMap* format1, 930 const NEONFormatMap* format2) { 931 instrbits_ = instr->GetInstructionBits(); 932 SetFormatMaps(format0, format1, format2); 933 } 934 935 // Set the format mapping for all or individual substitutions. 936 void SetFormatMaps(const NEONFormatMap* format0, 937 const NEONFormatMap* format1 = NULL, 938 const NEONFormatMap* format2 = NULL, 939 const NEONFormatMap* format3 = NULL) { 940 VIXL_ASSERT(format0 != NULL); 941 formats_[0] = format0; 942 formats_[1] = (format1 == NULL) ? formats_[0] : format1; 943 formats_[2] = (format2 == NULL) ? formats_[1] : format2; 944 formats_[3] = (format3 == NULL) ? formats_[2] : format3; 945 } 946 void SetFormatMap(unsigned index, const NEONFormatMap* format) { 947 VIXL_ASSERT(index <= ArrayLength(formats_)); 948 VIXL_ASSERT(format != NULL); 949 formats_[index] = format; 950 } 951 952 // Substitute %s in the input string with the placeholder string for each 953 // register, ie. "'B", "'H", etc. 954 const char* SubstitutePlaceholders(const char* string) { 955 return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); 956 } 957 958 // Substitute %s in the input string with a new string based on the 959 // substitution mode. 960 const char* Substitute(const char* string, 961 SubstitutionMode mode0 = kFormat, 962 SubstitutionMode mode1 = kFormat, 963 SubstitutionMode mode2 = kFormat, 964 SubstitutionMode mode3 = kFormat) { 965 const char* subst0 = GetSubstitute(0, mode0); 966 const char* subst1 = GetSubstitute(1, mode1); 967 const char* subst2 = GetSubstitute(2, mode2); 968 const char* subst3 = GetSubstitute(3, mode3); 969 970 if ((subst0 == NULL) || (subst1 == NULL) || (subst2 == NULL) || 971 (subst3 == NULL)) { 972 return NULL; 973 } 974 975 snprintf(form_buffer_, 976 sizeof(form_buffer_), 977 string, 978 subst0, 979 subst1, 980 subst2, 981 subst3); 982 return form_buffer_; 983 } 984 985 // Append a "2" to a mnemonic string based on the state of the Q bit. 986 const char* Mnemonic(const char* mnemonic) { 987 if ((mnemonic != NULL) && (instrbits_ & NEON_Q) != 0) { 988 snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); 989 return mne_buffer_; 990 } 991 return mnemonic; 992 } 993 994 VectorFormat GetVectorFormat(int format_index = 0) { 995 return GetVectorFormat(formats_[format_index]); 996 } 997 998 VectorFormat GetVectorFormat(const NEONFormatMap* format_map) { 999 static const VectorFormat vform[] = {kFormatUndefined, 1000 kFormat8B, 1001 kFormat16B, 1002 kFormat4H, 1003 kFormat8H, 1004 kFormat2S, 1005 kFormat4S, 1006 kFormat1D, 1007 kFormat2D, 1008 kFormatB, 1009 kFormatH, 1010 kFormatS, 1011 kFormatD}; 1012 VIXL_ASSERT(GetNEONFormat(format_map) < ArrayLength(vform)); 1013 return vform[GetNEONFormat(format_map)]; 1014 } 1015 1016 // Built in mappings for common cases. 1017 1018 // The integer format map uses three bits (Q, size<1:0>) to encode the 1019 // "standard" set of NEON integer vector formats. 1020 static const NEONFormatMap* IntegerFormatMap() { 1021 static const NEONFormatMap map = 1022 {{23, 22, 30}, 1023 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}}; 1024 return ↦ 1025 } 1026 1027 // The long integer format map uses two bits (size<1:0>) to encode the 1028 // long set of NEON integer vector formats. These are used in narrow, wide 1029 // and long operations. 1030 static const NEONFormatMap* LongIntegerFormatMap() { 1031 static const NEONFormatMap map = {{23, 22}, {NF_8H, NF_4S, NF_2D}}; 1032 return ↦ 1033 } 1034 1035 // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector 1036 // formats: NF_2S, NF_4S, NF_2D. 1037 static const NEONFormatMap* FPFormatMap() { 1038 // The FP format map assumes two bits (Q, size<0>) are used to encode the 1039 // NEON FP vector formats: NF_2S, NF_4S, NF_2D. 1040 static const NEONFormatMap map = {{22, 30}, 1041 {NF_2S, NF_4S, NF_UNDEF, NF_2D}}; 1042 return ↦ 1043 } 1044 1045 // The FP16 format map uses one bit (Q) to encode the NEON vector format: 1046 // NF_4H, NF_8H. 1047 static const NEONFormatMap* FP16FormatMap() { 1048 static const NEONFormatMap map = {{30}, {NF_4H, NF_8H}}; 1049 return ↦ 1050 } 1051 1052 // The load/store format map uses three bits (Q, 11, 10) to encode the 1053 // set of NEON vector formats. 1054 static const NEONFormatMap* LoadStoreFormatMap() { 1055 static const NEONFormatMap map = 1056 {{11, 10, 30}, 1057 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}}; 1058 return ↦ 1059 } 1060 1061 // The logical format map uses one bit (Q) to encode the NEON vector format: 1062 // NF_8B, NF_16B. 1063 static const NEONFormatMap* LogicalFormatMap() { 1064 static const NEONFormatMap map = {{30}, {NF_8B, NF_16B}}; 1065 return ↦ 1066 } 1067 1068 // The triangular format map uses between two and five bits to encode the NEON 1069 // vector format: 1070 // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H 1071 // x1000->2S, x1001->4S, 10001->2D, all others undefined. 1072 static const NEONFormatMap* TriangularFormatMap() { 1073 static const NEONFormatMap map = 1074 {{19, 18, 17, 16, 30}, 1075 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 1076 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 1077 NF_UNDEF, NF_2D, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 1078 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B}}; 1079 return ↦ 1080 } 1081 1082 // The shift immediate map uses between two and five bits to encode the NEON 1083 // vector format: 1084 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H, 1085 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined. 1086 static const NEONFormatMap* ShiftImmFormatMap() { 1087 static const NEONFormatMap map = {{22, 21, 20, 19, 30}, 1088 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, 1089 NF_4H, NF_8H, NF_4H, NF_8H, 1090 NF_2S, NF_4S, NF_2S, NF_4S, 1091 NF_2S, NF_4S, NF_2S, NF_4S, 1092 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, 1093 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, 1094 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, 1095 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}}; 1096 return ↦ 1097 } 1098 1099 // The shift long/narrow immediate map uses between two and four bits to 1100 // encode the NEON vector format: 1101 // 0001->8H, 001x->4S, 01xx->2D, all others undefined. 1102 static const NEONFormatMap* ShiftLongNarrowImmFormatMap() { 1103 static const NEONFormatMap map = 1104 {{22, 21, 20, 19}, 1105 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}}; 1106 return ↦ 1107 } 1108 1109 // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar 1110 // formats: NF_B, NF_H, NF_S, NF_D. 1111 static const NEONFormatMap* ScalarFormatMap() { 1112 static const NEONFormatMap map = {{23, 22}, {NF_B, NF_H, NF_S, NF_D}}; 1113 return ↦ 1114 } 1115 1116 // The long scalar format map uses two bits (size<1:0>) to encode the longer 1117 // NEON scalar formats: NF_H, NF_S, NF_D. 1118 static const NEONFormatMap* LongScalarFormatMap() { 1119 static const NEONFormatMap map = {{23, 22}, {NF_H, NF_S, NF_D}}; 1120 return ↦ 1121 } 1122 1123 // The FP scalar format map assumes one bit (size<0>) is used to encode the 1124 // NEON FP scalar formats: NF_S, NF_D. 1125 static const NEONFormatMap* FPScalarFormatMap() { 1126 static const NEONFormatMap map = {{22}, {NF_S, NF_D}}; 1127 return ↦ 1128 } 1129 1130 // The FP scalar pairwise format map assumes two bits (U, size<0>) are used to 1131 // encode the NEON FP scalar formats: NF_H, NF_S, NF_D. 1132 static const NEONFormatMap* FPScalarPairwiseFormatMap() { 1133 static const NEONFormatMap map = {{29, 22}, {NF_H, NF_UNDEF, NF_S, NF_D}}; 1134 return ↦ 1135 } 1136 1137 // The triangular scalar format map uses between one and four bits to encode 1138 // the NEON FP scalar formats: 1139 // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. 1140 static const NEONFormatMap* TriangularScalarFormatMap() { 1141 static const NEONFormatMap map = {{19, 18, 17, 16}, 1142 {NF_UNDEF, 1143 NF_B, 1144 NF_H, 1145 NF_B, 1146 NF_S, 1147 NF_B, 1148 NF_H, 1149 NF_B, 1150 NF_D, 1151 NF_B, 1152 NF_H, 1153 NF_B, 1154 NF_S, 1155 NF_B, 1156 NF_H, 1157 NF_B}}; 1158 return ↦ 1159 } 1160 1161 private: 1162 // Get a pointer to a string that represents the format or placeholder for 1163 // the specified substitution index, based on the format map and instruction. 1164 const char* GetSubstitute(int index, SubstitutionMode mode) { 1165 if (mode == kFormat) { 1166 return NEONFormatAsString(GetNEONFormat(formats_[index])); 1167 } 1168 VIXL_ASSERT(mode == kPlaceholder); 1169 return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); 1170 } 1171 1172 // Get the NEONFormat enumerated value for bits obtained from the 1173 // instruction based on the specified format mapping. 1174 NEONFormat GetNEONFormat(const NEONFormatMap* format_map) { 1175 return format_map->map[PickBits(format_map->bits)]; 1176 } 1177 1178 // Convert a NEONFormat into a string. 1179 static const char* NEONFormatAsString(NEONFormat format) { 1180 // clang-format off 1181 static const char* formats[] = { 1182 "undefined", 1183 "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d", 1184 "b", "h", "s", "d" 1185 }; 1186 // clang-format on 1187 VIXL_ASSERT(format < ArrayLength(formats)); 1188 return formats[format]; 1189 } 1190 1191 // Convert a NEONFormat into a register placeholder string. 1192 static const char* NEONFormatAsPlaceholder(NEONFormat format) { 1193 VIXL_ASSERT((format == NF_B) || (format == NF_H) || (format == NF_S) || 1194 (format == NF_D) || (format == NF_UNDEF)); 1195 // clang-format off 1196 static const char* formats[] = { 1197 "undefined", 1198 "undefined", "undefined", "undefined", "undefined", 1199 "undefined", "undefined", "undefined", "undefined", 1200 "'B", "'H", "'S", "'D" 1201 }; 1202 // clang-format on 1203 return formats[format]; 1204 } 1205 1206 // Select bits from instrbits_ defined by the bits array, concatenate them, 1207 // and return the value. 1208 uint8_t PickBits(const uint8_t bits[]) { 1209 uint8_t result = 0; 1210 for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { 1211 if (bits[b] == 0) break; 1212 result <<= 1; 1213 result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; 1214 } 1215 return result; 1216 } 1217 1218 Instr instrbits_; 1219 const NEONFormatMap* formats_[4]; 1220 char form_buffer_[64]; 1221 char mne_buffer_[16]; 1222 }; 1223 } // namespace vixl 1224 1225 #endif // VIXL_A64_INSTRUCTIONS_A64_H_