tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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 &map;
   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_