tor-browser

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

Architecture-riscv64.h (15789B)


      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_riscv64_Architecture_riscv64_h
      8 #define jit_riscv64_Architecture_riscv64_h
      9 
     10 // JitSpewer.h is included through MacroAssembler implementations for other
     11 // platforms, so include it here to avoid inadvertent build bustage.
     12 #include "mozilla/MathAlgorithms.h"
     13 
     14 #include <algorithm>
     15 
     16 #include "jit/JitSpewer.h"
     17 #include "jit/shared/Architecture-shared.h"
     18 #include "js/Utility.h"
     19 
     20 namespace js {
     21 namespace jit {
     22 
     23 static const uint32_t SimdMemoryAlignment =
     24    16;  // Make it 4 to avoid a bunch of div-by-zero warnings
     25 
     26 // RISCV64 has 32 64-bit integer registers, x0 though x31.
     27 //  The program counter is not accessible as a register.
     28 
     29 // RISCV INT Register Convention:
     30 // Name          Alias          Usage
     31 // x0            zero           hardwired to 0, ignores writes
     32 // x1            ra             return address for calls
     33 // x2            sp             stack pointer
     34 // x3            gp             global pointer
     35 // x4            tp             thread pointer
     36 // x5-x7         t0-t2          temporary register 0
     37 // x8            fp/s0          Callee-saved register 0 or frame pointer
     38 // x9            s1             Callee-saved register 1
     39 // x10-x11       a0-a1          return value or function argument
     40 // x12-x17       a2-a7          function argument 2
     41 // x18-x27       s2-s11         Callee-saved register
     42 // x28-x31       t3-t6          temporary register 3
     43 
     44 // RISCV-64 FP Register Convention:
     45 //  Name         Alias           Usage
     46 //  $f0-$f7      $ft0-$ft7       Temporary registers
     47 //  $f8-$f9      $fs0-$fs1       Callee-saved registers
     48 //  $f10-$f11    $fa0-$fa1       Return values
     49 //  $f12-$f17    $fa2-$fa7       Args values
     50 //  $f18-$f27    $fs2-$fs11      Callee-saved registers
     51 //  $f28-$f31    $ft8-$ft11      Temporary registers
     52 class Registers {
     53 public:
     54  enum RegisterID {
     55    x0 = 0,
     56    x1,
     57    x2,
     58    x3,
     59    x4,
     60    x5,
     61    x6,
     62    x7,
     63    x8,
     64    x9,
     65    x10,
     66    x11,
     67    x12,
     68    x13,
     69    x14,
     70    x15,
     71    x16,
     72    x17,
     73    x18,
     74    x19,
     75    x20,
     76    x21,
     77    x22,
     78    x23,
     79    x24,
     80    x25,
     81    x26,
     82    x27,
     83    x28,
     84    x29,
     85    x30,
     86    x31,
     87    zero = x0,
     88    ra = x1,
     89    sp = x2,
     90    gp = x3,
     91    tp = x4,
     92    t0 = x5,
     93    t1 = x6,
     94    t2 = x7,
     95    fp = x8,
     96    s1 = x9,
     97    a0 = x10,
     98    a1 = x11,
     99    a2 = x12,
    100    a3 = x13,
    101    a4 = x14,
    102    a5 = x15,
    103    a6 = x16,
    104    a7 = x17,
    105    s2 = x18,
    106    s3 = x19,
    107    s4 = x20,
    108    s5 = x21,
    109    s6 = x22,
    110    s7 = x23,
    111    s8 = x24,
    112    s9 = x25,
    113    s10 = x26,
    114    s11 = x27,
    115    t3 = x28,
    116    t4 = x29,
    117    t5 = x30,
    118    t6 = x31,
    119    invalid_reg,
    120  };
    121  typedef uint8_t Code;
    122  typedef RegisterID Encoding;
    123  union RegisterContent {
    124    uintptr_t r;
    125  };
    126 
    127  typedef uint32_t SetType;
    128 
    129  static uint32_t SetSize(SetType x) {
    130    static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
    131    return mozilla::CountPopulation32(x);
    132  }
    133  static uint32_t FirstBit(SetType x) {
    134    return mozilla::CountTrailingZeroes32(x);
    135  }
    136  static uint32_t LastBit(SetType x) {
    137    return 31 - mozilla::CountLeadingZeroes32(x);
    138  }
    139  static const char* GetName(uint32_t code) {
    140    static const char* const Names[] = {
    141        "zero", "ra", "sp", "gp", "tp",  "t0",  "t1", "t2", "fp", "s1", "a0",
    142        "a1",   "a2", "a3", "a4", "a5",  "a6",  "a7", "s2", "s3", "s4", "s5",
    143        "s6",   "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
    144    static_assert(Total == std::size(Names), "Table is the correct size");
    145    if (code >= Total) {
    146      return "invalid";
    147    }
    148    return Names[code];
    149  }
    150 
    151  static Code FromName(const char*);
    152 
    153  static const Encoding StackPointer = sp;
    154  static const Encoding Invalid = invalid_reg;
    155  static const uint32_t Total = 32;
    156  static const uint32_t TotalPhys = 32;
    157  static const uint32_t Allocatable = 24;
    158  static const SetType NoneMask = 0x0;
    159  static const SetType AllMask = 0xFFFFFFFF;
    160  static const SetType ArgRegMask =
    161      (1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) |
    162      (1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) |
    163      (1 << Registers::a6) | (1 << Registers::a7);
    164 
    165  static const SetType VolatileMask =
    166      ArgRegMask | (1 << Registers::t0) | (1 << Registers::t1) |
    167      (1 << Registers::t2) | (1 << Registers::t3) | (1 << Registers::t4) |
    168      (1 << Registers::t5) | (1 << Registers::t6);
    169 
    170  // We use this constant to save registers when entering functions. This
    171  // is why $ra is added here even though it is not "Non Volatile".
    172  static const SetType NonVolatileMask =
    173      (1 << Registers::ra) | (1 << Registers::fp) | (1 << Registers::s1) |
    174      (1 << Registers::s2) | (1 << Registers::s3) | (1 << Registers::s4) |
    175      (1 << Registers::s5) | (1 << Registers::s6) | (1 << Registers::s7) |
    176      (1 << Registers::s8) | (1 << Registers::s9) | (1 << Registers::s10) |
    177      (1 << Registers::s11);
    178 
    179  static const SetType NonAllocatableMask =
    180      (1 << Registers::zero) |  // Always be zero.
    181      (1 << Registers::t4) |    // Scratch reg
    182      (1 << Registers::t5) |    // Scratch reg
    183      (1 << Registers::t6) |    // Scratch reg or call reg
    184      (1 << Registers::s11) |   // Scratch reg
    185      (1 << Registers::ra) | (1 << Registers::tp) | (1 << Registers::sp) |
    186      (1 << Registers::fp) | (1 << Registers::gp);
    187 
    188  static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    189 
    190  // Registers returned from a JS -> JS call.
    191  static const SetType JSCallMask = (1 << Registers::a2);
    192 
    193  // Registers returned from a JS -> C call.
    194  static const SetType CallMask = (1 << Registers::a0);
    195 
    196  static const SetType WrapperMask = VolatileMask;
    197 };
    198 
    199 // Smallest integer type that can hold a register bitmask.
    200 typedef uint32_t PackedRegisterMask;
    201 
    202 class FloatRegisters {
    203 public:
    204  enum FPRegisterID {
    205    f0 = 0,
    206    f1,
    207    f2,
    208    f3,
    209    f4,
    210    f5,
    211    f6,
    212    f7,
    213    f8,
    214    f9,
    215    f10,
    216    f11,
    217    f12,
    218    f13,
    219    f14,
    220    f15,
    221    f16,
    222    f17,
    223    f18,
    224    f19,
    225    f20,
    226    f21,
    227    f22,
    228    f23,
    229    f24,
    230    f25,
    231    f26,
    232    f27,
    233    f28,
    234    f29,
    235    f30,
    236    f31,
    237    invalid_reg,
    238    ft0 = f0,
    239    ft1 = f1,
    240    ft2 = f2,
    241    ft3 = f3,
    242    ft4 = f4,
    243    ft5 = f5,
    244    ft6 = f6,
    245    ft7 = f7,
    246    fs0 = f8,
    247    fs1 = f9,
    248    fa0 = f10,
    249    fa1 = f11,
    250    fa2 = f12,
    251    fa3 = f13,
    252    fa4 = f14,
    253    fa5 = f15,
    254    fa6 = f16,
    255    fa7 = f17,
    256    fs2 = f18,
    257    fs3 = f19,
    258    fs4 = f20,
    259    fs5 = f21,
    260    fs6 = f22,
    261    fs7 = f23,
    262    fs8 = f24,
    263    fs9 = f25,
    264    fs10 = f26,
    265    fs11 = f27,  // Scratch register
    266    ft8 = f28,
    267    ft9 = f29,
    268    ft10 = f30,  // Scratch register
    269    ft11 = f31
    270  };
    271 
    272  enum Kind : uint8_t { Double, Single, NumTypes };
    273 
    274  // (invalid << 7) | (kind << 5) | encoding
    275  using Code = uint8_t;
    276  using Encoding = FPRegisterID;
    277 
    278  union RegisterContent {
    279    float s;
    280    double d;
    281  };
    282 
    283  static const char* GetName(Code code) {
    284    static const char* const Names[] = {
    285        "ft0", "ft1", "ft2",  "ft3",  "ft4", "ft5", "ft6",  "ft7",
    286        "fs0", "fs1", "fa0",  "fa1",  "fa2", "fa3", "fa4",  "fa5",
    287        "fa6", "fa7", "fs2",  "fs3",  "fs4", "fs5", "fs6",  "fs7",
    288        "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"};
    289    static_assert(TotalPhys == std::size(Names), "Table is the correct size");
    290    if (code >= Total) {
    291      return "invalid";
    292    }
    293    return Names[code & 0x1f];
    294  }
    295 
    296  static Code FromName(const char* name);
    297 
    298  using SetType = uint64_t;
    299 
    300  static const Code Invalid = Code(0b10000000);
    301  static const uint32_t TotalPhys = 32;
    302  static const uint32_t Total = TotalPhys * NumTypes;
    303  static const uint32_t Allocatable = 23;
    304 
    305  static_assert(sizeof(SetType) * 8 >= Total,
    306                "SetType should be large enough to enumerate all registers.");
    307 
    308  // Magic values which are used to duplicate a mask of physical register for
    309  // a specific type of register. A multiplication is used to copy and shift
    310  // the bits of the physical register mask.
    311  static const SetType SpreadSingle = SetType(1)
    312                                      << (uint32_t(Kind::Single) * TotalPhys);
    313  static const SetType SpreadDouble = SetType(1)
    314                                      << (uint32_t(Kind::Double) * TotalPhys);
    315  static const SetType Spread = SpreadSingle | SpreadDouble;
    316 
    317  static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
    318  static const SetType AllMask = AllPhysMask * Spread;
    319  static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
    320  static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
    321  static const SetType NoneMask = SetType(0);
    322 
    323  static const SetType NonVolatileMask =
    324      SetType((1 << FloatRegisters::fs0) | (1 << FloatRegisters::fs1) |
    325              (1 << FloatRegisters::fs2) | (1 << FloatRegisters::fs3) |
    326              (1 << FloatRegisters::fs4) | (1 << FloatRegisters::fs5) |
    327              (1 << FloatRegisters::fs6) | (1 << FloatRegisters::fs7) |
    328              (1 << FloatRegisters::fs8) | (1 << FloatRegisters::fs9) |
    329              (1 << FloatRegisters::fs10) | (1 << FloatRegisters::fs11)) *
    330      Spread;
    331  static const SetType VolatileMask = AllMask & ~NonVolatileMask;
    332 
    333  // fs11/ft10 is the scratch register.
    334  static const SetType NonAllocatableMask =
    335      ((SetType(1) << FloatRegisters::fs11) |
    336       (SetType(1) << FloatRegisters::ft10)) *
    337      Spread;
    338 
    339  static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
    340 };
    341 
    342 template <typename T>
    343 class TypedRegisterSet;
    344 
    345 struct FloatRegister {
    346 public:
    347  using Codes = FloatRegisters;
    348  using Code = Codes::Code;
    349  using Encoding = Codes::Encoding;
    350  using SetType = Codes::SetType;
    351 
    352  static uint32_t SetSize(SetType x) {
    353    static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
    354    x |= x >> FloatRegisters::TotalPhys;
    355    x &= FloatRegisters::AllPhysMask;
    356    return mozilla::CountPopulation32(x);
    357  }
    358 
    359  static uint32_t FirstBit(SetType x) {
    360    static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
    361    return mozilla::CountTrailingZeroes64(x);
    362  }
    363  static uint32_t LastBit(SetType x) {
    364    static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
    365    return 63 - mozilla::CountLeadingZeroes64(x);
    366  }
    367 
    368  static FloatRegister FromCode(Code code) {
    369    MOZ_ASSERT(code < Codes::Total);
    370    const Encoding encoding = Encoding(code & 0x1f);
    371    const Kind kind = Kind((code >> 5) & 0x3);
    372    return FloatRegister(encoding, kind);
    373  }
    374  bool isSimd128() const { return false; }
    375  bool isInvalid() const { return invalid_; }
    376  FloatRegister asSingle() const {
    377    MOZ_ASSERT(!invalid_);
    378    return FloatRegister(Encoding(encoding_), FloatRegisters::Single);
    379  }
    380  FloatRegister asDouble() const {
    381    MOZ_ASSERT(!invalid_);
    382    return FloatRegister(Encoding(encoding_), FloatRegisters::Double);
    383  }
    384  FloatRegister asSimd128() const { MOZ_CRASH(); }
    385  constexpr Code code() const {
    386    MOZ_ASSERT(!invalid_);
    387    return Code((invalid_ << 7) | ((static_cast<uint8_t>(kind_) & 0x3) << 5) |
    388                (static_cast<uint8_t>(encoding_) & 0x1f));
    389  }
    390  constexpr Encoding encoding() const { return encoding_; }
    391  const char* name() const { return FloatRegisters::GetName(encoding()); }
    392  bool volatile_() const {
    393    MOZ_ASSERT(!invalid_);
    394    return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
    395  }
    396  bool operator!=(FloatRegister other) const { return code() != other.code(); }
    397  bool operator==(FloatRegister other) const { return code() == other.code(); }
    398  bool aliases(FloatRegister other) const {
    399    return other.encoding_ == encoding_;
    400  }
    401  uint32_t numAliased() const { return FloatRegisters::NumTypes; }
    402  FloatRegister aliased(uint32_t aliasIdx) const {
    403    MOZ_ASSERT(!invalid_);
    404    MOZ_ASSERT(aliasIdx < numAliased());
    405    return FloatRegister(Encoding(encoding_),
    406                         Kind((aliasIdx + kind_) % numAliased()));
    407  }
    408  // Ensure that two floating point registers' types are equivalent.
    409  bool equiv(FloatRegister other) const {
    410    MOZ_ASSERT(!invalid_);
    411    return kind_ == other.kind_;
    412  }
    413  constexpr uint32_t size() const {
    414    MOZ_ASSERT(!invalid_);
    415    if (kind_ == FloatRegisters::Double) {
    416      return sizeof(double);
    417    }
    418    MOZ_ASSERT(kind_ == FloatRegisters::Single);
    419    return sizeof(float);
    420  }
    421  uint32_t numAlignedAliased() { return numAliased(); }
    422  FloatRegister alignedAliased(uint32_t aliasIdx) {
    423    MOZ_ASSERT(aliasIdx < numAliased());
    424    return aliased(aliasIdx);
    425  }
    426  SetType alignedOrDominatedAliasedSet() const {
    427    return Codes::Spread << encoding_;
    428  }
    429  static constexpr RegTypeName DefaultType = RegTypeName::Float64;
    430 
    431  template <RegTypeName Name = DefaultType>
    432  static SetType LiveAsIndexableSet(SetType s) {
    433    return SetType(0);
    434  }
    435 
    436  template <RegTypeName Name = DefaultType>
    437  static SetType AllocatableAsIndexableSet(SetType s) {
    438    static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
    439    return LiveAsIndexableSet<Name>(s);
    440  }
    441 
    442  FloatRegister singleOverlay() const;
    443  FloatRegister doubleOverlay() const;
    444 
    445  static TypedRegisterSet<FloatRegister> ReduceSetForPush(
    446      const TypedRegisterSet<FloatRegister>& s);
    447 
    448  uint32_t getRegisterDumpOffsetInBytes() {
    449 #ifdef ENABLE_WASM_SIMD
    450 #  error "Needs more careful logic if SIMD is enabled"
    451 #endif
    452 
    453    return encoding() * sizeof(double);
    454  }
    455  static Code FromName(const char* name);
    456 
    457  // This is used in static initializers, so produce a bogus value instead of
    458  // crashing.
    459  static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
    460 
    461 private:
    462  using Kind = Codes::Kind;
    463  // These fields only hold valid values: an invalid register is always
    464  // represented as a valid encoding and kind with the invalid_ bit set.
    465  Encoding encoding_;  // 32 encodings
    466  Kind kind_;          // Double, Single; more later
    467  bool invalid_;
    468 
    469 public:
    470  constexpr FloatRegister(Encoding encoding, Kind kind)
    471      : encoding_(encoding), kind_(kind), invalid_(false) {
    472    MOZ_ASSERT(uint32_t(encoding) < Codes::Total);
    473  }
    474 
    475  constexpr explicit FloatRegister(Encoding encoding)
    476      : encoding_(encoding), kind_(FloatRegisters::Double), invalid_(false) {
    477    MOZ_ASSERT(uint32_t(encoding) < Codes::Total);
    478  }
    479 
    480  constexpr FloatRegister()
    481      : encoding_(FloatRegisters::invalid_reg),
    482        kind_(FloatRegisters::Double),
    483        invalid_(true) {}
    484 
    485  bool isSingle() const {
    486    MOZ_ASSERT(!invalid_);
    487    return kind_ == FloatRegisters::Single;
    488  }
    489 
    490  bool isDouble() const {
    491    MOZ_ASSERT(!invalid_);
    492    return kind_ == FloatRegisters::Double;
    493  }
    494 };
    495 
    496 template <>
    497 inline FloatRegister::SetType
    498 FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) {
    499  return set & FloatRegisters::AllSingleMask;
    500 }
    501 
    502 template <>
    503 inline FloatRegister::SetType
    504 FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) {
    505  return set & FloatRegisters::AllDoubleMask;
    506 }
    507 
    508 template <>
    509 inline FloatRegister::SetType
    510 FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) {
    511  return set;
    512 }
    513 
    514 inline bool hasUnaliasedDouble() { return false; }
    515 inline bool hasMultiAlias() { return false; }
    516 
    517 static constexpr uint32_t ShadowStackSpace = 0;
    518 static const uint32_t JumpImmediateRange = INT32_MAX;
    519 
    520 #ifdef JS_NUNBOX32
    521 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
    522 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
    523 #endif
    524 
    525 static const uint32_t SpillSlotSize =
    526    std::max(sizeof(Registers::RegisterContent),
    527             sizeof(FloatRegisters::RegisterContent));
    528 
    529 inline uint32_t GetRISCV64Flags() { return 0; }
    530 
    531 }  // namespace jit
    532 }  // namespace js
    533 
    534 #endif /* jit_riscv64_Architecture_riscv64_h */