tor-browser

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

Registers-vixl.h (35996B)


      1 // Copyright 2019, 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_REGISTERS_A64_H_
     28 #define VIXL_A64_REGISTERS_A64_H_
     29 
     30 #include "jit/arm64/Architecture-arm64.h"
     31 #include "jit/arm64/vixl/Instructions-vixl.h"
     32 #include "jit/Registers.h"
     33 
     34 namespace vixl {
     35 
     36 // An integer type capable of representing a homogeneous, non-overlapping set of
     37 // registers as a bitmask of their codes.
     38 typedef uint64_t RegList;
     39 static const int kRegListSizeInBits = sizeof(RegList) * 8;
     40 
     41 class Register;
     42 class WRegister;
     43 class XRegister;
     44 
     45 class VRegister;
     46 class BRegister;
     47 class HRegister;
     48 class SRegister;
     49 class DRegister;
     50 class QRegister;
     51 
     52 class ZRegister;
     53 
     54 class PRegister;
     55 class PRegisterWithLaneSize;
     56 class PRegisterM;
     57 class PRegisterZ;
     58 
     59 // A container for any single register supported by the processor. Selected
     60 // qualifications are also supported. Basic registers can be constructed
     61 // directly as CPURegister objects. Other variants should be constructed as one
     62 // of the derived classes.
     63 //
     64 // CPURegister aims to support any getter that would also be available to more
     65 // specialised register types. However, using the equivalent functions on the
     66 // specialised register types can avoid run-time checks, and should therefore be
     67 // preferred where run-time polymorphism isn't required.
     68 //
     69 // Type-specific modifiers are typically implemented only on the derived
     70 // classes.
     71 //
     72 // The encoding is such that CPURegister objects are cheap to pass by value.
     73 class CPURegister {
     74 public:
     75  enum RegisterBank : uint8_t {
     76    kNoRegisterBank = 0,
     77    kRRegisterBank,
     78    kVRegisterBank,
     79    kPRegisterBank
     80  };
     81  enum RegisterType {
     82    kNoRegister,
     83    kRegister,
     84    kVRegister,
     85    kZRegister,
     86    kPRegister
     87  };
     88 
     89  static const unsigned kUnknownSize = 0;
     90 
     91  VIXL_CONSTEXPR CPURegister()
     92      : code_(0),
     93        bank_(kNoRegisterBank),
     94        size_(kEncodedUnknownSize),
     95        qualifiers_(kNoQualifiers),
     96        lane_size_(kEncodedUnknownSize) {}
     97 
     98  constexpr CPURegister(int code, int size_in_bits, RegisterType type)
     99      : code_(code),
    100        bank_(GetBankFor(type)),
    101        size_(EncodeSizeInBits(size_in_bits)),
    102        qualifiers_(kNoQualifiers),
    103        lane_size_(EncodeSizeInBits(size_in_bits)) {
    104    VIXL_ASSERT(IsValid());
    105  }
    106 
    107  // Basic accessors.
    108 
    109  // TODO: Make this return 'int'.
    110  unsigned GetCode() const { return code_; }
    111  unsigned code() const { return GetCode(); }
    112 
    113  RegisterBank GetBank() const { return bank_; }
    114 
    115  // For scalar registers, the lane size matches the register size, and is
    116  // always known.
    117  constexpr bool HasSize() const { return size_ != kEncodedUnknownSize; }
    118  constexpr bool HasLaneSize() const { return lane_size_ != kEncodedUnknownSize; }
    119 
    120  RegList GetBit() const {
    121    if (IsNone()) return 0;
    122    VIXL_ASSERT(code_ < kRegListSizeInBits);
    123    return static_cast<RegList>(1) << code_;
    124  }
    125  RegList Bit() const { return GetBit(); }
    126 
    127  // Return the highest valid register code for this type, to allow generic
    128  // loops to be written. This excludes kSPRegInternalCode, since it is not
    129  // contiguous, and sp usually requires special handling anyway.
    130  unsigned GetMaxCode() const { return GetMaxCodeFor(GetBank()); }
    131 
    132  // Registers without a known size report kUnknownSize.
    133  int GetSizeInBits() const { return DecodeSizeInBits(size_); }
    134  unsigned size() const {     return GetSizeInBits(); }
    135  int SizeInBits() const { return GetSizeInBits(); }
    136  int GetSizeInBytes() const { return DecodeSizeInBytes(size_); }
    137  int SizeInBytes() const { return GetSizeInBytes(); }
    138  // TODO: Make these return 'int'.
    139  unsigned GetLaneSizeInBits() const { return DecodeSizeInBits(lane_size_); }
    140  unsigned LaneSizeInBits() const { return GetLaneSizeInBits(); }
    141  unsigned GetLaneSizeInBytes() const { return DecodeSizeInBytes(lane_size_); }
    142  unsigned LaneSizeInBytes() const { return GetLaneSizeInBytes(); }
    143  unsigned GetLaneSizeInBytesLog2() const {
    144    VIXL_ASSERT(HasLaneSize());
    145    return DecodeSizeInBytesLog2(lane_size_);
    146  }
    147  unsigned LaneSizeInBytesLog2() const { return GetLaneSizeInBytesLog2(); }
    148 
    149  int GetLanes() const {
    150    if (HasSize() && HasLaneSize()) {
    151      // Take advantage of the size encoding to calculate this efficiently.
    152      VIXL_STATIC_ASSERT(kEncodedHRegSize == (kEncodedBRegSize + 1));
    153      VIXL_STATIC_ASSERT(kEncodedSRegSize == (kEncodedHRegSize + 1));
    154      VIXL_STATIC_ASSERT(kEncodedDRegSize == (kEncodedSRegSize + 1));
    155      VIXL_STATIC_ASSERT(kEncodedQRegSize == (kEncodedDRegSize + 1));
    156      int log2_delta = static_cast<int>(size_) - static_cast<int>(lane_size_);
    157      VIXL_ASSERT(log2_delta >= 0);
    158      return 1 << log2_delta;
    159    }
    160    return kUnknownSize;
    161  }
    162  int lanes() const { return GetLanes(); }
    163 
    164  bool Is8Bits() const { return size_ == kEncodedBRegSize; }
    165  bool Is16Bits() const { return size_ == kEncodedHRegSize; }
    166  bool Is32Bits() const { return size_ == kEncodedSRegSize; }
    167  bool Is64Bits() const { return size_ == kEncodedDRegSize; }
    168  bool Is128Bits() const { return size_ == kEncodedQRegSize; }
    169 
    170  bool IsLaneSizeB() const { return lane_size_ == kEncodedBRegSize; }
    171  bool IsLaneSizeH() const { return lane_size_ == kEncodedHRegSize; }
    172  bool IsLaneSizeS() const { return lane_size_ == kEncodedSRegSize; }
    173  bool IsLaneSizeD() const { return lane_size_ == kEncodedDRegSize; }
    174  bool IsLaneSizeQ() const { return lane_size_ == kEncodedQRegSize; }
    175 
    176  // If Is<Foo>Register(), then it is valid to convert the CPURegister to some
    177  // <Foo>Register<Bar> type.
    178  //
    179  //  If...                              ... then it is safe to construct ...
    180  //      r.IsRegister()                       -> Register(r)
    181  //      r.IsVRegister()                      -> VRegister(r)
    182  //      r.IsZRegister()                      -> ZRegister(r)
    183  //      r.IsPRegister()                      -> PRegister(r)
    184  //
    185  //      r.IsPRegister() && HasLaneSize()     -> PRegisterWithLaneSize(r)
    186  //      r.IsPRegister() && IsMerging()       -> PRegisterM(r)
    187  //      r.IsPRegister() && IsZeroing()       -> PRegisterZ(r)
    188  bool IsRegister() const { return GetType() == kRegister; }
    189  bool IsVRegister() const { return GetType() == kVRegister; }
    190  bool IsZRegister() const { return GetType() == kZRegister; }
    191  bool IsPRegister() const { return GetType() == kPRegister; }
    192 
    193  bool IsNone() const { return GetType() == kNoRegister; }
    194 
    195  // `GetType() == kNoRegister` implies IsNone(), and vice-versa.
    196  // `GetType() == k<Foo>Register` implies Is<Foo>Register(), and vice-versa.
    197  RegisterType GetType() const {
    198    switch (bank_) {
    199      case kNoRegisterBank:
    200        return kNoRegister;
    201      case kRRegisterBank:
    202        return kRegister;
    203      case kVRegisterBank:
    204        return HasSize() ? kVRegister : kZRegister;
    205      case kPRegisterBank:
    206        return kPRegister;
    207    }
    208    VIXL_UNREACHABLE();
    209    return kNoRegister;
    210  }
    211 
    212  // IsFPRegister() is true for scalar FP types (and therefore implies
    213  // IsVRegister()). There is no corresponding FPRegister type.
    214  bool IsFPRegister() const { return Is1H() || Is1S() || Is1D(); }
    215 
    216  // TODO: These are stricter forms of the helpers above. We should make the
    217  // basic helpers strict, and remove these.
    218  constexpr bool IsValidRegister() const {
    219    return ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)) &&
    220           (bank_ == kRRegisterBank) &&
    221           ((size_ == kEncodedWRegSize) || (size_ == kEncodedXRegSize)) &&
    222           (qualifiers_ == kNoQualifiers) && (lane_size_ == size_);
    223  }
    224  constexpr bool IsValidVRegister() const {
    225    VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
    226    return (code_ < kNumberOfVRegisters) && (bank_ == kVRegisterBank) &&
    227           ((size_ >= kEncodedBRegSize) && (size_ <= kEncodedQRegSize)) &&
    228           (qualifiers_ == kNoQualifiers) &&
    229           (lane_size_ != kEncodedUnknownSize) && (lane_size_ <= size_);
    230  }
    231  constexpr bool IsValidFPRegister() const {
    232    return IsValidVRegister() && IsFPRegister();
    233  }
    234  constexpr bool IsValidZRegister() const {
    235    VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
    236    // Z registers are valid with or without a lane size, so we don't need to
    237    // check lane_size_.
    238    return (code_ < kNumberOfZRegisters) && (bank_ == kVRegisterBank) &&
    239           (size_ == kEncodedUnknownSize) && (qualifiers_ == kNoQualifiers);
    240  }
    241  constexpr bool IsValidPRegister() const {
    242    VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
    243    // P registers are valid with or without a lane size, so we don't need to
    244    // check lane_size_.
    245    return (code_ < kNumberOfPRegisters) && (bank_ == kPRegisterBank) &&
    246           (size_ == kEncodedUnknownSize) &&
    247           ((qualifiers_ == kNoQualifiers) || (qualifiers_ == kMerging) ||
    248            (qualifiers_ == kZeroing));
    249  }
    250 
    251  constexpr bool IsValid() const {
    252    return IsValidRegister() || IsValidVRegister() || IsValidZRegister() ||
    253           IsValidPRegister();
    254  }
    255  bool IsValidOrNone() const { return IsNone() || IsValid(); }
    256 
    257  bool IsVector() const { return HasLaneSize() && (size_ != lane_size_); }
    258  bool IsScalar() const { return HasLaneSize() && (size_ == lane_size_); }
    259 
    260  bool IsSameType(const CPURegister& other) const {
    261    return GetType() == other.GetType();
    262  }
    263 
    264  bool IsSameBank(const CPURegister& other) const {
    265    return GetBank() == other.GetBank();
    266  }
    267 
    268  // Two registers with unknown size are considered to have the same size if
    269  // they also have the same type. For example, all Z registers have the same
    270  // size, even though we don't know what that is.
    271  bool IsSameSizeAndType(const CPURegister& other) const {
    272    return IsSameType(other) && (size_ == other.size_);
    273  }
    274 
    275  bool IsSameFormat(const CPURegister& other) const {
    276    return IsSameSizeAndType(other) && (lane_size_ == other.lane_size_);
    277  }
    278 
    279  // Note that NoReg aliases itself, so that 'Is' implies 'Aliases'.
    280  bool Aliases(const CPURegister& other) const {
    281    return IsSameBank(other) && (code_ == other.code_);
    282  }
    283 
    284  bool Is(const CPURegister& other) const {
    285    if (IsRegister() || IsVRegister()) {
    286      // For core (W, X) and FP/NEON registers, we only consider the code, size
    287      // and type. This is legacy behaviour.
    288      // TODO: We should probably check every field for all registers.
    289      return Aliases(other) && (size_ == other.size_);
    290    } else {
    291      // For Z and P registers, we require all fields to match exactly.
    292      VIXL_ASSERT(IsNone() || IsZRegister() || IsPRegister());
    293      return (code_ == other.code_) && (bank_ == other.bank_) &&
    294             (size_ == other.size_) && (qualifiers_ == other.qualifiers_) &&
    295             (lane_size_ == other.lane_size_);
    296    }
    297  }
    298 
    299  // Conversions to specific register types. The result is a register that
    300  // aliases the original CPURegister. That is, the original register bank
    301  // (`GetBank()`) is checked and the code (`GetCode()`) preserved, but all
    302  // other properties are ignored.
    303  //
    304  // Typical usage:
    305  //
    306  //     if (reg.GetBank() == kVRegisterBank) {
    307  //       DRegister d = reg.D();
    308  //       ...
    309  //     }
    310  //
    311  // These could all return types with compile-time guarantees (like XRegister),
    312  // but this breaks backwards-compatibility quite severely, particularly with
    313  // code like `cond ? reg.W() : reg.X()`, which would have indeterminate type.
    314 
    315  // Core registers, like "w0".
    316  Register W() const;
    317  Register X() const;
    318  // FP/NEON registers, like "b0".
    319  VRegister B() const;
    320  VRegister H() const;
    321  VRegister S() const;
    322  VRegister D() const;
    323  VRegister Q() const;
    324  VRegister V() const;
    325  // SVE registers, like "z0".
    326  ZRegister Z() const;
    327  PRegister P() const;
    328 
    329  // Utilities for kRegister types.
    330 
    331  bool IsZero() const { return IsRegister() && (code_ == kZeroRegCode); }
    332  bool IsSP() const { return IsRegister() && (code_ == kSPRegInternalCode); }
    333  bool IsW() const { return IsRegister() && Is32Bits(); }
    334  bool IsX() const { return IsRegister() && Is64Bits(); }
    335 
    336  // Utilities for FP/NEON kVRegister types.
    337 
    338  // These helpers ensure that the size and type of the register are as
    339  // described. They do not consider the number of lanes that make up a vector.
    340  // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
    341  // does not imply Is1D() or Is8B().
    342  // Check the number of lanes, ie. the format of the vector, using methods such
    343  // as Is8B(), Is1D(), etc.
    344  bool IsB() const { return IsVRegister() && Is8Bits(); }
    345  bool IsH() const { return IsVRegister() && Is16Bits(); }
    346  bool IsS() const { return IsVRegister() && Is32Bits(); }
    347  bool IsD() const { return IsVRegister() && Is64Bits(); }
    348  bool IsQ() const { return IsVRegister() && Is128Bits(); }
    349 
    350  // As above, but also check that the register has exactly one lane. For
    351  // example, reg.Is1D() implies DRegister(reg).IsValid(), but reg.IsD() does
    352  // not.
    353  bool Is1B() const { return IsB() && IsScalar(); }
    354  bool Is1H() const { return IsH() && IsScalar(); }
    355  bool Is1S() const { return IsS() && IsScalar(); }
    356  bool Is1D() const { return IsD() && IsScalar(); }
    357  bool Is1Q() const { return IsQ() && IsScalar(); }
    358 
    359  // Check the specific NEON format.
    360  bool Is8B() const { return IsD() && IsLaneSizeB(); }
    361  bool Is16B() const { return IsQ() && IsLaneSizeB(); }
    362  bool Is2H() const { return IsS() && IsLaneSizeH(); }
    363  bool Is4H() const { return IsD() && IsLaneSizeH(); }
    364  bool Is8H() const { return IsQ() && IsLaneSizeH(); }
    365  bool Is2S() const { return IsD() && IsLaneSizeS(); }
    366  bool Is4S() const { return IsQ() && IsLaneSizeS(); }
    367  bool Is2D() const { return IsQ() && IsLaneSizeD(); }
    368 
    369  // A semantic alias for sdot and udot (indexed and by element) instructions.
    370  // The current CPURegister implementation cannot not tell this from Is1S(),
    371  // but it might do later.
    372  // TODO: Do this with the qualifiers_ field.
    373  bool Is1S4B() const { return Is1S(); }
    374 
    375  // Utilities for SVE registers.
    376 
    377  constexpr bool IsUnqualified() const { return qualifiers_ == kNoQualifiers; }
    378  constexpr bool IsMerging() const { return IsPRegister() && (qualifiers_ == kMerging); }
    379  constexpr bool IsZeroing() const { return IsPRegister() && (qualifiers_ == kZeroing); }
    380 
    381  // SVE types have unknown sizes, but within known bounds.
    382 
    383  int GetMaxSizeInBytes() const {
    384    switch (GetType()) {
    385      case kZRegister:
    386        return kZRegMaxSizeInBytes;
    387      case kPRegister:
    388        return kPRegMaxSizeInBytes;
    389      default:
    390        VIXL_ASSERT(HasSize());
    391        return GetSizeInBits();
    392    }
    393  }
    394 
    395  int GetMinSizeInBytes() const {
    396    switch (GetType()) {
    397      case kZRegister:
    398        return kZRegMinSizeInBytes;
    399      case kPRegister:
    400        return kPRegMinSizeInBytes;
    401      default:
    402        VIXL_ASSERT(HasSize());
    403        return GetSizeInBits();
    404    }
    405  }
    406 
    407  int GetMaxSizeInBits() const { return GetMaxSizeInBytes() * kBitsPerByte; }
    408  int GetMinSizeInBits() const { return GetMinSizeInBytes() * kBitsPerByte; }
    409 
    410  static constexpr RegisterBank GetBankFor(RegisterType type) {
    411    switch (type) {
    412      case kNoRegister:
    413        return kNoRegisterBank;
    414      case kRegister:
    415        return kRRegisterBank;
    416      case kVRegister:
    417      case kZRegister:
    418        return kVRegisterBank;
    419      case kPRegister:
    420        return kPRegisterBank;
    421    }
    422    VIXL_UNREACHABLE();
    423    return kNoRegisterBank;
    424  }
    425 
    426  static unsigned GetMaxCodeFor(CPURegister::RegisterType type) {
    427    return GetMaxCodeFor(GetBankFor(type));
    428  }
    429 
    430 protected:
    431  enum EncodedSize : uint8_t {
    432    // Ensure that kUnknownSize (and therefore kNoRegister) is encoded as zero.
    433    kEncodedUnknownSize = 0,
    434 
    435    // The implementation assumes that the remaining sizes are encoded as
    436    // `log2(size) + c`, so the following names must remain in sequence.
    437    kEncodedBRegSize,
    438    kEncodedHRegSize,
    439    kEncodedSRegSize,
    440    kEncodedDRegSize,
    441    kEncodedQRegSize,
    442 
    443    kEncodedWRegSize = kEncodedSRegSize,
    444    kEncodedXRegSize = kEncodedDRegSize
    445  };
    446  VIXL_STATIC_ASSERT(kSRegSize == kWRegSize);
    447  VIXL_STATIC_ASSERT(kDRegSize == kXRegSize);
    448 
    449  char GetLaneSizeSymbol() const {
    450    switch (lane_size_) {
    451      case kEncodedBRegSize:
    452        return 'B';
    453      case kEncodedHRegSize:
    454        return 'H';
    455      case kEncodedSRegSize:
    456        return 'S';
    457      case kEncodedDRegSize:
    458        return 'D';
    459      case kEncodedQRegSize:
    460        return 'Q';
    461      case kEncodedUnknownSize:
    462        break;
    463    }
    464    VIXL_UNREACHABLE();
    465    return '?';
    466  }
    467 
    468  static constexpr EncodedSize EncodeSizeInBits(int size_in_bits) {
    469    switch (size_in_bits) {
    470      case kUnknownSize:
    471        return kEncodedUnknownSize;
    472      case kBRegSize:
    473        return kEncodedBRegSize;
    474      case kHRegSize:
    475        return kEncodedHRegSize;
    476      case kSRegSize:
    477        return kEncodedSRegSize;
    478      case kDRegSize:
    479        return kEncodedDRegSize;
    480      case kQRegSize:
    481        return kEncodedQRegSize;
    482    }
    483    VIXL_UNREACHABLE();
    484    return kEncodedUnknownSize;
    485  }
    486 
    487  static int DecodeSizeInBytesLog2(EncodedSize encoded_size) {
    488    switch (encoded_size) {
    489      case kEncodedUnknownSize:
    490        // Log2 of B-sized lane in bytes is 0, so we can't just return 0 here.
    491        VIXL_UNREACHABLE();
    492        return -1;
    493      case kEncodedBRegSize:
    494        return kBRegSizeInBytesLog2;
    495      case kEncodedHRegSize:
    496        return kHRegSizeInBytesLog2;
    497      case kEncodedSRegSize:
    498        return kSRegSizeInBytesLog2;
    499      case kEncodedDRegSize:
    500        return kDRegSizeInBytesLog2;
    501      case kEncodedQRegSize:
    502        return kQRegSizeInBytesLog2;
    503    }
    504    VIXL_UNREACHABLE();
    505    return kUnknownSize;
    506  }
    507 
    508  static int DecodeSizeInBytes(EncodedSize encoded_size) {
    509    if (encoded_size == kEncodedUnknownSize) {
    510      return kUnknownSize;
    511    }
    512    return 1 << DecodeSizeInBytesLog2(encoded_size);
    513  }
    514 
    515  static int DecodeSizeInBits(EncodedSize encoded_size) {
    516    VIXL_STATIC_ASSERT(kUnknownSize == 0);
    517    return DecodeSizeInBytes(encoded_size) * kBitsPerByte;
    518  }
    519 
    520  static unsigned GetMaxCodeFor(CPURegister::RegisterBank bank);
    521 
    522  enum Qualifiers : uint8_t {
    523    kNoQualifiers = 0,
    524    // Used by P registers.
    525    kMerging,
    526    kZeroing
    527  };
    528 
    529  // An unchecked constructor, for use by derived classes.
    530  constexpr CPURegister(int code,
    531              EncodedSize size,
    532              RegisterBank bank,
    533              EncodedSize lane_size,
    534              Qualifiers qualifiers = kNoQualifiers)
    535      : code_(code),
    536        bank_(bank),
    537        size_(size),
    538        qualifiers_(qualifiers),
    539        lane_size_(lane_size) {}
    540 
    541  // TODO: Check that access to these fields is reasonably efficient.
    542  uint8_t code_;
    543  RegisterBank bank_;
    544  EncodedSize size_;
    545  Qualifiers qualifiers_;
    546  EncodedSize lane_size_;
    547 };
    548 // Ensure that CPURegisters can fit in a single (64-bit) register. This is a
    549 // proxy for being "cheap to pass by value", which is hard to check directly.
    550 VIXL_STATIC_ASSERT(sizeof(CPURegister) <= sizeof(uint64_t));
    551 
    552 // TODO: Add constexpr constructors.
    553 #define VIXL_DECLARE_REGISTER_COMMON(NAME, REGISTER_TYPE, PARENT_TYPE) \
    554  VIXL_CONSTEXPR NAME() : PARENT_TYPE() {}                             \
    555                                                                       \
    556  explicit constexpr NAME(CPURegister other) : PARENT_TYPE(other) {    \
    557    VIXL_ASSERT(IsValid());                                            \
    558  }                                                                    \
    559                                                                       \
    560  VIXL_CONSTEXPR static unsigned GetMaxCode() {                        \
    561    return kNumberOf##REGISTER_TYPE##s - 1;                            \
    562  }
    563 
    564 // Any W or X register, including the zero register and the stack pointer.
    565 class Register : public CPURegister {
    566 public:
    567  VIXL_DECLARE_REGISTER_COMMON(Register, Register, CPURegister)
    568 
    569  constexpr Register(int code, int size_in_bits)
    570      : CPURegister(code, size_in_bits, kRegister) {
    571    VIXL_ASSERT(IsValidRegister());
    572  }
    573 
    574  constexpr Register(js::jit::Register r, unsigned size_in_bits)
    575      : CPURegister(r.code(), size_in_bits, kRegister) {
    576    VIXL_ASSERT(IsValidRegister());
    577  }
    578 
    579  constexpr bool IsValid() const { return IsValidRegister(); }
    580 
    581  js::jit::Register asUnsized() const {
    582    // asUnsized() is only ever used on temp registers or on registers that
    583    // are known not to be SP, and there should be no risk of it being
    584    // applied to SP.  Check anyway.
    585    VIXL_ASSERT(code_ != kSPRegInternalCode);
    586    return js::jit::Register::FromCode((js::jit::Register::Code)code_);
    587  }
    588 };
    589 
    590 // Any FP or NEON V register, including vector (V.<T>) and scalar forms
    591 // (B, H, S, D, Q).
    592 class VRegister : public CPURegister {
    593 public:
    594  VIXL_DECLARE_REGISTER_COMMON(VRegister, VRegister, CPURegister)
    595 
    596  // For historical reasons, VRegister(0) returns v0.1Q (or equivalently, q0).
    597  explicit constexpr VRegister(int code, int size_in_bits = kQRegSize, int lanes = 1)
    598      : CPURegister(code,
    599                    EncodeSizeInBits(size_in_bits),
    600                    kVRegisterBank,
    601                    EncodeLaneSizeInBits(size_in_bits, lanes)) {
    602    VIXL_ASSERT(IsValidVRegister());
    603  }
    604 
    605  VRegister(int code, VectorFormat format)
    606      : CPURegister(code,
    607                    EncodeSizeInBits(RegisterSizeInBitsFromFormat(format)),
    608                    kVRegisterBank,
    609                    EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
    610                    kNoQualifiers) {
    611    VIXL_ASSERT(IsValid());
    612  }
    613 
    614  constexpr VRegister(js::jit::FloatRegister r)
    615      : CPURegister(r.encoding(), r.size() * 8, kVRegister) {
    616    VIXL_ASSERT(IsValid());
    617  }
    618  constexpr VRegister(js::jit::FloatRegister r, unsigned size_in_bits)
    619      : CPURegister(r.encoding(), size_in_bits, kVRegister) {
    620    VIXL_ASSERT(IsValid());
    621  }
    622 
    623  VRegister V8B() const;
    624  VRegister V16B() const;
    625  VRegister V2H() const;
    626  VRegister V4H() const;
    627  VRegister V8H() const;
    628  VRegister V2S() const;
    629  VRegister V4S() const;
    630  VRegister V1D() const;
    631  VRegister V2D() const;
    632  VRegister V1Q() const;
    633  VRegister S4B() const;
    634 
    635  constexpr bool IsValid() const { return IsValidVRegister(); }
    636 
    637 protected:
    638  static constexpr EncodedSize EncodeLaneSizeInBits(int size_in_bits, int lanes) {
    639    VIXL_ASSERT(lanes >= 1);
    640    VIXL_ASSERT((size_in_bits % lanes) == 0);
    641    return EncodeSizeInBits(size_in_bits / lanes);
    642  }
    643 };
    644 
    645 // Backward compatibility for FPRegisters.
    646 typedef VRegister FPRegister;
    647 
    648 // Any SVE Z register, with or without a lane size specifier.
    649 class ZRegister : public CPURegister {
    650 public:
    651  VIXL_DECLARE_REGISTER_COMMON(ZRegister, ZRegister, CPURegister)
    652 
    653  explicit constexpr ZRegister(int code, int lane_size_in_bits = kUnknownSize)
    654      : CPURegister(code,
    655                    kEncodedUnknownSize,
    656                    kVRegisterBank,
    657                    EncodeSizeInBits(lane_size_in_bits)) {
    658    VIXL_ASSERT(IsValid());
    659  }
    660 
    661  ZRegister(int code, VectorFormat format)
    662      : CPURegister(code,
    663                    kEncodedUnknownSize,
    664                    kVRegisterBank,
    665                    EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
    666                    kNoQualifiers) {
    667    VIXL_ASSERT(IsValid());
    668  }
    669 
    670  // Return a Z register with a known lane size (like "z0.B").
    671  ZRegister VnB() const { return ZRegister(GetCode(), kBRegSize); }
    672  ZRegister VnH() const { return ZRegister(GetCode(), kHRegSize); }
    673  ZRegister VnS() const { return ZRegister(GetCode(), kSRegSize); }
    674  ZRegister VnD() const { return ZRegister(GetCode(), kDRegSize); }
    675  ZRegister VnQ() const { return ZRegister(GetCode(), kQRegSize); }
    676 
    677  template <typename T>
    678  ZRegister WithLaneSize(T format) const {
    679    return ZRegister(GetCode(), format);
    680  }
    681 
    682  ZRegister WithSameLaneSizeAs(const CPURegister& other) const {
    683    VIXL_ASSERT(other.HasLaneSize());
    684    return this->WithLaneSize(other.GetLaneSizeInBits());
    685  }
    686 
    687  constexpr bool IsValid() const { return IsValidZRegister(); }
    688 };
    689 
    690 // Any SVE P register, with or without a qualifier or lane size specifier.
    691 class PRegister : public CPURegister {
    692 public:
    693  VIXL_DECLARE_REGISTER_COMMON(PRegister, PRegister, CPURegister)
    694 
    695  explicit constexpr PRegister(int code) : CPURegister(code, kUnknownSize, kPRegister) {
    696    VIXL_ASSERT(IsValid());
    697  }
    698 
    699  constexpr bool IsValid() const {
    700    return IsValidPRegister() && !HasLaneSize() && IsUnqualified();
    701  }
    702 
    703  // Return a P register with a known lane size (like "p0.B").
    704  PRegisterWithLaneSize VnB() const;
    705  PRegisterWithLaneSize VnH() const;
    706  PRegisterWithLaneSize VnS() const;
    707  PRegisterWithLaneSize VnD() const;
    708 
    709  template <typename T>
    710  PRegisterWithLaneSize WithLaneSize(T format) const;
    711 
    712  PRegisterWithLaneSize WithSameLaneSizeAs(const CPURegister& other) const;
    713 
    714  // SVE predicates are specified (in normal assembly) with a "/z" (zeroing) or
    715  // "/m" (merging) suffix. These methods are VIXL's equivalents.
    716  PRegisterZ Zeroing() const;
    717  PRegisterM Merging() const;
    718 
    719 protected:
    720  // Unchecked constructors, for use by derived classes.
    721  constexpr PRegister(int code, EncodedSize encoded_lane_size)
    722      : CPURegister(code,
    723                    kEncodedUnknownSize,
    724                    kPRegisterBank,
    725                    encoded_lane_size,
    726                    kNoQualifiers) {}
    727 
    728  constexpr PRegister(int code, Qualifiers qualifiers)
    729      : CPURegister(code,
    730                    kEncodedUnknownSize,
    731                    kPRegisterBank,
    732                    kEncodedUnknownSize,
    733                    qualifiers) {}
    734 };
    735 
    736 // Any SVE P register with a known lane size (like "p0.B").
    737 class PRegisterWithLaneSize : public PRegister {
    738 public:
    739  VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize, PRegister, PRegister)
    740 
    741  constexpr PRegisterWithLaneSize(int code, int lane_size_in_bits)
    742      : PRegister(code, EncodeSizeInBits(lane_size_in_bits)) {
    743    VIXL_ASSERT(IsValid());
    744  }
    745 
    746  PRegisterWithLaneSize(int code, VectorFormat format)
    747      : PRegister(code, EncodeSizeInBits(LaneSizeInBitsFromFormat(format))) {
    748    VIXL_ASSERT(IsValid());
    749  }
    750 
    751  bool IsValid() const {
    752    return IsValidPRegister() && HasLaneSize() && IsUnqualified();
    753  }
    754 
    755  // Overload lane size accessors so we can assert `HasLaneSize()`. This allows
    756  // tools such as clang-tidy to prove that the result of GetLaneSize* is
    757  // non-zero.
    758 
    759  // TODO: Make these return 'int'.
    760  unsigned GetLaneSizeInBits() const {
    761    VIXL_ASSERT(HasLaneSize());
    762    return PRegister::GetLaneSizeInBits();
    763  }
    764 
    765  unsigned GetLaneSizeInBytes() const {
    766    VIXL_ASSERT(HasLaneSize());
    767    return PRegister::GetLaneSizeInBytes();
    768  }
    769 };
    770 
    771 // Any SVE P register with the zeroing qualifier (like "p0/z").
    772 class PRegisterZ : public PRegister {
    773 public:
    774  VIXL_DECLARE_REGISTER_COMMON(PRegisterZ, PRegister, PRegister)
    775 
    776  explicit constexpr PRegisterZ(int code) : PRegister(code, kZeroing) {
    777    VIXL_ASSERT(IsValid());
    778  }
    779 
    780  bool IsValid() const {
    781    return IsValidPRegister() && !HasLaneSize() && IsZeroing();
    782  }
    783 };
    784 
    785 // Any SVE P register with the merging qualifier (like "p0/m").
    786 class PRegisterM : public PRegister {
    787 public:
    788  VIXL_DECLARE_REGISTER_COMMON(PRegisterM, PRegister, PRegister)
    789 
    790  explicit constexpr PRegisterM(int code) : PRegister(code, kMerging) {
    791    VIXL_ASSERT(IsValid());
    792  }
    793 
    794  bool IsValid() const {
    795    return IsValidPRegister() && !HasLaneSize() && IsMerging();
    796  }
    797 };
    798 
    799 inline PRegisterWithLaneSize PRegister::VnB() const {
    800  return PRegisterWithLaneSize(GetCode(), kBRegSize);
    801 }
    802 inline PRegisterWithLaneSize PRegister::VnH() const {
    803  return PRegisterWithLaneSize(GetCode(), kHRegSize);
    804 }
    805 inline PRegisterWithLaneSize PRegister::VnS() const {
    806  return PRegisterWithLaneSize(GetCode(), kSRegSize);
    807 }
    808 inline PRegisterWithLaneSize PRegister::VnD() const {
    809  return PRegisterWithLaneSize(GetCode(), kDRegSize);
    810 }
    811 
    812 template <typename T>
    813 inline PRegisterWithLaneSize PRegister::WithLaneSize(T format) const {
    814  return PRegisterWithLaneSize(GetCode(), format);
    815 }
    816 
    817 inline PRegisterWithLaneSize PRegister::WithSameLaneSizeAs(
    818    const CPURegister& other) const {
    819  VIXL_ASSERT(other.HasLaneSize());
    820  return this->WithLaneSize(other.GetLaneSizeInBits());
    821 }
    822 
    823 inline PRegisterZ PRegister::Zeroing() const { return PRegisterZ(GetCode()); }
    824 inline PRegisterM PRegister::Merging() const { return PRegisterM(GetCode()); }
    825 
    826 #define VIXL_REGISTER_WITH_SIZE_LIST(V) \
    827  V(WRegister, kWRegSize, Register)     \
    828  V(XRegister, kXRegSize, Register)     \
    829  V(QRegister, kQRegSize, VRegister)    \
    830  V(DRegister, kDRegSize, VRegister)    \
    831  V(SRegister, kSRegSize, VRegister)    \
    832  V(HRegister, kHRegSize, VRegister)    \
    833  V(BRegister, kBRegSize, VRegister)
    834 
    835 #define VIXL_DEFINE_REGISTER_WITH_SIZE(NAME, SIZE, PARENT)           \
    836  class NAME : public PARENT {                                       \
    837   public:                                                           \
    838    VIXL_CONSTEXPR NAME() : PARENT() {}                              \
    839    explicit constexpr NAME(int code) : PARENT(code, SIZE) {}        \
    840                                                                     \
    841    explicit constexpr NAME(PARENT other) : PARENT(other) {          \
    842      VIXL_ASSERT(GetSizeInBits() == SIZE);                          \
    843    }                                                                \
    844                                                                     \
    845    PARENT As##PARENT() const { return *this; }                      \
    846                                                                     \
    847    VIXL_CONSTEXPR int GetSizeInBits() const { return SIZE; }        \
    848                                                                     \
    849    constexpr bool IsValid() const {                                 \
    850      return PARENT::IsValid() && (PARENT::GetSizeInBits() == SIZE); \
    851    }                                                                \
    852  };
    853 
    854 VIXL_REGISTER_WITH_SIZE_LIST(VIXL_DEFINE_REGISTER_WITH_SIZE)
    855 
    856 // No*Reg is used to provide default values for unused arguments, error cases
    857 // and so on. Note that these (and the default constructors) all compare equal
    858 // (using the Is() method).
    859 constexpr Register NoReg;
    860 constexpr VRegister NoVReg;
    861 constexpr CPURegister NoCPUReg;
    862 constexpr ZRegister NoZReg;
    863 
    864 // TODO: Ideally, these would use specialised register types (like XRegister and
    865 // so on). However, doing so throws up template overloading problems elsewhere.
    866 #define VIXL_DEFINE_REGISTERS(N)           \
    867  constexpr Register w##N = WRegister(N);  \
    868  constexpr Register x##N = XRegister(N);  \
    869  constexpr VRegister b##N = BRegister(N); \
    870  constexpr VRegister h##N = HRegister(N); \
    871  constexpr VRegister s##N = SRegister(N); \
    872  constexpr VRegister d##N = DRegister(N); \
    873  constexpr VRegister q##N = QRegister(N); \
    874  constexpr VRegister v##N(N);             \
    875  constexpr ZRegister z##N(N);
    876 AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS)
    877 #undef VIXL_DEFINE_REGISTERS
    878 
    879 #define VIXL_DEFINE_P_REGISTERS(N) const PRegister p##N(N);
    880 AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS)
    881 #undef VIXL_DEFINE_P_REGISTERS
    882 
    883 // VIXL represents 'sp' with a unique code, to tell it apart from 'xzr'.
    884 constexpr Register wsp = WRegister(kSPRegInternalCode);
    885 constexpr Register sp = XRegister(kSPRegInternalCode);
    886 
    887 // Standard aliases.
    888 constexpr Register ip0 = x16;
    889 constexpr Register ip1 = x17;
    890 constexpr Register lr = x30;
    891 constexpr Register xzr = x31;
    892 constexpr Register wzr = w31;
    893 
    894 // AreAliased returns true if any of the named registers overlap. Arguments
    895 // set to NoReg are ignored. The system stack pointer may be specified.
    896 bool AreAliased(const CPURegister& reg1,
    897                const CPURegister& reg2,
    898                const CPURegister& reg3 = NoReg,
    899                const CPURegister& reg4 = NoReg,
    900                const CPURegister& reg5 = NoReg,
    901                const CPURegister& reg6 = NoReg,
    902                const CPURegister& reg7 = NoReg,
    903                const CPURegister& reg8 = NoReg);
    904 
    905 // AreSameSizeAndType returns true if all of the specified registers have the
    906 // same size, and are of the same type. The system stack pointer may be
    907 // specified. Arguments set to NoReg are ignored, as are any subsequent
    908 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
    909 bool AreSameSizeAndType(const CPURegister& reg1,
    910                        const CPURegister& reg2,
    911                        const CPURegister& reg3 = NoCPUReg,
    912                        const CPURegister& reg4 = NoCPUReg,
    913                        const CPURegister& reg5 = NoCPUReg,
    914                        const CPURegister& reg6 = NoCPUReg,
    915                        const CPURegister& reg7 = NoCPUReg,
    916                        const CPURegister& reg8 = NoCPUReg);
    917 
    918 // AreEven returns true if all of the specified registers have even register
    919 // indices. Arguments set to NoReg are ignored, as are any subsequent
    920 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
    921 bool AreEven(const CPURegister& reg1,
    922             const CPURegister& reg2,
    923             const CPURegister& reg3 = NoReg,
    924             const CPURegister& reg4 = NoReg,
    925             const CPURegister& reg5 = NoReg,
    926             const CPURegister& reg6 = NoReg,
    927             const CPURegister& reg7 = NoReg,
    928             const CPURegister& reg8 = NoReg);
    929 
    930 // AreConsecutive returns true if all of the specified registers are
    931 // consecutive in the register file. Arguments set to NoReg are ignored, as are
    932 // any subsequent arguments. At least one argument (reg1) must be valid
    933 // (not NoCPUReg).
    934 bool AreConsecutive(const CPURegister& reg1,
    935                    const CPURegister& reg2,
    936                    const CPURegister& reg3 = NoCPUReg,
    937                    const CPURegister& reg4 = NoCPUReg);
    938 
    939 // AreSameFormat returns true if all of the specified registers have the same
    940 // vector format. Arguments set to NoReg are ignored, as are any subsequent
    941 // arguments. At least one argument (reg1) must be valid (not NoVReg).
    942 bool AreSameFormat(const CPURegister& reg1,
    943                   const CPURegister& reg2,
    944                   const CPURegister& reg3 = NoCPUReg,
    945                   const CPURegister& reg4 = NoCPUReg);
    946 
    947 // AreSameLaneSize returns true if all of the specified registers have the same
    948 // element lane size, B, H, S or D. It doesn't compare the type of registers.
    949 // Arguments set to NoReg are ignored, as are any subsequent arguments.
    950 // At least one argument (reg1) must be valid (not NoVReg).
    951 // TODO: Remove this, and replace its uses with AreSameFormat.
    952 bool AreSameLaneSize(const CPURegister& reg1,
    953                     const CPURegister& reg2,
    954                     const CPURegister& reg3 = NoCPUReg,
    955                     const CPURegister& reg4 = NoCPUReg);
    956 }  // namespace vixl
    957 
    958 #endif  // VIXL_A64_REGISTERS_A64_H_