tor-browser

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

Architecture-arm.h (25163B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_arm_Architecture_arm_h
      8 #define jit_arm_Architecture_arm_h
      9 
     10 #include "mozilla/EnumSet.h"
     11 #include "mozilla/MathAlgorithms.h"
     12 
     13 #include <algorithm>
     14 #include <limits.h>
     15 #include <stdint.h>
     16 
     17 #include "jit/shared/Architecture-shared.h"
     18 
     19 #include "js/Utility.h"
     20 
     21 namespace js {
     22 namespace jit {
     23 
     24 // These offsets are specific to nunboxing, and capture offsets into the
     25 // components of a js::Value.
     26 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
     27 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
     28 
     29 static constexpr uint32_t ShadowStackSpace = 0;
     30 
     31 // How far forward/back can a jump go? Provide a generous buffer for thunks.
     32 static const uint32_t JumpImmediateRange = 20 * 1024 * 1024;
     33 
     34 class Registers {
     35 public:
     36  enum RegisterID {
     37    r0 = 0,
     38    r1,
     39    r2,
     40    r3,
     41    r4,
     42    r5,
     43    r6,
     44    r7,
     45    r8,
     46    r9,
     47    r10,
     48    r11,
     49    fp = r11,
     50    r12,
     51    ip = r12,
     52    r13,
     53    sp = r13,
     54    r14,
     55    lr = r14,
     56    r15,
     57    pc = r15,
     58    invalid_reg
     59  };
     60  using Code = uint8_t;
     61  using Encoding = RegisterID;
     62 
     63  // Content spilled during bailouts.
     64  union RegisterContent {
     65    uintptr_t r;
     66  };
     67 
     68  static const char* GetName(Code code) {
     69    MOZ_ASSERT(code < Total);
     70    static const char* const Names[] = {"r0",  "r1", "r2",  "r3", "r4",  "r5",
     71                                        "r6",  "r7", "r8",  "r9", "r10", "r11",
     72                                        "r12", "sp", "r14", "pc"};
     73    return Names[code];
     74  }
     75  static const char* GetName(Encoding i) { return GetName(Code(i)); }
     76 
     77  static Code FromName(const char* name);
     78 
     79  static const Encoding StackPointer = sp;
     80  static const Encoding Invalid = invalid_reg;
     81 
     82  static const uint32_t Total = 16;
     83  static const uint32_t Allocatable = 13;
     84 
     85  using SetType = uint32_t;
     86 
     87  static const SetType AllMask = (1 << Total) - 1;
     88  static const SetType ArgRegMask =
     89      (1 << r0) | (1 << r1) | (1 << r2) | (1 << r3);
     90 
     91  static const SetType VolatileMask =
     92      (1 << r0) | (1 << r1) | (1 << Registers::r2) |
     93      (1 << Registers::r3)
     94 #if defined(XP_IOS)
     95      // per
     96      // https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW4
     97      | (1 << Registers::r9)
     98 #endif
     99      ;
    100 
    101  static const SetType NonVolatileMask =
    102      (1 << Registers::r4) | (1 << Registers::r5) | (1 << Registers::r6) |
    103      (1 << Registers::r7) | (1 << Registers::r8) |
    104 #if !defined(XP_IOS)
    105      (1 << Registers::r9) |
    106 #endif
    107      (1 << Registers::r10) | (1 << Registers::r11) | (1 << Registers::r12) |
    108      (1 << Registers::r14);
    109 
    110  static const SetType WrapperMask = VolatileMask |          // = arguments
    111                                     (1 << Registers::r4) |  // = outReg
    112                                     (1 << Registers::r5);   // = argBase
    113 
    114  static const SetType NonAllocatableMask =
    115      (1 << Registers::sp) | (1 << Registers::r12) |  // r12 = ip = scratch
    116      (1 << Registers::lr) | (1 << Registers::pc) | (1 << Registers::fp);
    117 
    118  // Registers returned from a JS -> JS call.
    119  static const SetType JSCallMask = (1 << Registers::r2) | (1 << Registers::r3);
    120 
    121  // Registers returned from a JS -> C call.
    122  static const SetType CallMask =
    123      (1 << Registers::r0) |
    124      (1 << Registers::r1);  // Used for double-size returns.
    125 
    126  static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    127 
    128  static uint32_t SetSize(SetType x) {
    129    static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
    130    return mozilla::CountPopulation32(x);
    131  }
    132  static uint32_t FirstBit(SetType x) {
    133    return mozilla::CountTrailingZeroes32(x);
    134  }
    135  static uint32_t LastBit(SetType x) {
    136    return 31 - mozilla::CountLeadingZeroes32(x);
    137  }
    138 };
    139 
    140 // Smallest integer type that can hold a register bitmask.
    141 using PackedRegisterMask = uint16_t;
    142 
    143 class FloatRegisters {
    144 public:
    145  enum FPRegisterID {
    146    s0,
    147    s1,
    148    s2,
    149    s3,
    150    s4,
    151    s5,
    152    s6,
    153    s7,
    154    s8,
    155    s9,
    156    s10,
    157    s11,
    158    s12,
    159    s13,
    160    s14,
    161    s15,
    162    s16,
    163    s17,
    164    s18,
    165    s19,
    166    s20,
    167    s21,
    168    s22,
    169    s23,
    170    s24,
    171    s25,
    172    s26,
    173    s27,
    174    s28,
    175    s29,
    176    s30,
    177    s31,
    178    d0,
    179    d1,
    180    d2,
    181    d3,
    182    d4,
    183    d5,
    184    d6,
    185    d7,
    186    d8,
    187    d9,
    188    d10,
    189    d11,
    190    d12,
    191    d13,
    192    d14,
    193    d15,
    194    d16,
    195    d17,
    196    d18,
    197    d19,
    198    d20,
    199    d21,
    200    d22,
    201    d23,
    202    d24,
    203    d25,
    204    d26,
    205    d27,
    206    d28,
    207    d29,
    208    d30,
    209    d31,
    210    invalid_freg
    211  };
    212 
    213  using Code = uint32_t;
    214  using Encoding = FPRegisterID;
    215 
    216  // Content spilled during bailouts.
    217  union RegisterContent {
    218    double d;
    219  };
    220 
    221  static const char* GetDoubleName(Encoding code) {
    222    static const char* const Names[] = {
    223        "d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
    224        "d8",  "d9",  "d10", "d11", "d12", "d13", "d14", "d15",
    225        "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
    226        "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
    227    return Names[code];
    228  }
    229  static const char* GetSingleName(Encoding code) {
    230    static const char* const Names[] = {
    231        "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
    232        "s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
    233        "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
    234        "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
    235    return Names[code];
    236  }
    237 
    238  static Code FromName(const char* name);
    239 
    240  static const Encoding Invalid = invalid_freg;
    241  static const uint32_t Total = 48;
    242  static const uint32_t TotalDouble = 16;
    243  static const uint32_t TotalSingle = 32;
    244  static const uint32_t Allocatable = 45;
    245  // There are only 32 places that we can put values.
    246  static const uint32_t TotalPhys = 32;
    247  static uint32_t ActualTotalPhys();
    248 
    249  /* clang-format off */
    250    // ARM float registers overlap in a way that for 1 double registers, in the
    251    // range d0-d15, we have 2 singles register in the range s0-s31. d16-d31
    252    // have no single register aliases.  The aliasing rule state that d{n}
    253    // aliases s{2n} and s{2n+1}, for n in [0 .. 15].
    254    //
    255    // The register set is used to represent either allocatable register or live
    256    // registers. The register maps d0-d15 and s0-s31 to a single bit each. The
    257    // registers d16-d31 are not used at the moment.
    258    //
    259    // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss
    260    //                     ^                 ^ ^                                     ^
    261    //                     '-- d15      d0 --' '-- s31                          s0 --'
    262    //
    263    // LiveSet are handled by adding the bit of each register without
    264    // considering the aliases.
    265    //
    266    // AllocatableSet are handled by adding and removing the bit of each
    267    // aligned-or-dominated-aliased registers.
    268    //
    269    //     ...0...00... : s{2n}, s{2n+1} and d{n} are not available
    270    //     ...1...01... : s{2n} is available (*)
    271    //     ...0...10... : s{2n+1} is available
    272    //     ...1...11... : s{2n}, s{2n+1} and d{n} are available
    273    //
    274    // (*) Note that d{n} bit is set, but is not available because s{2n+1} bit
    275    // is not set, which is required as d{n} dominates s{2n+1}. The d{n} bit is
    276    // set, because s{2n} is aligned.
    277    //
    278    //        |        d{n}       |
    279    //        | s{2n+1} |  s{2n}  |
    280    //
    281  /* clang-format on */
    282  using SetType = uint64_t;
    283  static const SetType AllSingleMask = (1ull << TotalSingle) - 1;
    284  static const SetType AllDoubleMask = ((1ull << TotalDouble) - 1)
    285                                       << TotalSingle;
    286  static const SetType AllMask = AllDoubleMask | AllSingleMask;
    287 
    288  // d15 is the ScratchFloatReg.
    289  static const SetType NonVolatileDoubleMask =
    290      ((1ULL << d8) | (1ULL << d9) | (1ULL << d10) | (1ULL << d11) |
    291       (1ULL << d12) | (1ULL << d13) | (1ULL << d14));
    292  // s30 and s31 alias d15.
    293  static const SetType NonVolatileMask =
    294      (NonVolatileDoubleMask |
    295       ((1 << s16) | (1 << s17) | (1 << s18) | (1 << s19) | (1 << s20) |
    296        (1 << s21) | (1 << s22) | (1 << s23) | (1 << s24) | (1 << s25) |
    297        (1 << s26) | (1 << s27) | (1 << s28) | (1 << s29) | (1 << s30)));
    298 
    299  static const SetType VolatileMask = AllMask & ~NonVolatileMask;
    300  static const SetType VolatileDoubleMask =
    301      AllDoubleMask & ~NonVolatileDoubleMask;
    302 
    303  static const SetType WrapperMask = VolatileMask;
    304 
    305  // d15 is the ARM scratch float register.
    306  // s30 and s31 alias d15.
    307  static const SetType NonAllocatableMask =
    308      ((1ULL << d15)) | (1ULL << s30) | (1ULL << s31);
    309 
    310  static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    311 };
    312 
    313 static const uint32_t SpillSlotSize =
    314    std::max(sizeof(Registers::RegisterContent),
    315             sizeof(FloatRegisters::RegisterContent));
    316 
    317 template <typename T>
    318 class TypedRegisterSet;
    319 
    320 class VFPRegister {
    321 public:
    322  // What type of data is being stored in this register? UInt / Int are
    323  // specifically for vcvt, where we need to know how the data is supposed to
    324  // be converted.
    325  enum RegType : uint8_t { Single = 0x0, Double = 0x1, UInt = 0x2, Int = 0x3 };
    326 
    327  using Codes = FloatRegisters;
    328  using Code = Codes::Code;
    329  using Encoding = Codes::Encoding;
    330 
    331  // Bitfields below are all uint32_t to make sure MSVC packs them correctly.
    332 public:
    333  // ARM doesn't have more than 32 registers of each type, so 5 bits should
    334  // suffice.
    335  uint32_t code_ : 5;
    336 
    337 protected:
    338  uint32_t kind : 2;
    339  uint32_t _isInvalid : 1;
    340  uint32_t _isMissing : 1;
    341 
    342 public:
    343  constexpr VFPRegister(uint32_t r, RegType k)
    344      : code_(Code(r)), kind(k), _isInvalid(false), _isMissing(false) {}
    345  constexpr VFPRegister()
    346      : code_(Code(0)), kind(Double), _isInvalid(true), _isMissing(false) {}
    347 
    348  constexpr VFPRegister(RegType k, uint32_t id, bool invalid, bool missing)
    349      : code_(Code(id)), kind(k), _isInvalid(invalid), _isMissing(missing) {}
    350 
    351  explicit constexpr VFPRegister(Code id)
    352      : code_(id), kind(Double), _isInvalid(false), _isMissing(false) {}
    353  bool operator==(const VFPRegister& other) const {
    354    return kind == other.kind && code_ == other.code_ &&
    355           isInvalid() == other.isInvalid();
    356  }
    357  bool operator!=(const VFPRegister& other) const { return !operator==(other); }
    358 
    359  bool isSingle() const { return kind == Single; }
    360  bool isDouble() const { return kind == Double; }
    361  bool isSimd128() const { return false; }
    362  bool isFloat() const { return (kind == Double) || (kind == Single); }
    363  bool isInt() const { return (kind == UInt) || (kind == Int); }
    364  bool isSInt() const { return kind == Int; }
    365  bool isUInt() const { return kind == UInt; }
    366  bool equiv(const VFPRegister& other) const { return other.kind == kind; }
    367  size_t size() const { return (kind == Double) ? 8 : 4; }
    368  bool isInvalid() const { return _isInvalid; }
    369  bool isMissing() const {
    370    MOZ_ASSERT(!_isInvalid);
    371    return _isMissing;
    372  }
    373 
    374  VFPRegister doubleOverlay(unsigned int which = 0) const;
    375  VFPRegister singleOverlay(unsigned int which = 0) const;
    376  VFPRegister sintOverlay(unsigned int which = 0) const;
    377  VFPRegister uintOverlay(unsigned int which = 0) const;
    378 
    379  VFPRegister asSingle() const { return singleOverlay(); }
    380  VFPRegister asDouble() const { return doubleOverlay(); }
    381  VFPRegister asSimd128() const { MOZ_CRASH("NYI"); }
    382 
    383  struct VFPRegIndexSplit;
    384  VFPRegIndexSplit encode();
    385 
    386  // For serializing values.
    387  struct VFPRegIndexSplit {
    388    const uint32_t block : 4;
    389    const uint32_t bit : 1;
    390 
    391   private:
    392    friend VFPRegIndexSplit js::jit::VFPRegister::encode();
    393 
    394    VFPRegIndexSplit(uint32_t block_, uint32_t bit_)
    395        : block(block_), bit(bit_) {
    396      MOZ_ASSERT(block == block_);
    397      MOZ_ASSERT(bit == bit_);
    398    }
    399  };
    400 
    401  Code code() const {
    402    MOZ_ASSERT(!_isInvalid && !_isMissing);
    403    // This should only be used in areas where we only have doubles and
    404    // singles.
    405    MOZ_ASSERT(isFloat());
    406    return Code(code_ | (kind << 5));
    407  }
    408  Encoding encoding() const {
    409    MOZ_ASSERT(!_isInvalid && !_isMissing);
    410    return Encoding(code_);
    411  }
    412  uint32_t id() const { return code_; }
    413  static VFPRegister FromCode(uint32_t i) {
    414    uint32_t code = i & 31;
    415    uint32_t kind = i >> 5;
    416    return VFPRegister(code, RegType(kind));
    417  }
    418  bool volatile_() const {
    419    if (isDouble()) {
    420      return !!((1ULL << (code_ >> 1)) & FloatRegisters::VolatileMask);
    421    }
    422    return !!((1ULL << code_) & FloatRegisters::VolatileMask);
    423  }
    424  const char* name() const {
    425    if (isDouble()) {
    426      return FloatRegisters::GetDoubleName(Encoding(code_));
    427    }
    428    return FloatRegisters::GetSingleName(Encoding(code_));
    429  }
    430  bool aliases(const VFPRegister& other) {
    431    if (kind == other.kind) {
    432      return code_ == other.code_;
    433    }
    434    return doubleOverlay() == other.doubleOverlay();
    435  }
    436  static const int NumAliasedDoubles = 16;
    437  uint32_t numAliased() const {
    438    if (isDouble()) {
    439      if (code_ < NumAliasedDoubles) {
    440        return 3;
    441      }
    442      return 1;
    443    }
    444    return 2;
    445  }
    446 
    447  VFPRegister aliased(uint32_t aliasIdx) {
    448    if (aliasIdx == 0) {
    449      return *this;
    450    }
    451    if (isDouble()) {
    452      MOZ_ASSERT(code_ < NumAliasedDoubles);
    453      MOZ_ASSERT(aliasIdx <= 2);
    454      return singleOverlay(aliasIdx - 1);
    455    }
    456    MOZ_ASSERT(aliasIdx == 1);
    457    return doubleOverlay(aliasIdx - 1);
    458  }
    459  uint32_t numAlignedAliased() const {
    460    if (isDouble()) {
    461      if (code_ < NumAliasedDoubles) {
    462        return 2;
    463      }
    464      return 1;
    465    }
    466    // s1 has 0 other aligned aliases, 1 total.
    467    // s0 has 1 other aligned aliase, 2 total.
    468    return 2 - (code_ & 1);
    469  }
    470  // |   d0    |
    471  // | s0 | s1 |
    472  // If we've stored s0 and s1 in memory, we also want to say that d0 is
    473  // stored there, but it is only stored at the location where it is aligned
    474  // e.g. at s0, not s1.
    475  VFPRegister alignedAliased(uint32_t aliasIdx) {
    476    if (aliasIdx == 0) {
    477      return *this;
    478    }
    479    MOZ_ASSERT(aliasIdx == 1);
    480    if (isDouble()) {
    481      MOZ_ASSERT(code_ < NumAliasedDoubles);
    482      return singleOverlay(aliasIdx - 1);
    483    }
    484    MOZ_ASSERT((code_ & 1) == 0);
    485    return doubleOverlay(aliasIdx - 1);
    486  }
    487 
    488  using SetType = FloatRegisters::SetType;
    489 
    490  // This function is used to ensure that Register set can take all Single
    491  // registers, even if we are taking a mix of either double or single
    492  // registers.
    493  //
    494  //   s0.alignedOrDominatedAliasedSet() == s0 | d0.
    495  //   s1.alignedOrDominatedAliasedSet() == s1.
    496  //   d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0.
    497  //
    498  // This way the Allocatable register set does not have to do any arithmetics
    499  // to know if a register is available or not, as we have the following
    500  // relations:
    501  //
    502  //  d0.alignedOrDominatedAliasedSet() ==
    503  //      s0.alignedOrDominatedAliasedSet() | s1.alignedOrDominatedAliasedSet()
    504  //
    505  //  s0.alignedOrDominatedAliasedSet() & s1.alignedOrDominatedAliasedSet() == 0
    506  //
    507  SetType alignedOrDominatedAliasedSet() const {
    508    if (isSingle()) {
    509      if (code_ % 2 != 0) {
    510        return SetType(1) << code_;
    511      }
    512      return (SetType(1) << code_) | (SetType(1) << (32 + code_ / 2));
    513    }
    514 
    515    MOZ_ASSERT(isDouble());
    516    return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_));
    517  }
    518 
    519  static constexpr RegTypeName DefaultType = RegTypeName::Float64;
    520 
    521  template <RegTypeName = DefaultType>
    522  static SetType LiveAsIndexableSet(SetType s) {
    523    return SetType(0);
    524  }
    525 
    526  template <RegTypeName Name = DefaultType>
    527  static SetType AllocatableAsIndexableSet(SetType s) {
    528    static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
    529    return SetType(0);
    530  }
    531 
    532  static uint32_t SetSize(SetType x) {
    533    static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
    534    return mozilla::CountPopulation32(x);
    535  }
    536  static Code FromName(const char* name) {
    537    return FloatRegisters::FromName(name);
    538  }
    539  static TypedRegisterSet<VFPRegister> ReduceSetForPush(
    540      const TypedRegisterSet<VFPRegister>& s);
    541  static uint32_t GetPushSizeInBytes(const TypedRegisterSet<VFPRegister>& s);
    542  uint32_t getRegisterDumpOffsetInBytes();
    543  static uint32_t FirstBit(SetType x) {
    544    return mozilla::CountTrailingZeroes64(x);
    545  }
    546  static uint32_t LastBit(SetType x) {
    547    return 63 - mozilla::CountLeadingZeroes64(x);
    548  }
    549 };
    550 
    551 template <>
    552 inline VFPRegister::SetType
    553 VFPRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) {
    554  return set & FloatRegisters::AllSingleMask;
    555 }
    556 
    557 template <>
    558 inline VFPRegister::SetType
    559 VFPRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) {
    560  return set & FloatRegisters::AllDoubleMask;
    561 }
    562 
    563 template <>
    564 inline VFPRegister::SetType VFPRegister::LiveAsIndexableSet<RegTypeName::Any>(
    565    SetType set) {
    566  return set;
    567 }
    568 
    569 template <>
    570 inline VFPRegister::SetType
    571 VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float32>(SetType set) {
    572  // Single registers are not dominating any smaller registers, thus masking
    573  // is enough to convert an allocatable set into a set of register list all
    574  // single register available.
    575  return set & FloatRegisters::AllSingleMask;
    576 }
    577 
    578 template <>
    579 inline VFPRegister::SetType
    580 VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float64>(SetType set) {
    581  /* clang-format off */
    582    // An allocatable float register set is represented as follow:
    583    //
    584    // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss
    585    //                     ^                 ^ ^                                     ^
    586    //                     '-- d15      d0 --' '-- s31                          s0 --'
    587    //
    588    //     ...0...00... : s{2n}, s{2n+1} and d{n} are not available
    589    //     ...1...01... : s{2n} is available
    590    //     ...0...10... : s{2n+1} is available
    591    //     ...1...11... : s{2n}, s{2n+1} and d{n} are available
    592    //
    593    // The goal of this function is to return the set of double registers which
    594    // are available as an indexable bit set. This implies that iff a double bit
    595    // is set in the returned set, then the register is available.
    596    //
    597    // To do so, this functions converts the 32 bits set of single registers
    598    // into a 16 bits set of equivalent double registers. Then, we mask out
    599    // double registers which do not have all the single register that compose
    600    // them. As d{n} bit is set when s{2n} is available, we only need to take
    601    // s{2n+1} into account.
    602  /* clang-format on */
    603 
    604  // Convert  s7s6s5s4 s3s2s1s0  into  s7s5s3s1, for all s0-s31.
    605  SetType s2d = AllocatableAsIndexableSet<RegTypeName::Float32>(set);
    606  static_assert(FloatRegisters::TotalSingle == 32, "Wrong mask");
    607  s2d = (0xaaaaaaaa & s2d) >> 1;  // Filter s{2n+1} registers.
    608  // Group adjacent bits as follow:
    609  //     0.0.s3.s1 == ((0.s3.0.s1) >> 1 | (0.s3.0.s1)) & 0b0011;
    610  s2d = ((s2d >> 1) | s2d) & 0x33333333;  // 0a0b --> 00ab
    611  s2d = ((s2d >> 2) | s2d) & 0x0f0f0f0f;  // 00ab00cd --> 0000abcd
    612  s2d = ((s2d >> 4) | s2d) & 0x00ff00ff;
    613  s2d = ((s2d >> 8) | s2d) & 0x0000ffff;
    614  // Move the s7s5s3s1 to the aliased double positions.
    615  s2d = s2d << FloatRegisters::TotalSingle;
    616 
    617  // Note: We currently do not use any representation for d16-d31.
    618  static_assert(FloatRegisters::TotalDouble == 16,
    619                "d16-d31 do not have a single register mapping");
    620 
    621  // Filter out any double register which are not allocatable due to
    622  // non-aligned dominated single registers.
    623  return set & s2d;
    624 }
    625 
    626 // The only floating point register set that we work with are the VFP Registers.
    627 using FloatRegister = VFPRegister;
    628 
    629 enum class ARMCapability : uint32_t {
    630  // Flag when the capabilities are initialized, so they can be atomically set.
    631  Initialized,
    632 
    633  // Flag when HWCAP_VFP is set.
    634  VFP,
    635 
    636  // Flag when HWCAP_VFPD32 is set.
    637  VFPD32,
    638 
    639  // Flag when HWCAP_VFPv3 is set.
    640  VFPv3,
    641 
    642  // Flag when HWCAP_VFPv3D16 is set.
    643  VFPv3D16,
    644 
    645  // Flag when HWCAP_VFPv4 is set.
    646  VFPv4,
    647 
    648  // Flag when HWCAP_NEON is set.
    649  Neon,
    650 
    651  // Flag when HWCAP_IDIVA is set.
    652  IDivA,
    653 
    654  // Flag when HWCAP_FPHP is set (floating point half-precision).
    655  FPHP,
    656 
    657  // Flag when signaled alignment faults are to be fixed up.
    658  FixupFault,
    659 
    660  // Flag when alignment faults are enabled and signal.
    661  AlignmentFault,
    662 
    663  // Flag the use of the hardfp ABI.
    664  UseHardFpABI,
    665 
    666  // Flag the use of the ARMv7 arch, otherwise ARMv6.
    667  ARMv7,
    668 };
    669 
    670 using ARMCapabilities = mozilla::EnumSet<ARMCapability>;
    671 
    672 class ARMFlags final {
    673  // The override flags parsed from the ARMHWCAP environment variable or from
    674  // the --arm-hwcap js shell argument. They are stable after startup: there is
    675  // no longer a programmatic way of setting these from JS.
    676  static inline ARMCapabilities capabilities{};
    677 
    678 public:
    679  ARMFlags() = delete;
    680 
    681  // ARMFlags::Init is called from the JitContext constructor to read the
    682  // hardware flags. This method must only be called exactly once.
    683  //
    684  // If the environment variable ARMHWCAP is set then the flags are read from it
    685  // instead; see ParseARMHwCapFlags.
    686  static void Init();
    687 
    688  static bool IsInitialized() {
    689    return capabilities.contains(ARMCapability::Initialized);
    690  }
    691 
    692  static uint32_t GetFlags() {
    693    MOZ_ASSERT(IsInitialized());
    694    return capabilities.serialize();
    695  }
    696  static bool HasARMv7() {
    697    MOZ_ASSERT(IsInitialized());
    698    return capabilities.contains(ARMCapability::ARMv7);
    699  }
    700  static bool HasMOVWT() {
    701    MOZ_ASSERT(IsInitialized());
    702    return capabilities.contains(ARMCapability::ARMv7);
    703  }
    704  // {LD,ST}REX{B,H,D}
    705  static bool HasLDSTREXBHD() {
    706    // These are really available from ARMv6K and later, but why bother?
    707    MOZ_ASSERT(IsInitialized());
    708    return capabilities.contains(ARMCapability::ARMv7);
    709  }
    710  // DMB, DSB, and ISB
    711  static bool HasDMBDSBISB() {
    712    MOZ_ASSERT(IsInitialized());
    713    return capabilities.contains(ARMCapability::ARMv7);
    714  }
    715  static bool HasVFP() {
    716    MOZ_ASSERT(IsInitialized());
    717    return capabilities.contains(ARMCapability::VFP);
    718  }
    719  static bool Has32DP() {
    720    MOZ_ASSERT(IsInitialized());
    721    return capabilities.contains(ARMCapability::VFPD32);
    722  }
    723  static bool HasVFPv3() {
    724    MOZ_ASSERT(IsInitialized());
    725    return capabilities.contains(ARMCapability::VFPv3);
    726  }
    727  static bool HasVFPv4() {
    728    MOZ_ASSERT(IsInitialized());
    729    return capabilities.contains(ARMCapability::VFPv4);
    730  }
    731  static bool HasNEON() {
    732    MOZ_ASSERT(IsInitialized());
    733    return capabilities.contains(ARMCapability::Neon);
    734  }
    735  static bool HasIDIV() {
    736    MOZ_ASSERT(IsInitialized());
    737    return capabilities.contains(ARMCapability::IDivA);
    738  }
    739  static bool HasFPHalfPrecision() {
    740    MOZ_ASSERT(IsInitialized());
    741    return capabilities.contains(ARMCapability::FPHP);
    742  }
    743 
    744  // Returns true when cpu alignment faults are enabled and signaled, and thus
    745  // we should ensure loads and stores are aligned.
    746  static bool HasAlignmentFault() {
    747    MOZ_ASSERT(IsInitialized());
    748    return capabilities.contains(ARMCapability::AlignmentFault);
    749  }
    750 
    751 #ifdef JS_SIMULATOR_ARM
    752  // Returns true when cpu alignment faults will be fixed up by the
    753  // "operating system", which functionality we will emulate.
    754  static bool FixupFault() {
    755    MOZ_ASSERT(IsInitialized());
    756    return capabilities.contains(ARMCapability::FixupFault);
    757  }
    758 #endif
    759 
    760 // If the simulator is used then the ABI choice is dynamic. Otherwise the ABI is
    761 // static and useHardFpABI is constexpr so that unused branches can be optimized
    762 // away.
    763 #ifdef JS_SIMULATOR_ARM
    764  static bool UseHardFpABI() {
    765    MOZ_ASSERT(IsInitialized());
    766    return capabilities.contains(ARMCapability::UseHardFpABI);
    767  }
    768 #else
    769  static constexpr bool UseHardFpABI() {
    770 // GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
    771 // ABI target. The iOS toolchain doesn't define anything specific here, but
    772 // iOS always supports VFP.
    773 #  if defined(__ARM_PCS_VFP) || defined(XP_IOS)
    774    return true;
    775 #  else
    776    return false;
    777 #  endif
    778  }
    779 #endif
    780 };
    781 
    782 // Arm/D32 has double registers that can NOT be treated as float32 and this
    783 // requires some dances in lowering.
    784 inline bool hasUnaliasedDouble() { return ARMFlags::Has32DP(); }
    785 
    786 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 to
    787 // a double as a temporary, you need a temporary double register.
    788 inline bool hasMultiAlias() { return true; }
    789 
    790 // Register a string denoting ARM hardware flags. During engine initialization,
    791 // these flags will then be used instead of the actual hardware capabilities.
    792 // This must be called before JS_Init and the passed string's buffer must
    793 // outlive the JS_Init call.
    794 void SetARMHwCapFlagsString(const char* armHwCap);
    795 
    796 // Retrieve the ARM hardware flags as a bitmask. They must have been set.
    797 inline uint32_t GetARMFlags() { return ARMFlags::GetFlags(); }
    798 
    799 // In order to handle SoftFp ABI calls, we need to be able to express that we
    800 // have ABIArg which are represented by pair of general purpose registers.
    801 #define JS_CODEGEN_REGISTER_PAIR 1
    802 
    803 }  // namespace jit
    804 }  // namespace js
    805 
    806 #endif /* jit_arm_Architecture_arm_h */