tor-browser

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

Architecture-arm64.h (23278B)


      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_arm64_Architecture_arm64_h
      8 #define jit_arm64_Architecture_arm64_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/MathAlgorithms.h"
     12 
     13 #include <algorithm>
     14 
     15 #include "jit/arm64/vixl/Cpu-Features-vixl.h"
     16 #include "jit/arm64/vixl/Instructions-vixl.h"
     17 #include "jit/shared/Architecture-shared.h"
     18 
     19 #include "js/Utility.h"
     20 
     21 #define JS_HAS_HIDDEN_SP
     22 static const uint32_t HiddenSPEncoding = vixl::kSPRegInternalCode;
     23 
     24 namespace js {
     25 namespace jit {
     26 
     27 // AArch64 has 32 64-bit integer registers, x0 though x31.
     28 //
     29 //  x31 (or, more accurately, the integer register with encoding 31, since
     30 //  there is no x31 per se) is special and functions as both the stack pointer
     31 //  and a zero register.
     32 //
     33 //  The bottom 32 bits of each of the X registers is accessible as w0 through
     34 //  w31. The program counter is not accessible as a register.
     35 //
     36 // SIMD and scalar floating-point registers share a register bank.
     37 //  32 bit float registers are s0 through s31.
     38 //  64 bit double registers are d0 through d31.
     39 //  128 bit SIMD registers are v0 through v31.
     40 //  e.g., s0 is the bottom 32 bits of d0, which is the bottom 64 bits of v0.
     41 
     42 // AArch64 Calling Convention:
     43 //  x0 - x7: arguments and return value
     44 //  x8: indirect result (struct) location
     45 //  x9 - x15: temporary registers
     46 //  x16 - x17: intra-call-use registers (PLT, linker)
     47 //  x18: platform specific use (TLS)
     48 //  x19 - x28: callee-saved registers
     49 //  x29: frame pointer
     50 //  x30: link register
     51 
     52 // AArch64 Calling Convention for Floats:
     53 //  d0 - d7: arguments and return value
     54 //  d8 - d15: callee-saved registers
     55 //   Bits 64:128 are not saved for v8-v15.
     56 //  d16 - d31: temporary registers
     57 
     58 // AArch64 does not have soft float.
     59 
     60 class Registers {
     61 public:
     62  enum RegisterID {
     63    w0 = 0,
     64    x0 = 0,
     65    w1 = 1,
     66    x1 = 1,
     67    w2 = 2,
     68    x2 = 2,
     69    w3 = 3,
     70    x3 = 3,
     71    w4 = 4,
     72    x4 = 4,
     73    w5 = 5,
     74    x5 = 5,
     75    w6 = 6,
     76    x6 = 6,
     77    w7 = 7,
     78    x7 = 7,
     79    w8 = 8,
     80    x8 = 8,
     81    w9 = 9,
     82    x9 = 9,
     83    w10 = 10,
     84    x10 = 10,
     85    w11 = 11,
     86    x11 = 11,
     87    w12 = 12,
     88    x12 = 12,
     89    w13 = 13,
     90    x13 = 13,
     91    w14 = 14,
     92    x14 = 14,
     93    w15 = 15,
     94    x15 = 15,
     95    w16 = 16,
     96    x16 = 16,
     97    ip0 = 16,  // MacroAssembler scratch register 1.
     98    w17 = 17,
     99    x17 = 17,
    100    ip1 = 17,  // MacroAssembler scratch register 2.
    101    w18 = 18,
    102    x18 = 18,
    103    tls = 18,  // Platform-specific use (TLS).
    104    w19 = 19,
    105    x19 = 19,
    106    w20 = 20,
    107    x20 = 20,
    108    w21 = 21,
    109    x21 = 21,
    110    w22 = 22,
    111    x22 = 22,
    112    w23 = 23,
    113    x23 = 23,
    114    w24 = 24,
    115    x24 = 24,
    116    w25 = 25,
    117    x25 = 25,
    118    w26 = 26,
    119    x26 = 26,
    120    w27 = 27,
    121    x27 = 27,
    122    w28 = 28,
    123    x28 = 28,
    124    w29 = 29,
    125    x29 = 29,
    126    fp = 29,
    127    w30 = 30,
    128    x30 = 30,
    129    lr = 30,
    130    w31 = 31,
    131    x31 = 31,
    132    wzr = 31,
    133    xzr = 31,
    134    sp = 31,  // Special: both stack pointer and a zero register.
    135  };
    136  using Code = uint8_t;
    137  using Encoding = uint32_t;
    138  using SetType = uint32_t;
    139 
    140  static const Code Invalid = 0xFF;
    141 
    142  union RegisterContent {
    143    uintptr_t r;
    144  };
    145 
    146  static uint32_t SetSize(SetType x) {
    147    static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
    148    return mozilla::CountPopulation32(x);
    149  }
    150  static uint32_t FirstBit(SetType x) {
    151    return mozilla::CountTrailingZeroes32(x);
    152  }
    153  static uint32_t LastBit(SetType x) {
    154    return 31 - mozilla::CountLeadingZeroes32(x);
    155  }
    156 
    157  static const char* GetName(uint32_t code) {
    158    static const char* const Names[] = {
    159        "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
    160        "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
    161        "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
    162        "x24", "x25", "x26", "x27", "x28", "x29", "lr",  "sp"};
    163    static_assert(Total == std::size(Names), "Table is the correct size");
    164    if (code >= Total) {
    165      return "invalid";
    166    }
    167    return Names[code];
    168  }
    169 
    170  static Code FromName(const char* name);
    171 
    172  static const uint32_t Total = 32;
    173  static const uint32_t TotalPhys = 32;
    174  static const uint32_t Allocatable =
    175      27;  // No named special-function registers.
    176 
    177  static const SetType AllMask = 0xFFFFFFFF;
    178  static const SetType NoneMask = 0x0;
    179 
    180  static const SetType ArgRegMask =
    181      (1 << Registers::x0) | (1 << Registers::x1) | (1 << Registers::x2) |
    182      (1 << Registers::x3) | (1 << Registers::x4) | (1 << Registers::x5) |
    183      (1 << Registers::x6) | (1 << Registers::x7);
    184 
    185  static const SetType VolatileMask =
    186      (1 << Registers::x0) | (1 << Registers::x1) | (1 << Registers::x2) |
    187      (1 << Registers::x3) | (1 << Registers::x4) | (1 << Registers::x5) |
    188      (1 << Registers::x6) | (1 << Registers::x7) | (1 << Registers::x8) |
    189      (1 << Registers::x9) | (1 << Registers::x10) | (1 << Registers::x11) |
    190      (1 << Registers::x12) | (1 << Registers::x13) | (1 << Registers::x14) |
    191      (1 << Registers::x15) | (1 << Registers::x16) | (1 << Registers::x17) |
    192      (1 << Registers::x18);
    193 
    194  static const SetType NonVolatileMask =
    195      (1 << Registers::x19) | (1 << Registers::x20) | (1 << Registers::x21) |
    196      (1 << Registers::x22) | (1 << Registers::x23) | (1 << Registers::x24) |
    197      (1 << Registers::x25) | (1 << Registers::x26) | (1 << Registers::x27) |
    198      (1 << Registers::x28) | (1 << Registers::x29) | (1 << Registers::x30);
    199 
    200  static const SetType NonAllocatableMask =
    201      (1 << Registers::x28) |  // PseudoStackPointer.
    202      (1 << Registers::ip0) |  // First scratch register.
    203      (1 << Registers::ip1) |  // Second scratch register.
    204      (1 << Registers::tls) | (1 << Registers::lr) | (1 << Registers::sp) |
    205      (1 << Registers::fp);
    206 
    207  static const SetType WrapperMask = VolatileMask;
    208 
    209  // Registers returned from a JS -> JS call.
    210  static const SetType JSCallMask = (1 << Registers::x2);
    211 
    212  // Registers returned from a JS -> C call.
    213  static const SetType CallMask = (1 << Registers::x0);
    214 
    215  static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    216 };
    217 
    218 // Smallest integer type that can hold a register bitmask.
    219 using PackedRegisterMask = uint32_t;
    220 
    221 template <typename T>
    222 class TypedRegisterSet;
    223 
    224 // 128-bit bitset for FloatRegisters::SetType.
    225 
    226 class Bitset128 {
    227  // The order (hi, lo) looks best in the debugger.
    228  uint64_t hi, lo;
    229 
    230 public:
    231  MOZ_IMPLICIT constexpr Bitset128(uint64_t initial) : hi(0), lo(initial) {}
    232  MOZ_IMPLICIT constexpr Bitset128(const Bitset128& that)
    233      : hi(that.hi), lo(that.lo) {}
    234 
    235  constexpr Bitset128(uint64_t hi, uint64_t lo) : hi(hi), lo(lo) {}
    236 
    237  constexpr uint64_t high() const { return hi; }
    238 
    239  constexpr uint64_t low() const { return lo; }
    240 
    241  constexpr Bitset128 operator|(Bitset128 that) const {
    242    return Bitset128(hi | that.hi, lo | that.lo);
    243  }
    244 
    245  constexpr Bitset128 operator&(Bitset128 that) const {
    246    return Bitset128(hi & that.hi, lo & that.lo);
    247  }
    248 
    249  constexpr Bitset128 operator^(Bitset128 that) const {
    250    return Bitset128(hi ^ that.hi, lo ^ that.lo);
    251  }
    252 
    253  constexpr Bitset128 operator~() const { return Bitset128(~hi, ~lo); }
    254 
    255  // We must avoid shifting by the word width, which is complex.  Inlining plus
    256  // shift-by-constant will remove a lot of code in the normal case.
    257 
    258  constexpr Bitset128 operator<<(size_t shift) const {
    259    if (shift == 0) {
    260      return *this;
    261    }
    262    if (shift < 64) {
    263      return Bitset128((hi << shift) | (lo >> (64 - shift)), lo << shift);
    264    }
    265    if (shift == 64) {
    266      return Bitset128(lo, 0);
    267    }
    268    return Bitset128(lo << (shift - 64), 0);
    269  }
    270 
    271  constexpr Bitset128 operator>>(size_t shift) const {
    272    if (shift == 0) {
    273      return *this;
    274    }
    275    if (shift < 64) {
    276      return Bitset128(hi >> shift, (lo >> shift) | (hi << (64 - shift)));
    277    }
    278    if (shift == 64) {
    279      return Bitset128(0, hi);
    280    }
    281    return Bitset128(0, hi >> (shift - 64));
    282  }
    283 
    284  constexpr bool operator==(Bitset128 that) const {
    285    return lo == that.lo && hi == that.hi;
    286  }
    287 
    288  constexpr bool operator!=(Bitset128 that) const {
    289    return lo != that.lo || hi != that.hi;
    290  }
    291 
    292  constexpr bool operator!() const { return (hi | lo) == 0; }
    293 
    294  Bitset128& operator|=(const Bitset128& that) {
    295    hi |= that.hi;
    296    lo |= that.lo;
    297    return *this;
    298  }
    299 
    300  Bitset128& operator&=(const Bitset128& that) {
    301    hi &= that.hi;
    302    lo &= that.lo;
    303    return *this;
    304  }
    305 
    306  uint32_t size() const {
    307    return mozilla::CountPopulation64(hi) + mozilla::CountPopulation64(lo);
    308  }
    309 
    310  uint32_t countTrailingZeroes() const {
    311    if (lo) {
    312      return mozilla::CountTrailingZeroes64(lo);
    313    }
    314    return mozilla::CountTrailingZeroes64(hi) + 64;
    315  }
    316 
    317  uint32_t countLeadingZeroes() const {
    318    if (hi) {
    319      return mozilla::CountLeadingZeroes64(hi);
    320    }
    321    return mozilla::CountLeadingZeroes64(lo) + 64;
    322  }
    323 };
    324 
    325 class FloatRegisters {
    326 public:
    327  enum FPRegisterID {
    328    s0 = 0,
    329    d0 = 0,
    330    v0 = 0,
    331    s1 = 1,
    332    d1 = 1,
    333    v1 = 1,
    334    s2 = 2,
    335    d2 = 2,
    336    v2 = 2,
    337    s3 = 3,
    338    d3 = 3,
    339    v3 = 3,
    340    s4 = 4,
    341    d4 = 4,
    342    v4 = 4,
    343    s5 = 5,
    344    d5 = 5,
    345    v5 = 5,
    346    s6 = 6,
    347    d6 = 6,
    348    v6 = 6,
    349    s7 = 7,
    350    d7 = 7,
    351    v7 = 7,
    352    s8 = 8,
    353    d8 = 8,
    354    v8 = 8,
    355    s9 = 9,
    356    d9 = 9,
    357    v9 = 9,
    358    s10 = 10,
    359    d10 = 10,
    360    v10 = 10,
    361    s11 = 11,
    362    d11 = 11,
    363    v11 = 11,
    364    s12 = 12,
    365    d12 = 12,
    366    v12 = 12,
    367    s13 = 13,
    368    d13 = 13,
    369    v13 = 13,
    370    s14 = 14,
    371    d14 = 14,
    372    v14 = 14,
    373    s15 = 15,
    374    d15 = 15,
    375    v15 = 15,
    376    s16 = 16,
    377    d16 = 16,
    378    v16 = 16,
    379    s17 = 17,
    380    d17 = 17,
    381    v17 = 17,
    382    s18 = 18,
    383    d18 = 18,
    384    v18 = 18,
    385    s19 = 19,
    386    d19 = 19,
    387    v19 = 19,
    388    s20 = 20,
    389    d20 = 20,
    390    v20 = 20,
    391    s21 = 21,
    392    d21 = 21,
    393    v21 = 21,
    394    s22 = 22,
    395    d22 = 22,
    396    v22 = 22,
    397    s23 = 23,
    398    d23 = 23,
    399    v23 = 23,
    400    s24 = 24,
    401    d24 = 24,
    402    v24 = 24,
    403    s25 = 25,
    404    d25 = 25,
    405    v25 = 25,
    406    s26 = 26,
    407    d26 = 26,
    408    v26 = 26,
    409    s27 = 27,
    410    d27 = 27,
    411    v27 = 27,
    412    s28 = 28,
    413    d28 = 28,
    414    v28 = 28,
    415    s29 = 29,
    416    d29 = 29,
    417    v29 = 29,
    418    s30 = 30,
    419    d30 = 30,
    420    v30 = 30,
    421    s31 = 31,
    422    d31 = 31,
    423    v31 = 31,  // Scratch register.
    424  };
    425 
    426  // Eight bits: (invalid << 7) | (kind << 5) | encoding
    427  using Code = uint8_t;
    428  using Encoding = FPRegisterID;
    429  using SetType = Bitset128;
    430 
    431  enum Kind : uint8_t { Single, Double, Simd128, NumTypes };
    432 
    433  static constexpr Code Invalid = 0x80;
    434 
    435  static const char* GetName(uint32_t code) {
    436    // clang-format off
    437    static const char* const Names[] = {
    438        "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",  "s8",  "s9",
    439        "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19",
    440        "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29",
    441        "s30", "s31",
    442 
    443        "d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",  "d8",  "d9",
    444        "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
    445        "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
    446        "d30", "d31",
    447 
    448        "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",  "v8",  "v9",
    449        "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
    450        "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
    451        "v30", "v31",
    452    };
    453    // clang-format on
    454    static_assert(Total == std::size(Names), "Table is the correct size");
    455    if (code >= Total) {
    456      return "invalid";
    457    }
    458    return Names[code];
    459  }
    460 
    461  static Code FromName(const char* name);
    462 
    463  static const uint32_t TotalPhys = 32;
    464  static const uint32_t Total = TotalPhys * NumTypes;
    465  static const uint32_t Allocatable = 31;  // Without d31, the scratch register.
    466 
    467  static_assert(sizeof(SetType) * 8 >= Total,
    468                "SetType should be large enough to enumerate all registers.");
    469 
    470  static constexpr unsigned ShiftSingle = uint32_t(Single) * TotalPhys;
    471  static constexpr unsigned ShiftDouble = uint32_t(Double) * TotalPhys;
    472  static constexpr unsigned ShiftSimd128 = uint32_t(Simd128) * TotalPhys;
    473 
    474  static constexpr SetType NoneMask = SetType(0);
    475  static constexpr SetType AllPhysMask = ~(~SetType(0) << TotalPhys);
    476  static constexpr SetType AllSingleMask = AllPhysMask << ShiftSingle;
    477  static constexpr SetType AllDoubleMask = AllPhysMask << ShiftDouble;
    478  static constexpr SetType AllSimd128Mask = AllPhysMask << ShiftSimd128;
    479  static constexpr SetType AllMask =
    480      AllDoubleMask | AllSingleMask | AllSimd128Mask;
    481  static constexpr SetType AliasMask = (SetType(1) << ShiftSingle) |
    482                                       (SetType(1) << ShiftDouble) |
    483                                       (SetType(1) << ShiftSimd128);
    484 
    485  static_assert(ShiftSingle == 0,
    486                "Or the NonVolatileMask must be computed differently");
    487 
    488  static constexpr SetType NonVolatileSingleMask =
    489      SetType((1 << FloatRegisters::s8) | (1 << FloatRegisters::s9) |
    490              (1 << FloatRegisters::s10) | (1 << FloatRegisters::s11) |
    491              (1 << FloatRegisters::s12) | (1 << FloatRegisters::s13) |
    492              (1 << FloatRegisters::s14) | (1 << FloatRegisters::s15));
    493 
    494  // Note: only the bottom 64 bits of v8-v15 will be preserved.
    495  static constexpr SetType NonVolatileMask =
    496      (NonVolatileSingleMask << ShiftSingle) |
    497      (NonVolatileSingleMask << ShiftDouble);
    498 
    499  static constexpr SetType VolatileMask = AllMask & ~NonVolatileMask;
    500 
    501  static constexpr SetType WrapperMask = VolatileMask;
    502 
    503  static_assert(ShiftSingle == 0,
    504                "Or the NonAllocatableMask must be computed differently");
    505 
    506  // d31 is the ScratchFloatReg.
    507  static constexpr SetType NonAllocatableSingleMask =
    508      (SetType(1) << FloatRegisters::s31);
    509 
    510  static constexpr SetType NonAllocatableMask =
    511      NonAllocatableSingleMask | (NonAllocatableSingleMask << ShiftDouble) |
    512      (NonAllocatableSingleMask << ShiftSimd128);
    513 
    514  static constexpr SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    515 
    516  // Content spilled during bailouts.
    517  union RegisterContent {
    518    float s;
    519    double d;
    520    uint8_t v128[16];
    521  };
    522 
    523  static constexpr Encoding encoding(Code c) {
    524    // assert() not available in constexpr function.
    525    // assert(c < Total);
    526    return Encoding(c & 31);
    527  }
    528 
    529  static constexpr Kind kind(Code c) {
    530    // assert() not available in constexpr function.
    531    // assert(c < Total && ((c >> 5) & 3) < NumTypes);
    532    return Kind((c >> 5) & 3);
    533  }
    534 
    535  static constexpr Code fromParts(uint32_t encoding, uint32_t kind,
    536                                  uint32_t invalid) {
    537    return Code((invalid << 7) | (kind << 5) | encoding);
    538  }
    539 };
    540 
    541 static const uint32_t SpillSlotSize =
    542    std::max(sizeof(Registers::RegisterContent),
    543             sizeof(FloatRegisters::RegisterContent));
    544 
    545 static constexpr uint32_t ShadowStackSpace = 0;
    546 
    547 // When our only strategy for far jumps is to encode the offset directly, and
    548 // not insert any jump islands during assembly for even further jumps, then the
    549 // architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit
    550 // value.  We further reduce this range to allow the far-jump inserting code to
    551 // have some breathing room.
    552 static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024));
    553 
    554 static const uint32_t ABIStackAlignment = 16;
    555 static const uint32_t CodeAlignment = 16;
    556 static const bool StackKeptAligned = false;
    557 
    558 // Although sp is only usable if 16-byte alignment is kept,
    559 // the Pseudo-StackPointer enables use of 8-byte alignment.
    560 static const uint32_t StackAlignment = 8;
    561 static const uint32_t NativeFrameSize = 8;
    562 
    563 struct FloatRegister {
    564  using Codes = FloatRegisters;
    565  using Code = Codes::Code;
    566  using Encoding = Codes::Encoding;
    567  using SetType = Codes::SetType;
    568 
    569  static uint32_t SetSize(SetType x) {
    570    static_assert(sizeof(SetType) == 16, "SetType must be 128 bits");
    571    x |= x >> FloatRegisters::TotalPhys;
    572    x |= x >> FloatRegisters::TotalPhys;
    573    x &= FloatRegisters::AllPhysMask;
    574    MOZ_ASSERT(x.high() == 0);
    575    MOZ_ASSERT((x.low() >> 32) == 0);
    576    return mozilla::CountPopulation32(x.low());
    577  }
    578 
    579  static uint32_t FirstBit(SetType x) {
    580    static_assert(sizeof(SetType) == 16, "SetType");
    581    return x.countTrailingZeroes();
    582  }
    583  static uint32_t LastBit(SetType x) {
    584    static_assert(sizeof(SetType) == 16, "SetType");
    585    return 127 - x.countLeadingZeroes();
    586  }
    587 
    588  static constexpr size_t SizeOfSimd128 = 16;
    589 
    590 private:
    591  // These fields only hold valid values: an invalid register is always
    592  // represented as a valid encoding and kind with the invalid_ bit set.
    593  uint8_t encoding_;  // 32 encodings
    594  uint8_t kind_;      // Double, Single, Simd128
    595  bool invalid_;
    596 
    597  using Kind = Codes::Kind;
    598 
    599 public:
    600  constexpr FloatRegister(Encoding encoding, Kind kind)
    601      : encoding_(encoding), kind_(kind), invalid_(false) {
    602    // assert(uint32_t(encoding) < Codes::TotalPhys);
    603  }
    604 
    605  constexpr FloatRegister()
    606      : encoding_(0), kind_(FloatRegisters::Double), invalid_(true) {}
    607 
    608  static FloatRegister FromCode(uint32_t i) {
    609    MOZ_ASSERT(i < Codes::Total);
    610    return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::kind(i));
    611  }
    612 
    613  bool isSingle() const {
    614    MOZ_ASSERT(!invalid_);
    615    return kind_ == FloatRegisters::Single;
    616  }
    617  bool isDouble() const {
    618    MOZ_ASSERT(!invalid_);
    619    return kind_ == FloatRegisters::Double;
    620  }
    621  bool isSimd128() const {
    622    MOZ_ASSERT(!invalid_);
    623    return kind_ == FloatRegisters::Simd128;
    624  }
    625  bool isInvalid() const { return invalid_; }
    626 
    627  FloatRegister asSingle() const {
    628    MOZ_ASSERT(!invalid_);
    629    return FloatRegister(Encoding(encoding_), FloatRegisters::Single);
    630  }
    631  FloatRegister asDouble() const {
    632    MOZ_ASSERT(!invalid_);
    633    return FloatRegister(Encoding(encoding_), FloatRegisters::Double);
    634  }
    635  FloatRegister asSimd128() const {
    636    MOZ_ASSERT(!invalid_);
    637    return FloatRegister(Encoding(encoding_), FloatRegisters::Simd128);
    638  }
    639 
    640  constexpr uint32_t size() const {
    641    MOZ_ASSERT(!invalid_);
    642    if (kind_ == FloatRegisters::Double) {
    643      return sizeof(double);
    644    }
    645    if (kind_ == FloatRegisters::Single) {
    646      return sizeof(float);
    647    }
    648    MOZ_ASSERT(kind_ == FloatRegisters::Simd128);
    649    return SizeOfSimd128;
    650  }
    651 
    652  constexpr Code code() const {
    653    // assert(!invalid_);
    654    return Codes::fromParts(encoding_, kind_, invalid_);
    655  }
    656 
    657  constexpr Encoding encoding() const {
    658    MOZ_ASSERT(!invalid_);
    659    return Encoding(encoding_);
    660  }
    661 
    662  const char* name() const { return FloatRegisters::GetName(code()); }
    663  bool volatile_() const {
    664    MOZ_ASSERT(!invalid_);
    665    return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
    666  }
    667  constexpr bool operator!=(FloatRegister other) const {
    668    return code() != other.code();
    669  }
    670  constexpr bool operator==(FloatRegister other) const {
    671    return code() == other.code();
    672  }
    673 
    674  bool aliases(FloatRegister other) const {
    675    return other.encoding_ == encoding_;
    676  }
    677  // This function mostly exists for the ARM backend.  It is to ensure that two
    678  // floating point registers' types are equivalent.  e.g. S0 is not equivalent
    679  // to D16, since S0 holds a float32, and D16 holds a Double.
    680  // Since all floating point registers on x86 and x64 are equivalent, it is
    681  // reasonable for this function to do the same.
    682  bool equiv(FloatRegister other) const {
    683    MOZ_ASSERT(!invalid_);
    684    return kind_ == other.kind_;
    685  }
    686 
    687  uint32_t numAliased() const { return Codes::NumTypes; }
    688  uint32_t numAlignedAliased() { return numAliased(); }
    689 
    690  FloatRegister aliased(uint32_t aliasIdx) {
    691    MOZ_ASSERT(!invalid_);
    692    MOZ_ASSERT(aliasIdx < numAliased());
    693    return FloatRegister(Encoding(encoding_),
    694                         Kind((aliasIdx + kind_) % Codes::NumTypes));
    695  }
    696  FloatRegister alignedAliased(uint32_t aliasIdx) { return aliased(aliasIdx); }
    697  SetType alignedOrDominatedAliasedSet() const {
    698    return Codes::AliasMask << encoding_;
    699  }
    700 
    701  static constexpr RegTypeName DefaultType = RegTypeName::Float64;
    702 
    703  template <RegTypeName Name = DefaultType>
    704  static SetType LiveAsIndexableSet(SetType s) {
    705    return SetType(0);
    706  }
    707 
    708  template <RegTypeName Name = DefaultType>
    709  static SetType AllocatableAsIndexableSet(SetType s) {
    710    static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
    711    return LiveAsIndexableSet<Name>(s);
    712  }
    713 
    714  static TypedRegisterSet<FloatRegister> ReduceSetForPush(
    715      const TypedRegisterSet<FloatRegister>& s);
    716  static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
    717  uint32_t getRegisterDumpOffsetInBytes();
    718 
    719  // For N in 0..31, if any of sN, dN or qN is a member of `s`, the
    720  // returned set will contain all of sN, dN and qN.
    721  static TypedRegisterSet<FloatRegister> BroadcastToAllSizes(
    722      const TypedRegisterSet<FloatRegister>& s);
    723 };
    724 
    725 template <>
    726 inline FloatRegister::SetType
    727 FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) {
    728  return set & FloatRegisters::AllSingleMask;
    729 }
    730 
    731 template <>
    732 inline FloatRegister::SetType
    733 FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) {
    734  return set & FloatRegisters::AllDoubleMask;
    735 }
    736 
    737 template <>
    738 inline FloatRegister::SetType
    739 FloatRegister::LiveAsIndexableSet<RegTypeName::Vector128>(SetType set) {
    740  return set & FloatRegisters::AllSimd128Mask;
    741 }
    742 
    743 template <>
    744 inline FloatRegister::SetType
    745 FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) {
    746  return set;
    747 }
    748 
    749 class ARM64Flags final {
    750  // List of enabled CPU features. Initialized once |Init()|.
    751  static inline vixl::CPUFeatures features{};
    752 
    753  // List of disabled CPU features. Must be set before calling |Init()|.
    754  static inline vixl::CPUFeatures disabledFeatures{};
    755 
    756 public:
    757  ARM64Flags() = delete;
    758 
    759  // ARM64Flags::Init is called from the JitContext constructor to read the
    760  // hardware flags. This method must only be called exactly once.
    761  static void Init();
    762 
    763  static bool IsInitialized() { return features != vixl::CPUFeatures::None(); }
    764 
    765  static vixl::CPUFeatures GetCPUFeatures() {
    766    MOZ_ASSERT(IsInitialized());
    767    return features;
    768  }
    769 
    770  // Disable CPU features for testing. Can be called repeatedly to disable
    771  // additional features. Must be called before |Init()|.
    772  static void DisableCPUFeatures(vixl::CPUFeatures features) {
    773    MOZ_ASSERT(!IsInitialized());
    774    disabledFeatures.Combine(features);
    775  }
    776 
    777  static uint32_t GetFlags() {
    778    MOZ_ASSERT(IsInitialized());
    779 
    780    // TODO: vixl::CPUFeatures supports more than 32 values, so it can't be used
    781    // directly for GetFlags.
    782    return 0;
    783  }
    784 };
    785 
    786 // ARM/D32 has double registers that cannot be treated as float32.
    787 // Luckily, ARMv8 doesn't have the same misfortune.
    788 inline bool hasUnaliasedDouble() { return false; }
    789 
    790 // ARM prior to ARMv8 also has doubles that alias multiple floats.
    791 // Again, ARMv8 is in the clear.
    792 inline bool hasMultiAlias() { return false; }
    793 
    794 // Retrieve the ARM64 hardware flags as a bitmask. They must have been set.
    795 inline uint32_t GetARM64Flags() { return ARM64Flags::GetFlags(); }
    796 
    797 bool CanFlushICacheFromBackgroundThreads();
    798 
    799 }  // namespace jit
    800 }  // namespace js
    801 
    802 #endif  // jit_arm64_Architecture_arm64_h