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_AARCH64_INSTRUCTIONS_AARCH64_H_ 28 #define VIXL_AARCH64_INSTRUCTIONS_AARCH64_H_ 29 30 #include "../globals-vixl.h" 31 #include "../utils-vixl.h" 32 33 #include "constants-aarch64.h" 34 35 namespace vixl { 36 namespace aarch64 { 37 // ISA constants. -------------------------------------------------------------- 38 39 typedef uint32_t Instr; 40 const unsigned kInstructionSize = 4; 41 const unsigned kInstructionSizeLog2 = 2; 42 const unsigned kLiteralEntrySize = 4; 43 const unsigned kLiteralEntrySizeLog2 = 2; 44 const unsigned kMaxLoadLiteralRange = 1 * MBytes; 45 46 // This is the nominal page size (as used by the adrp instruction); the actual 47 // size of the memory pages allocated by the kernel is likely to differ. 48 const unsigned kPageSize = 4 * KBytes; 49 const unsigned kPageSizeLog2 = 12; 50 51 const unsigned kBRegSize = 8; 52 const unsigned kBRegSizeLog2 = 3; 53 const unsigned kBRegSizeInBytes = kBRegSize / 8; 54 const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3; 55 const unsigned kHRegSize = 16; 56 const unsigned kHRegSizeLog2 = 4; 57 const unsigned kHRegSizeInBytes = kHRegSize / 8; 58 const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3; 59 const unsigned kWRegSize = 32; 60 const unsigned kWRegSizeLog2 = 5; 61 const unsigned kWRegSizeInBytes = kWRegSize / 8; 62 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; 63 const unsigned kXRegSize = 64; 64 const unsigned kXRegSizeLog2 = 6; 65 const unsigned kXRegSizeInBytes = kXRegSize / 8; 66 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; 67 const unsigned kSRegSize = 32; 68 const unsigned kSRegSizeLog2 = 5; 69 const unsigned kSRegSizeInBytes = kSRegSize / 8; 70 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; 71 const unsigned kDRegSize = 64; 72 const unsigned kDRegSizeLog2 = 6; 73 const unsigned kDRegSizeInBytes = kDRegSize / 8; 74 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; 75 const unsigned kQRegSize = 128; 76 const unsigned kQRegSizeLog2 = 7; 77 const unsigned kQRegSizeInBytes = kQRegSize / 8; 78 const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3; 79 const uint64_t kWRegMask = UINT64_C(0xffffffff); 80 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); 81 const uint64_t kSRegMask = UINT64_C(0xffffffff); 82 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); 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 kWMaxUInt = UINT64_C(0xffffffff); 92 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); 93 const int64_t kXMinInt = INT64_C(0x8000000000000000); 94 const int32_t kWMaxInt = INT32_C(0x7fffffff); 95 const int32_t kWMinInt = INT32_C(0x80000000); 96 const unsigned kFpRegCode = 29; 97 const unsigned kLinkRegCode = 30; 98 const unsigned kSpRegCode = 31; 99 const unsigned kZeroRegCode = 31; 100 const unsigned kSPRegInternalCode = 63; 101 const unsigned kRegCodeMask = 0x1f; 102 103 const unsigned kAddressTagOffset = 56; 104 const unsigned kAddressTagWidth = 8; 105 const uint64_t kAddressTagMask = ((UINT64_C(1) << kAddressTagWidth) - 1) 106 << kAddressTagOffset; 107 VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); 108 109 // AArch64 floating-point specifics. These match IEEE-754. 110 const unsigned kDoubleMantissaBits = 52; 111 const unsigned kDoubleExponentBits = 11; 112 const unsigned kFloatMantissaBits = 23; 113 const unsigned kFloatExponentBits = 8; 114 const unsigned kFloat16MantissaBits = 10; 115 const unsigned kFloat16ExponentBits = 5; 116 117 // Floating-point infinity values. 118 extern const float16 kFP16PositiveInfinity; 119 extern const float16 kFP16NegativeInfinity; 120 extern const float kFP32PositiveInfinity; 121 extern const float kFP32NegativeInfinity; 122 extern const double kFP64PositiveInfinity; 123 extern const double kFP64NegativeInfinity; 124 125 // The default NaN values (for FPCR.DN=1). 126 extern const float16 kFP16DefaultNaN; 127 extern const float kFP32DefaultNaN; 128 extern const double kFP64DefaultNaN; 129 130 unsigned CalcLSDataSize(LoadStoreOp op); 131 unsigned CalcLSPairDataSize(LoadStorePairOp op); 132 133 enum ImmBranchType { 134 UnknownBranchType = 0, 135 CondBranchType = 1, 136 UncondBranchType = 2, 137 CompareBranchType = 3, 138 TestBranchType = 4 139 }; 140 141 enum AddrMode { Offset, PreIndex, PostIndex }; 142 143 enum FPRounding { 144 // The first four values are encodable directly by FPCR<RMode>. 145 FPTieEven = 0x0, 146 FPPositiveInfinity = 0x1, 147 FPNegativeInfinity = 0x2, 148 FPZero = 0x3, 149 150 // The final rounding modes are only available when explicitly specified by 151 // the instruction (such as with fcvta). It cannot be set in FPCR. 152 FPTieAway, 153 FPRoundOdd 154 }; 155 156 enum Reg31Mode { Reg31IsStackPointer, Reg31IsZeroRegister }; 157 158 // Instructions. --------------------------------------------------------------- 159 160 class Instruction { 161 public: GetInstructionBits()162 Instr GetInstructionBits() const { 163 return *(reinterpret_cast<const Instr*>(this)); 164 } 165 VIXL_DEPRECATED("GetInstructionBits", Instr InstructionBits() const) { 166 return GetInstructionBits(); 167 } 168 SetInstructionBits(Instr new_instr)169 void SetInstructionBits(Instr new_instr) { 170 *(reinterpret_cast<Instr*>(this)) = new_instr; 171 } 172 ExtractBit(int pos)173 int ExtractBit(int pos) const { return (GetInstructionBits() >> pos) & 1; } Bit(int pos)174 VIXL_DEPRECATED("ExtractBit", int Bit(int pos) const) { 175 return ExtractBit(pos); 176 } 177 ExtractBits(int msb,int lsb)178 uint32_t ExtractBits(int msb, int lsb) const { 179 return ExtractUnsignedBitfield32(msb, lsb, GetInstructionBits()); 180 } 181 VIXL_DEPRECATED("ExtractBits", uint32_t Bits(int msb, int lsb) const) { 182 return ExtractBits(msb, lsb); 183 } 184 ExtractSignedBits(int msb,int lsb)185 int32_t ExtractSignedBits(int msb, int lsb) const { 186 int32_t bits = *(reinterpret_cast<const int32_t*>(this)); 187 return ExtractSignedBitfield32(msb, lsb, bits); 188 } 189 VIXL_DEPRECATED("ExtractSignedBits", 190 int32_t SignedBits(int msb, int lsb) const) { 191 return ExtractSignedBits(msb, lsb); 192 } 193 Mask(uint32_t mask)194 Instr Mask(uint32_t mask) const { return GetInstructionBits() & mask; } 195 196 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ 197 int32_t Get##Name() const { return this->Func(HighBit, LowBit); } \ 198 VIXL_DEPRECATED("Get" #Name, int32_t Name() const) { return Get##Name(); } INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)199 INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) 200 #undef DEFINE_GETTER 201 202 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), 203 // formed from ImmPCRelLo and ImmPCRelHi. 204 int GetImmPCRel() const { 205 uint32_t hi = static_cast<uint32_t>(GetImmPCRelHi()); 206 uint32_t lo = GetImmPCRelLo(); 207 uint32_t offset = (hi << ImmPCRelLo_width) | lo; 208 int width = ImmPCRelLo_width + ImmPCRelHi_width; 209 return ExtractSignedBitfield32(width - 1, 0, offset); 210 } ImmPCRel()211 VIXL_DEPRECATED("GetImmPCRel", int ImmPCRel() const) { return GetImmPCRel(); } 212 213 uint64_t GetImmLogical() const; 214 VIXL_DEPRECATED("GetImmLogical", uint64_t ImmLogical() const) { 215 return GetImmLogical(); 216 } 217 218 unsigned GetImmNEONabcdefgh() const; ImmNEONabcdefgh()219 VIXL_DEPRECATED("GetImmNEONabcdefgh", unsigned ImmNEONabcdefgh() const) { 220 return GetImmNEONabcdefgh(); 221 } 222 223 float GetImmFP32() const; ImmFP32()224 VIXL_DEPRECATED("GetImmFP32", float ImmFP32() const) { return GetImmFP32(); } 225 226 double GetImmFP64() const; ImmFP64()227 VIXL_DEPRECATED("GetImmFP64", double ImmFP64() const) { return GetImmFP64(); } 228 229 float GetImmNEONFP32() const; ImmNEONFP32()230 VIXL_DEPRECATED("GetImmNEONFP32", float ImmNEONFP32() const) { 231 return GetImmNEONFP32(); 232 } 233 234 double GetImmNEONFP64() const; ImmNEONFP64()235 VIXL_DEPRECATED("GetImmNEONFP64", double ImmNEONFP64() const) { 236 return GetImmNEONFP64(); 237 } 238 GetSizeLS()239 unsigned GetSizeLS() const { 240 return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask))); 241 } SizeLS()242 VIXL_DEPRECATED("GetSizeLS", unsigned SizeLS() const) { return GetSizeLS(); } 243 GetSizeLSPair()244 unsigned GetSizeLSPair() const { 245 return CalcLSPairDataSize( 246 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); 247 } SizeLSPair()248 VIXL_DEPRECATED("GetSizeLSPair", unsigned SizeLSPair() const) { 249 return GetSizeLSPair(); 250 } 251 GetNEONLSIndex(int access_size_shift)252 int GetNEONLSIndex(int access_size_shift) const { 253 int64_t q = GetNEONQ(); 254 int64_t s = GetNEONS(); 255 int64_t size = GetNEONLSSize(); 256 int64_t index = (q << 3) | (s << 2) | size; 257 return static_cast<int>(index >> access_size_shift); 258 } 259 VIXL_DEPRECATED("GetNEONLSIndex", NEONLSIndex(int access_size_shift)260 int NEONLSIndex(int access_size_shift) const) { 261 return GetNEONLSIndex(access_size_shift); 262 } 263 264 // Helpers. IsCondBranchImm()265 bool IsCondBranchImm() const { 266 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; 267 } 268 IsUncondBranchImm()269 bool IsUncondBranchImm() const { 270 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; 271 } 272 IsCompareBranch()273 bool IsCompareBranch() const { 274 return Mask(CompareBranchFMask) == CompareBranchFixed; 275 } 276 IsTestBranch()277 bool IsTestBranch() const { return Mask(TestBranchFMask) == TestBranchFixed; } 278 IsImmBranch()279 bool IsImmBranch() const { return GetBranchType() != UnknownBranchType; } 280 IsPCRelAddressing()281 bool IsPCRelAddressing() const { 282 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; 283 } 284 IsLogicalImmediate()285 bool IsLogicalImmediate() const { 286 return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; 287 } 288 IsAddSubImmediate()289 bool IsAddSubImmediate() const { 290 return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; 291 } 292 IsAddSubExtended()293 bool IsAddSubExtended() const { 294 return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; 295 } 296 IsLoadOrStore()297 bool IsLoadOrStore() const { 298 return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; 299 } 300 301 bool IsLoad() const; 302 bool IsStore() const; 303 IsLoadLiteral()304 bool IsLoadLiteral() const { 305 // This includes PRFM_lit. 306 return Mask(LoadLiteralFMask) == LoadLiteralFixed; 307 } 308 IsMovn()309 bool IsMovn() const { 310 return (Mask(MoveWideImmediateMask) == MOVN_x) || 311 (Mask(MoveWideImmediateMask) == MOVN_w); 312 } 313 314 static int GetImmBranchRangeBitwidth(ImmBranchType branch_type); 315 VIXL_DEPRECATED( 316 "GetImmBranchRangeBitwidth", ImmBranchRangeBitwidth(ImmBranchType branch_type)317 static int ImmBranchRangeBitwidth(ImmBranchType branch_type)) { 318 return GetImmBranchRangeBitwidth(branch_type); 319 } 320 321 static int32_t GetImmBranchForwardRange(ImmBranchType branch_type); 322 VIXL_DEPRECATED( 323 "GetImmBranchForwardRange", 324 static int32_t ImmBranchForwardRange(ImmBranchType branch_type)) { 325 return GetImmBranchForwardRange(branch_type); 326 } 327 328 static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset); 329 330 // Indicate whether Rd can be the stack pointer or the zero register. This 331 // does not check that the instruction actually has an Rd field. GetRdMode()332 Reg31Mode GetRdMode() const { 333 // The following instructions use sp or wsp as Rd: 334 // Add/sub (immediate) when not setting the flags. 335 // Add/sub (extended) when not setting the flags. 336 // Logical (immediate) when not setting the flags. 337 // Otherwise, r31 is the zero register. 338 if (IsAddSubImmediate() || IsAddSubExtended()) { 339 if (Mask(AddSubSetFlagsBit)) { 340 return Reg31IsZeroRegister; 341 } else { 342 return Reg31IsStackPointer; 343 } 344 } 345 if (IsLogicalImmediate()) { 346 // Of the logical (immediate) instructions, only ANDS (and its aliases) 347 // can set the flags. The others can all write into sp. 348 // Note that some logical operations are not available to 349 // immediate-operand instructions, so we have to combine two masks here. 350 if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { 351 return Reg31IsZeroRegister; 352 } else { 353 return Reg31IsStackPointer; 354 } 355 } 356 return Reg31IsZeroRegister; 357 } 358 VIXL_DEPRECATED("GetRdMode", Reg31Mode RdMode() const) { return GetRdMode(); } 359 360 // Indicate whether Rn can be the stack pointer or the zero register. This 361 // does not check that the instruction actually has an Rn field. GetRnMode()362 Reg31Mode GetRnMode() const { 363 // The following instructions use sp or wsp as Rn: 364 // All loads and stores. 365 // Add/sub (immediate). 366 // Add/sub (extended). 367 // Otherwise, r31 is the zero register. 368 if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { 369 return Reg31IsStackPointer; 370 } 371 return Reg31IsZeroRegister; 372 } 373 VIXL_DEPRECATED("GetRnMode", Reg31Mode RnMode() const) { return GetRnMode(); } 374 GetBranchType()375 ImmBranchType GetBranchType() const { 376 if (IsCondBranchImm()) { 377 return CondBranchType; 378 } else if (IsUncondBranchImm()) { 379 return UncondBranchType; 380 } else if (IsCompareBranch()) { 381 return CompareBranchType; 382 } else if (IsTestBranch()) { 383 return TestBranchType; 384 } else { 385 return UnknownBranchType; 386 } 387 } 388 VIXL_DEPRECATED("GetBranchType", ImmBranchType BranchType() const) { 389 return GetBranchType(); 390 } 391 392 // Find the target of this instruction. 'this' may be a branch or a 393 // PC-relative addressing instruction. 394 const Instruction* GetImmPCOffsetTarget() const; 395 VIXL_DEPRECATED("GetImmPCOffsetTarget", 396 const Instruction* ImmPCOffsetTarget() const) { 397 return GetImmPCOffsetTarget(); 398 } 399 400 // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or 401 // a PC-relative addressing instruction. 402 void SetImmPCOffsetTarget(const Instruction* target); 403 // Patch a literal load instruction to load from 'source'. 404 void SetImmLLiteral(const Instruction* source); 405 406 // The range of a load literal instruction, expressed as 'instr +- range'. 407 // The range is actually the 'positive' range; the branch instruction can 408 // target [instr - range - kInstructionSize, instr + range]. 409 static const int kLoadLiteralImmBitwidth = 19; 410 static const int kLoadLiteralRange = 411 (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize; 412 413 // Calculate the address of a literal referred to by a load-literal 414 // instruction, and return it as the specified type. 415 // 416 // The literal itself is safely mutable only if the backing buffer is safely 417 // mutable. 418 template <typename T> GetLiteralAddress()419 T GetLiteralAddress() const { 420 uint64_t base_raw = reinterpret_cast<uint64_t>(this); 421 int64_t offset = GetImmLLiteral() * static_cast<int>(kLiteralEntrySize); 422 uint64_t address_raw = base_raw + offset; 423 424 // Cast the address using a C-style cast. A reinterpret_cast would be 425 // appropriate, but it can't cast one integral type to another. 426 T address = (T)(address_raw); 427 428 // Assert that the address can be represented by the specified type. 429 VIXL_ASSERT((uint64_t)(address) == address_raw); 430 431 return address; 432 } 433 template <typename T> 434 VIXL_DEPRECATED("GetLiteralAddress", T LiteralAddress() const) { 435 return GetLiteralAddress<T>(); 436 } 437 GetLiteral32()438 uint32_t GetLiteral32() const { 439 uint32_t literal; 440 memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal)); 441 return literal; 442 } 443 VIXL_DEPRECATED("GetLiteral32", uint32_t Literal32() const) { 444 return GetLiteral32(); 445 } 446 GetLiteral64()447 uint64_t GetLiteral64() const { 448 uint64_t literal; 449 memcpy(&literal, GetLiteralAddress<const void*>(), sizeof(literal)); 450 return literal; 451 } 452 VIXL_DEPRECATED("GetLiteral64", uint64_t Literal64() const) { 453 return GetLiteral64(); 454 } 455 GetLiteralFP32()456 float GetLiteralFP32() const { return RawbitsToFloat(GetLiteral32()); } LiteralFP32()457 VIXL_DEPRECATED("GetLiteralFP32", float LiteralFP32() const) { 458 return GetLiteralFP32(); 459 } 460 GetLiteralFP64()461 double GetLiteralFP64() const { return RawbitsToDouble(GetLiteral64()); } LiteralFP64()462 VIXL_DEPRECATED("GetLiteralFP64", double LiteralFP64() const) { 463 return GetLiteralFP64(); 464 } 465 GetNextInstruction()466 const Instruction* GetNextInstruction() const { 467 return this + kInstructionSize; 468 } 469 VIXL_DEPRECATED("GetNextInstruction", 470 const Instruction* NextInstruction() const) { 471 return GetNextInstruction(); 472 } 473 GetInstructionAtOffset(int64_t offset)474 const Instruction* GetInstructionAtOffset(int64_t offset) const { 475 VIXL_ASSERT(IsWordAligned(this + offset)); 476 return this + offset; 477 } 478 VIXL_DEPRECATED("GetInstructionAtOffset", 479 const Instruction* InstructionAtOffset(int64_t offset) 480 const) { 481 return GetInstructionAtOffset(offset); 482 } 483 484 template <typename T> Cast(T src)485 static Instruction* Cast(T src) { 486 return reinterpret_cast<Instruction*>(src); 487 } 488 489 template <typename T> CastConst(T src)490 static const Instruction* CastConst(T src) { 491 return reinterpret_cast<const Instruction*>(src); 492 } 493 494 private: 495 int GetImmBranch() const; 496 497 static float Imm8ToFP32(uint32_t imm8); 498 static double Imm8ToFP64(uint32_t imm8); 499 500 void SetPCRelImmTarget(const Instruction* target); 501 void SetBranchImmTarget(const Instruction* target); 502 }; 503 504 505 // Functions for handling NEON vector format information. 506 enum VectorFormat { 507 kFormatUndefined = 0xffffffff, 508 kFormat8B = NEON_8B, 509 kFormat16B = NEON_16B, 510 kFormat4H = NEON_4H, 511 kFormat8H = NEON_8H, 512 kFormat2S = NEON_2S, 513 kFormat4S = NEON_4S, 514 kFormat1D = NEON_1D, 515 kFormat2D = NEON_2D, 516 517 // Scalar formats. We add the scalar bit to distinguish between scalar and 518 // vector enumerations; the bit is always set in the encoding of scalar ops 519 // and always clear for vector ops. Although kFormatD and kFormat1D appear 520 // to be the same, their meaning is subtly different. The first is a scalar 521 // operation, the second a vector operation that only affects one lane. 522 kFormatB = NEON_B | NEONScalar, 523 kFormatH = NEON_H | NEONScalar, 524 kFormatS = NEON_S | NEONScalar, 525 kFormatD = NEON_D | NEONScalar 526 }; 527 528 const int kMaxLanesPerVector = 16; 529 530 VectorFormat VectorFormatHalfWidth(VectorFormat vform); 531 VectorFormat VectorFormatDoubleWidth(VectorFormat vform); 532 VectorFormat VectorFormatDoubleLanes(VectorFormat vform); 533 VectorFormat VectorFormatHalfLanes(VectorFormat vform); 534 VectorFormat ScalarFormatFromLaneSize(int lanesize); 535 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform); 536 VectorFormat VectorFormatFillQ(VectorFormat vform); 537 VectorFormat ScalarFormatFromFormat(VectorFormat vform); 538 unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); 539 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); 540 // TODO: Make the return types of these functions consistent. 541 unsigned LaneSizeInBitsFromFormat(VectorFormat vform); 542 int LaneSizeInBytesFromFormat(VectorFormat vform); 543 int LaneSizeInBytesLog2FromFormat(VectorFormat vform); 544 int LaneCountFromFormat(VectorFormat vform); 545 int MaxLaneCountFromFormat(VectorFormat vform); 546 bool IsVectorFormat(VectorFormat vform); 547 int64_t MaxIntFromFormat(VectorFormat vform); 548 int64_t MinIntFromFormat(VectorFormat vform); 549 uint64_t MaxUintFromFormat(VectorFormat vform); 550 551 552 // clang-format off 553 enum NEONFormat { 554 NF_UNDEF = 0, 555 NF_8B = 1, 556 NF_16B = 2, 557 NF_4H = 3, 558 NF_8H = 4, 559 NF_2S = 5, 560 NF_4S = 6, 561 NF_1D = 7, 562 NF_2D = 8, 563 NF_B = 9, 564 NF_H = 10, 565 NF_S = 11, 566 NF_D = 12 567 }; 568 // clang-format on 569 570 static const unsigned kNEONFormatMaxBits = 6; 571 572 struct NEONFormatMap { 573 // The bit positions in the instruction to consider. 574 uint8_t bits[kNEONFormatMaxBits]; 575 576 // Mapping from concatenated bits to format. 577 NEONFormat map[1 << kNEONFormatMaxBits]; 578 }; 579 580 class NEONFormatDecoder { 581 public: 582 enum SubstitutionMode { kPlaceholder, kFormat }; 583 584 // Construct a format decoder with increasingly specific format maps for each 585 // subsitution. If no format map is specified, the default is the integer 586 // format map. NEONFormatDecoder(const Instruction * instr)587 explicit NEONFormatDecoder(const Instruction* instr) { 588 instrbits_ = instr->GetInstructionBits(); 589 SetFormatMaps(IntegerFormatMap()); 590 } NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format)591 NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format) { 592 instrbits_ = instr->GetInstructionBits(); 593 SetFormatMaps(format); 594 } NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1)595 NEONFormatDecoder(const Instruction* instr, 596 const NEONFormatMap* format0, 597 const NEONFormatMap* format1) { 598 instrbits_ = instr->GetInstructionBits(); 599 SetFormatMaps(format0, format1); 600 } NEONFormatDecoder(const Instruction * instr,const NEONFormatMap * format0,const NEONFormatMap * format1,const NEONFormatMap * format2)601 NEONFormatDecoder(const Instruction* instr, 602 const NEONFormatMap* format0, 603 const NEONFormatMap* format1, 604 const NEONFormatMap* format2) { 605 instrbits_ = instr->GetInstructionBits(); 606 SetFormatMaps(format0, format1, format2); 607 } 608 609 // Set the format mapping for all or individual substitutions. 610 void SetFormatMaps(const NEONFormatMap* format0, 611 const NEONFormatMap* format1 = NULL, 612 const NEONFormatMap* format2 = NULL) { 613 VIXL_ASSERT(format0 != NULL); 614 formats_[0] = format0; 615 formats_[1] = (format1 == NULL) ? formats_[0] : format1; 616 formats_[2] = (format2 == NULL) ? formats_[1] : format2; 617 } SetFormatMap(unsigned index,const NEONFormatMap * format)618 void SetFormatMap(unsigned index, const NEONFormatMap* format) { 619 VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0]))); 620 VIXL_ASSERT(format != NULL); 621 formats_[index] = format; 622 } 623 624 // Substitute %s in the input string with the placeholder string for each 625 // register, ie. "'B", "'H", etc. SubstitutePlaceholders(const char * string)626 const char* SubstitutePlaceholders(const char* string) { 627 return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); 628 } 629 630 // Substitute %s in the input string with a new string based on the 631 // substitution mode. 632 const char* Substitute(const char* string, 633 SubstitutionMode mode0 = kFormat, 634 SubstitutionMode mode1 = kFormat, 635 SubstitutionMode mode2 = kFormat) { 636 snprintf(form_buffer_, 637 sizeof(form_buffer_), 638 string, 639 GetSubstitute(0, mode0), 640 GetSubstitute(1, mode1), 641 GetSubstitute(2, mode2)); 642 return form_buffer_; 643 } 644 645 // Append a "2" to a mnemonic string based of the state of the Q bit. Mnemonic(const char * mnemonic)646 const char* Mnemonic(const char* mnemonic) { 647 if ((instrbits_ & NEON_Q) != 0) { 648 snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); 649 return mne_buffer_; 650 } 651 return mnemonic; 652 } 653 654 VectorFormat GetVectorFormat(int format_index = 0) { 655 return GetVectorFormat(formats_[format_index]); 656 } 657 GetVectorFormat(const NEONFormatMap * format_map)658 VectorFormat GetVectorFormat(const NEONFormatMap* format_map) { 659 static const VectorFormat vform[] = {kFormatUndefined, 660 kFormat8B, 661 kFormat16B, 662 kFormat4H, 663 kFormat8H, 664 kFormat2S, 665 kFormat4S, 666 kFormat1D, 667 kFormat2D, 668 kFormatB, 669 kFormatH, 670 kFormatS, 671 kFormatD}; 672 VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0]))); 673 return vform[GetNEONFormat(format_map)]; 674 } 675 676 // Built in mappings for common cases. 677 678 // The integer format map uses three bits (Q, size<1:0>) to encode the 679 // "standard" set of NEON integer vector formats. IntegerFormatMap()680 static const NEONFormatMap* IntegerFormatMap() { 681 static const NEONFormatMap map = 682 {{23, 22, 30}, 683 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}}; 684 return ↦ 685 } 686 687 // The long integer format map uses two bits (size<1:0>) to encode the 688 // long set of NEON integer vector formats. These are used in narrow, wide 689 // and long operations. LongIntegerFormatMap()690 static const NEONFormatMap* LongIntegerFormatMap() { 691 static const NEONFormatMap map = {{23, 22}, {NF_8H, NF_4S, NF_2D}}; 692 return ↦ 693 } 694 695 // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector 696 // formats: NF_2S, NF_4S, NF_2D. FPFormatMap()697 static const NEONFormatMap* FPFormatMap() { 698 // The FP format map assumes two bits (Q, size<0>) are used to encode the 699 // NEON FP vector formats: NF_2S, NF_4S, NF_2D. 700 static const NEONFormatMap map = {{22, 30}, 701 {NF_2S, NF_4S, NF_UNDEF, NF_2D}}; 702 return ↦ 703 } 704 705 // The load/store format map uses three bits (Q, 11, 10) to encode the 706 // set of NEON vector formats. LoadStoreFormatMap()707 static const NEONFormatMap* LoadStoreFormatMap() { 708 static const NEONFormatMap map = 709 {{11, 10, 30}, 710 {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}}; 711 return ↦ 712 } 713 714 // The logical format map uses one bit (Q) to encode the NEON vector format: 715 // NF_8B, NF_16B. LogicalFormatMap()716 static const NEONFormatMap* LogicalFormatMap() { 717 static const NEONFormatMap map = {{30}, {NF_8B, NF_16B}}; 718 return ↦ 719 } 720 721 // The triangular format map uses between two and five bits to encode the NEON 722 // vector format: 723 // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H 724 // x1000->2S, x1001->4S, 10001->2D, all others undefined. TriangularFormatMap()725 static const NEONFormatMap* TriangularFormatMap() { 726 static const NEONFormatMap map = 727 {{19, 18, 17, 16, 30}, 728 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 729 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 730 NF_UNDEF, NF_2D, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, 731 NF_2S, NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B}}; 732 return ↦ 733 } 734 735 // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar 736 // formats: NF_B, NF_H, NF_S, NF_D. ScalarFormatMap()737 static const NEONFormatMap* ScalarFormatMap() { 738 static const NEONFormatMap map = {{23, 22}, {NF_B, NF_H, NF_S, NF_D}}; 739 return ↦ 740 } 741 742 // The long scalar format map uses two bits (size<1:0>) to encode the longer 743 // NEON scalar formats: NF_H, NF_S, NF_D. LongScalarFormatMap()744 static const NEONFormatMap* LongScalarFormatMap() { 745 static const NEONFormatMap map = {{23, 22}, {NF_H, NF_S, NF_D}}; 746 return ↦ 747 } 748 749 // The FP scalar format map assumes one bit (size<0>) is used to encode the 750 // NEON FP scalar formats: NF_S, NF_D. FPScalarFormatMap()751 static const NEONFormatMap* FPScalarFormatMap() { 752 static const NEONFormatMap map = {{22}, {NF_S, NF_D}}; 753 return ↦ 754 } 755 756 // The triangular scalar format map uses between one and four bits to encode 757 // the NEON FP scalar formats: 758 // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. TriangularScalarFormatMap()759 static const NEONFormatMap* TriangularScalarFormatMap() { 760 static const NEONFormatMap map = {{19, 18, 17, 16}, 761 {NF_UNDEF, 762 NF_B, 763 NF_H, 764 NF_B, 765 NF_S, 766 NF_B, 767 NF_H, 768 NF_B, 769 NF_D, 770 NF_B, 771 NF_H, 772 NF_B, 773 NF_S, 774 NF_B, 775 NF_H, 776 NF_B}}; 777 return ↦ 778 } 779 780 private: 781 // Get a pointer to a string that represents the format or placeholder for 782 // the specified substitution index, based on the format map and instruction. GetSubstitute(int index,SubstitutionMode mode)783 const char* GetSubstitute(int index, SubstitutionMode mode) { 784 if (mode == kFormat) { 785 return NEONFormatAsString(GetNEONFormat(formats_[index])); 786 } 787 VIXL_ASSERT(mode == kPlaceholder); 788 return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); 789 } 790 791 // Get the NEONFormat enumerated value for bits obtained from the 792 // instruction based on the specified format mapping. GetNEONFormat(const NEONFormatMap * format_map)793 NEONFormat GetNEONFormat(const NEONFormatMap* format_map) { 794 return format_map->map[PickBits(format_map->bits)]; 795 } 796 797 // Convert a NEONFormat into a string. NEONFormatAsString(NEONFormat format)798 static const char* NEONFormatAsString(NEONFormat format) { 799 // clang-format off 800 static const char* formats[] = { 801 "undefined", 802 "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d", 803 "b", "h", "s", "d" 804 }; 805 // clang-format on 806 VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0]))); 807 return formats[format]; 808 } 809 810 // Convert a NEONFormat into a register placeholder string. NEONFormatAsPlaceholder(NEONFormat format)811 static const char* NEONFormatAsPlaceholder(NEONFormat format) { 812 VIXL_ASSERT((format == NF_B) || (format == NF_H) || (format == NF_S) || 813 (format == NF_D) || (format == NF_UNDEF)); 814 // clang-format off 815 static const char* formats[] = { 816 "undefined", 817 "undefined", "undefined", "undefined", "undefined", 818 "undefined", "undefined", "undefined", "undefined", 819 "'B", "'H", "'S", "'D" 820 }; 821 // clang-format on 822 return formats[format]; 823 } 824 825 // Select bits from instrbits_ defined by the bits array, concatenate them, 826 // and return the value. PickBits(const uint8_t bits[])827 uint8_t PickBits(const uint8_t bits[]) { 828 uint8_t result = 0; 829 for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { 830 if (bits[b] == 0) break; 831 result <<= 1; 832 result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; 833 } 834 return result; 835 } 836 837 Instr instrbits_; 838 const NEONFormatMap* formats_[3]; 839 char form_buffer_[64]; 840 char mne_buffer_[16]; 841 }; 842 } // namespace aarch64 843 } // namespace vixl 844 845 #endif // VIXL_AARCH64_INSTRUCTIONS_AARCH64_H_ 846