Home | History | Annotate | Download | only in aarch64
      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:
    162   Instr GetInstructionBits() const {
    163     return *(reinterpret_cast<const Instr*>(this));
    164   }
    165   VIXL_DEPRECATED("GetInstructionBits", Instr InstructionBits() const) {
    166     return GetInstructionBits();
    167   }
    168 
    169   void SetInstructionBits(Instr new_instr) {
    170     *(reinterpret_cast<Instr*>(this)) = new_instr;
    171   }
    172 
    173   int ExtractBit(int pos) const { return (GetInstructionBits() >> pos) & 1; }
    174   VIXL_DEPRECATED("ExtractBit", int Bit(int pos) const) {
    175     return ExtractBit(pos);
    176   }
    177 
    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 
    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 
    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(); }
    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   }
    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;
    219   VIXL_DEPRECATED("GetImmNEONabcdefgh", unsigned ImmNEONabcdefgh() const) {
    220     return GetImmNEONabcdefgh();
    221   }
    222 
    223   float GetImmFP32() const;
    224   VIXL_DEPRECATED("GetImmFP32", float ImmFP32() const) { return GetImmFP32(); }
    225 
    226   double GetImmFP64() const;
    227   VIXL_DEPRECATED("GetImmFP64", double ImmFP64() const) { return GetImmFP64(); }
    228 
    229   float GetImmNEONFP32() const;
    230   VIXL_DEPRECATED("GetImmNEONFP32", float ImmNEONFP32() const) {
    231     return GetImmNEONFP32();
    232   }
    233 
    234   double GetImmNEONFP64() const;
    235   VIXL_DEPRECATED("GetImmNEONFP64", double ImmNEONFP64() const) {
    236     return GetImmNEONFP64();
    237   }
    238 
    239   unsigned GetSizeLS() const {
    240     return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask)));
    241   }
    242   VIXL_DEPRECATED("GetSizeLS", unsigned SizeLS() const) { return GetSizeLS(); }
    243 
    244   unsigned GetSizeLSPair() const {
    245     return CalcLSPairDataSize(
    246         static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
    247   }
    248   VIXL_DEPRECATED("GetSizeLSPair", unsigned SizeLSPair() const) {
    249     return GetSizeLSPair();
    250   }
    251 
    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",
    260                   int NEONLSIndex(int access_size_shift) const) {
    261     return GetNEONLSIndex(access_size_shift);
    262   }
    263 
    264   // Helpers.
    265   bool IsCondBranchImm() const {
    266     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
    267   }
    268 
    269   bool IsUncondBranchImm() const {
    270     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
    271   }
    272 
    273   bool IsCompareBranch() const {
    274     return Mask(CompareBranchFMask) == CompareBranchFixed;
    275   }
    276 
    277   bool IsTestBranch() const { return Mask(TestBranchFMask) == TestBranchFixed; }
    278 
    279   bool IsImmBranch() const { return GetBranchType() != UnknownBranchType; }
    280 
    281   bool IsPCRelAddressing() const {
    282     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
    283   }
    284 
    285   bool IsLogicalImmediate() const {
    286     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
    287   }
    288 
    289   bool IsAddSubImmediate() const {
    290     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
    291   }
    292 
    293   bool IsAddSubExtended() const {
    294     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
    295   }
    296 
    297   bool IsLoadOrStore() const {
    298     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
    299   }
    300 
    301   bool IsLoad() const;
    302   bool IsStore() const;
    303 
    304   bool IsLoadLiteral() const {
    305     // This includes PRFM_lit.
    306     return Mask(LoadLiteralFMask) == LoadLiteralFixed;
    307   }
    308 
    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",
    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.
    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.
    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 
    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>
    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 
    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 
    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 
    456   float GetLiteralFP32() const { return RawbitsToFloat(GetLiteral32()); }
    457   VIXL_DEPRECATED("GetLiteralFP32", float LiteralFP32() const) {
    458     return GetLiteralFP32();
    459   }
    460 
    461   double GetLiteralFP64() const { return RawbitsToDouble(GetLiteral64()); }
    462   VIXL_DEPRECATED("GetLiteralFP64", double LiteralFP64() const) {
    463     return GetLiteralFP64();
    464   }
    465 
    466   const Instruction* GetNextInstruction() const {
    467     return this + kInstructionSize;
    468   }
    469   VIXL_DEPRECATED("GetNextInstruction",
    470                   const Instruction* NextInstruction() const) {
    471     return GetNextInstruction();
    472   }
    473 
    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>
    485   static Instruction* Cast(T src) {
    486     return reinterpret_cast<Instruction*>(src);
    487   }
    488 
    489   template <typename T>
    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.
    587   explicit NEONFormatDecoder(const Instruction* instr) {
    588     instrbits_ = instr->GetInstructionBits();
    589     SetFormatMaps(IntegerFormatMap());
    590   }
    591   NEONFormatDecoder(const Instruction* instr, const NEONFormatMap* format) {
    592     instrbits_ = instr->GetInstructionBits();
    593     SetFormatMaps(format);
    594   }
    595   NEONFormatDecoder(const Instruction* instr,
    596                     const NEONFormatMap* format0,
    597                     const NEONFormatMap* format1) {
    598     instrbits_ = instr->GetInstructionBits();
    599     SetFormatMaps(format0, format1);
    600   }
    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   }
    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.
    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.
    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 
    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.
    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 &map;
    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.
    690   static const NEONFormatMap* LongIntegerFormatMap() {
    691     static const NEONFormatMap map = {{23, 22}, {NF_8H, NF_4S, NF_2D}};
    692     return &map;
    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.
    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 &map;
    703   }
    704 
    705   // The load/store format map uses three bits (Q, 11, 10) to encode the
    706   // set of NEON vector formats.
    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 &map;
    712   }
    713 
    714   // The logical format map uses one bit (Q) to encode the NEON vector format:
    715   // NF_8B, NF_16B.
    716   static const NEONFormatMap* LogicalFormatMap() {
    717     static const NEONFormatMap map = {{30}, {NF_8B, NF_16B}};
    718     return &map;
    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.
    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 &map;
    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.
    737   static const NEONFormatMap* ScalarFormatMap() {
    738     static const NEONFormatMap map = {{23, 22}, {NF_B, NF_H, NF_S, NF_D}};
    739     return &map;
    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.
    744   static const NEONFormatMap* LongScalarFormatMap() {
    745     static const NEONFormatMap map = {{23, 22}, {NF_H, NF_S, NF_D}};
    746     return &map;
    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.
    751   static const NEONFormatMap* FPScalarFormatMap() {
    752     static const NEONFormatMap map = {{22}, {NF_S, NF_D}};
    753     return &map;
    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.
    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 &map;
    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.
    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.
    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.
    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.
    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.
    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