tor-browser

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

Simulator-loong64.cpp (140470B)


      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 // Copyright 2020 the V8 project authors. All rights reserved.
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 //       notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 //       copyright notice, this list of conditions and the following
     12 //       disclaimer in the documentation and/or other materials provided
     13 //       with the distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 //       contributors may be used to endorse or promote products derived
     16 //       from this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include "jit/loong64/Simulator-loong64.h"
     31 
     32 #include <cinttypes>
     33 #include <float.h>
     34 #include <limits>
     35 
     36 #include "jit/AtomicOperations.h"
     37 #include "jit/loong64/Assembler-loong64.h"
     38 #include "js/Conversions.h"
     39 #include "threading/LockGuard.h"
     40 #include "vm/JSContext.h"
     41 #include "vm/Runtime.h"
     42 #include "wasm/WasmInstance.h"
     43 #include "wasm/WasmSignalHandlers.h"
     44 
     45 #define I8(v) static_cast<int8_t>(v)
     46 #define I16(v) static_cast<int16_t>(v)
     47 #define U16(v) static_cast<uint16_t>(v)
     48 #define I32(v) static_cast<int32_t>(v)
     49 #define U32(v) static_cast<uint32_t>(v)
     50 #define I64(v) static_cast<int64_t>(v)
     51 #define U64(v) static_cast<uint64_t>(v)
     52 #define I128(v) static_cast<__int128_t>(v)
     53 #define U128(v) static_cast<__uint128_t>(v)
     54 
     55 #define I32_CHECK(v)                   \
     56  ({                                   \
     57    MOZ_ASSERT(I64(I32(v)) == I64(v)); \
     58    I32((v));                          \
     59  })
     60 
     61 namespace js {
     62 namespace jit {
     63 
     64 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
     65  uint64_t u0, v0, w0;
     66  int64_t u1, v1, w1, w2, t;
     67 
     68  u0 = u & 0xFFFFFFFFL;
     69  u1 = u >> 32;
     70  v0 = v & 0xFFFFFFFFL;
     71  v1 = v >> 32;
     72 
     73  w0 = u0 * v0;
     74  t = u1 * v0 + (w0 >> 32);
     75  w1 = t & 0xFFFFFFFFL;
     76  w2 = t >> 32;
     77  w1 = u0 * v1 + w1;
     78 
     79  return u1 * v1 + w2 + (w1 >> 32);
     80 }
     81 
     82 static uint64_t MultiplyHighUnsigned(uint64_t u, uint64_t v) {
     83  uint64_t u0, v0, w0;
     84  uint64_t u1, v1, w1, w2, t;
     85 
     86  u0 = u & 0xFFFFFFFFL;
     87  u1 = u >> 32;
     88  v0 = v & 0xFFFFFFFFL;
     89  v1 = v >> 32;
     90 
     91  w0 = u0 * v0;
     92  t = u1 * v0 + (w0 >> 32);
     93  w1 = t & 0xFFFFFFFFL;
     94  w2 = t >> 32;
     95  w1 = u0 * v1 + w1;
     96 
     97  return u1 * v1 + w2 + (w1 >> 32);
     98 }
     99 
    100 // Precondition: 0 <= shift < 32
    101 inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) {
    102  return (value >> shift) | (value << ((32 - shift) & 31));
    103 }
    104 
    105 // Precondition: 0 <= shift < 32
    106 inline constexpr uint32_t RotateLeft32(uint32_t value, uint32_t shift) {
    107  return (value << shift) | (value >> ((32 - shift) & 31));
    108 }
    109 
    110 // Precondition: 0 <= shift < 64
    111 inline constexpr uint64_t RotateRight64(uint64_t value, uint64_t shift) {
    112  return (value >> shift) | (value << ((64 - shift) & 63));
    113 }
    114 
    115 // Precondition: 0 <= shift < 64
    116 inline constexpr uint64_t RotateLeft64(uint64_t value, uint64_t shift) {
    117  return (value << shift) | (value >> ((64 - shift) & 63));
    118 }
    119 
    120 // break instr with MAX_BREAK_CODE.
    121 static const Instr kCallRedirInstr = op_break | CODEMask;
    122 
    123 // -----------------------------------------------------------------------------
    124 // LoongArch64 assembly various constants.
    125 
    126 class SimInstruction {
    127 public:
    128  enum {
    129    kInstrSize = 4,
    130    // On LoongArch, PC cannot actually be directly accessed. We behave as if PC
    131    // was always the value of the current instruction being executed.
    132    kPCReadOffset = 0
    133  };
    134 
    135  // Get the raw instruction bits.
    136  inline Instr instructionBits() const {
    137    return *reinterpret_cast<const Instr*>(this);
    138  }
    139 
    140  // Set the raw instruction bits to value.
    141  inline void setInstructionBits(Instr value) {
    142    *reinterpret_cast<Instr*>(this) = value;
    143  }
    144 
    145  // Read one particular bit out of the instruction bits.
    146  inline int bit(int nr) const { return (instructionBits() >> nr) & 1; }
    147 
    148  // Read a bit field out of the instruction bits.
    149  inline int bits(int hi, int lo) const {
    150    return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
    151  }
    152 
    153  // Instruction type.
    154  enum Type {
    155    kUnsupported = -1,
    156    kOp6Type,
    157    kOp7Type,
    158    kOp8Type,
    159    kOp10Type,
    160    kOp11Type,
    161    kOp12Type,
    162    kOp14Type,
    163    kOp15Type,
    164    kOp16Type,
    165    kOp17Type,
    166    kOp22Type,
    167    kOp24Type
    168  };
    169 
    170  // Get the encoding type of the instruction.
    171  Type instructionType() const;
    172 
    173  inline int rjValue() const { return bits(RJShift + RJBits - 1, RJShift); }
    174 
    175  inline int rkValue() const { return bits(RKShift + RKBits - 1, RKShift); }
    176 
    177  inline int rdValue() const { return bits(RDShift + RDBits - 1, RDShift); }
    178 
    179  inline int sa2Value() const { return bits(SAShift + SA2Bits - 1, SAShift); }
    180 
    181  inline int sa3Value() const { return bits(SAShift + SA3Bits - 1, SAShift); }
    182 
    183  inline int lsbwValue() const {
    184    return bits(LSBWShift + LSBWBits - 1, LSBWShift);
    185  }
    186 
    187  inline int msbwValue() const {
    188    return bits(MSBWShift + MSBWBits - 1, MSBWShift);
    189  }
    190 
    191  inline int lsbdValue() const {
    192    return bits(LSBDShift + LSBDBits - 1, LSBDShift);
    193  }
    194 
    195  inline int msbdValue() const {
    196    return bits(MSBDShift + MSBDBits - 1, MSBDShift);
    197  }
    198 
    199  inline int fdValue() const { return bits(FDShift + FDBits - 1, FDShift); }
    200 
    201  inline int fjValue() const { return bits(FJShift + FJBits - 1, FJShift); }
    202 
    203  inline int fkValue() const { return bits(FKShift + FKBits - 1, FKShift); }
    204 
    205  inline int faValue() const { return bits(FAShift + FABits - 1, FAShift); }
    206 
    207  inline int cdValue() const { return bits(CDShift + CDBits - 1, CDShift); }
    208 
    209  inline int cjValue() const { return bits(CJShift + CJBits - 1, CJShift); }
    210 
    211  inline int caValue() const { return bits(CAShift + CABits - 1, CAShift); }
    212 
    213  inline int condValue() const {
    214    return bits(CONDShift + CONDBits - 1, CONDShift);
    215  }
    216 
    217  inline int imm5Value() const {
    218    return bits(Imm5Shift + Imm5Bits - 1, Imm5Shift);
    219  }
    220 
    221  inline int imm6Value() const {
    222    return bits(Imm6Shift + Imm6Bits - 1, Imm6Shift);
    223  }
    224 
    225  inline int imm12Value() const {
    226    return bits(Imm12Shift + Imm12Bits - 1, Imm12Shift);
    227  }
    228 
    229  inline int imm14Value() const {
    230    return bits(Imm14Shift + Imm14Bits - 1, Imm14Shift);
    231  }
    232 
    233  inline int imm16Value() const {
    234    return bits(Imm16Shift + Imm16Bits - 1, Imm16Shift);
    235  }
    236 
    237  inline int imm20Value() const {
    238    return bits(Imm20Shift + Imm20Bits - 1, Imm20Shift);
    239  }
    240 
    241  inline int32_t imm26Value() const {
    242    return bits(Imm26Shift + Imm26Bits - 1, Imm26Shift);
    243  }
    244 
    245  // Say if the instruction is a debugger break/trap.
    246  bool isTrap() const;
    247 
    248 private:
    249  SimInstruction() = delete;
    250  SimInstruction(const SimInstruction& other) = delete;
    251  void operator=(const SimInstruction& other) = delete;
    252 };
    253 
    254 bool SimInstruction::isTrap() const {
    255  // is break??
    256  switch (bits(31, 15) << 15) {
    257    case op_break:
    258      return (instructionBits() != kCallRedirInstr) && (bits(15, 0) != 6);
    259    default:
    260      return false;
    261  };
    262 }
    263 
    264 SimInstruction::Type SimInstruction::instructionType() const {
    265  SimInstruction::Type kType = kUnsupported;
    266 
    267  // Check for kOp6Type
    268  switch (bits(31, 26) << 26) {
    269    case op_beqz:
    270    case op_bnez:
    271    case op_bcz:
    272    case op_jirl:
    273    case op_b:
    274    case op_bl:
    275    case op_beq:
    276    case op_bne:
    277    case op_blt:
    278    case op_bge:
    279    case op_bltu:
    280    case op_bgeu:
    281    case op_addu16i_d:
    282      kType = kOp6Type;
    283      break;
    284    default:
    285      kType = kUnsupported;
    286  }
    287 
    288  if (kType == kUnsupported) {
    289    // Check for kOp7Type
    290    switch (bits(31, 25) << 25) {
    291      case op_lu12i_w:
    292      case op_lu32i_d:
    293      case op_pcaddi:
    294      case op_pcalau12i:
    295      case op_pcaddu12i:
    296      case op_pcaddu18i:
    297        kType = kOp7Type;
    298        break;
    299      default:
    300        kType = kUnsupported;
    301    }
    302  }
    303 
    304  if (kType == kUnsupported) {
    305    // Check for kOp8Type
    306    switch (bits(31, 24) << 24) {
    307      case op_ll_w:
    308      case op_sc_w:
    309      case op_ll_d:
    310      case op_sc_d:
    311      case op_ldptr_w:
    312      case op_stptr_w:
    313      case op_ldptr_d:
    314      case op_stptr_d:
    315        kType = kOp8Type;
    316        break;
    317      default:
    318        kType = kUnsupported;
    319    }
    320  }
    321 
    322  if (kType == kUnsupported) {
    323    // Check for kOp10Type
    324    switch (bits(31, 22) << 22) {
    325      case op_bstrins_d:
    326      case op_bstrpick_d:
    327      case op_slti:
    328      case op_sltui:
    329      case op_addi_w:
    330      case op_addi_d:
    331      case op_lu52i_d:
    332      case op_andi:
    333      case op_ori:
    334      case op_xori:
    335      case op_ld_b:
    336      case op_ld_h:
    337      case op_ld_w:
    338      case op_ld_d:
    339      case op_st_b:
    340      case op_st_h:
    341      case op_st_w:
    342      case op_st_d:
    343      case op_ld_bu:
    344      case op_ld_hu:
    345      case op_ld_wu:
    346      case op_preld:
    347      case op_fld_s:
    348      case op_fst_s:
    349      case op_fld_d:
    350      case op_fst_d:
    351      case op_bstr_w:  // BSTRINS_W & BSTRPICK_W
    352        kType = kOp10Type;
    353        break;
    354      default:
    355        kType = kUnsupported;
    356    }
    357  }
    358 
    359  if (kType == kUnsupported) {
    360    // Check for kOp11Type
    361    switch (bits(31, 21) << 21) {
    362      case op_bstr_w:
    363        kType = kOp11Type;
    364        break;
    365      default:
    366        kType = kUnsupported;
    367    }
    368  }
    369 
    370  if (kType == kUnsupported) {
    371    // Check for kOp12Type
    372    switch (bits(31, 20) << 20) {
    373      case op_fmadd_s:
    374      case op_fmadd_d:
    375      case op_fmsub_s:
    376      case op_fmsub_d:
    377      case op_fnmadd_s:
    378      case op_fnmadd_d:
    379      case op_fnmsub_s:
    380      case op_fnmsub_d:
    381      case op_fcmp_cond_s:
    382      case op_fcmp_cond_d:
    383        kType = kOp12Type;
    384        break;
    385      default:
    386        kType = kUnsupported;
    387    }
    388  }
    389 
    390  if (kType == kUnsupported) {
    391    // Check for kOp14Type
    392    switch (bits(31, 18) << 18) {
    393      case op_bytepick_d:
    394      case op_fsel:
    395        kType = kOp14Type;
    396        break;
    397      default:
    398        kType = kUnsupported;
    399    }
    400  }
    401 
    402  if (kType == kUnsupported) {
    403    // Check for kOp15Type
    404    switch (bits(31, 17) << 17) {
    405      case op_bytepick_w:
    406      case op_alsl_w:
    407      case op_alsl_wu:
    408      case op_alsl_d:
    409        kType = kOp15Type;
    410        break;
    411      default:
    412        kType = kUnsupported;
    413    }
    414  }
    415 
    416  if (kType == kUnsupported) {
    417    // Check for kOp16Type
    418    switch (bits(31, 16) << 16) {
    419      case op_slli_d:
    420      case op_srli_d:
    421      case op_srai_d:
    422      case op_rotri_d:
    423        kType = kOp16Type;
    424        break;
    425      default:
    426        kType = kUnsupported;
    427    }
    428  }
    429 
    430  if (kType == kUnsupported) {
    431    // Check for kOp17Type
    432    switch (bits(31, 15) << 15) {
    433      case op_slli_w:
    434      case op_srli_w:
    435      case op_srai_w:
    436      case op_rotri_w:
    437      case op_add_w:
    438      case op_add_d:
    439      case op_sub_w:
    440      case op_sub_d:
    441      case op_slt:
    442      case op_sltu:
    443      case op_maskeqz:
    444      case op_masknez:
    445      case op_nor:
    446      case op_and:
    447      case op_or:
    448      case op_xor:
    449      case op_orn:
    450      case op_andn:
    451      case op_sll_w:
    452      case op_srl_w:
    453      case op_sra_w:
    454      case op_sll_d:
    455      case op_srl_d:
    456      case op_sra_d:
    457      case op_rotr_w:
    458      case op_rotr_d:
    459      case op_mul_w:
    460      case op_mul_d:
    461      case op_mulh_d:
    462      case op_mulh_du:
    463      case op_mulh_w:
    464      case op_mulh_wu:
    465      case op_mulw_d_w:
    466      case op_mulw_d_wu:
    467      case op_div_w:
    468      case op_mod_w:
    469      case op_div_wu:
    470      case op_mod_wu:
    471      case op_div_d:
    472      case op_mod_d:
    473      case op_div_du:
    474      case op_mod_du:
    475      case op_break:
    476      case op_fadd_s:
    477      case op_fadd_d:
    478      case op_fsub_s:
    479      case op_fsub_d:
    480      case op_fmul_s:
    481      case op_fmul_d:
    482      case op_fdiv_s:
    483      case op_fdiv_d:
    484      case op_fmax_s:
    485      case op_fmax_d:
    486      case op_fmin_s:
    487      case op_fmin_d:
    488      case op_fmaxa_s:
    489      case op_fmaxa_d:
    490      case op_fmina_s:
    491      case op_fmina_d:
    492      case op_fcopysign_s:
    493      case op_fcopysign_d:
    494      case op_ldx_b:
    495      case op_ldx_h:
    496      case op_ldx_w:
    497      case op_ldx_d:
    498      case op_stx_b:
    499      case op_stx_h:
    500      case op_stx_w:
    501      case op_stx_d:
    502      case op_ldx_bu:
    503      case op_ldx_hu:
    504      case op_ldx_wu:
    505      case op_fldx_s:
    506      case op_fldx_d:
    507      case op_fstx_s:
    508      case op_fstx_d:
    509      case op_amswap_w:
    510      case op_amswap_d:
    511      case op_amadd_w:
    512      case op_amadd_d:
    513      case op_amand_w:
    514      case op_amand_d:
    515      case op_amor_w:
    516      case op_amor_d:
    517      case op_amxor_w:
    518      case op_amxor_d:
    519      case op_ammax_w:
    520      case op_ammax_d:
    521      case op_ammin_w:
    522      case op_ammin_d:
    523      case op_ammax_wu:
    524      case op_ammax_du:
    525      case op_ammin_wu:
    526      case op_ammin_du:
    527      case op_amswap_db_w:
    528      case op_amswap_db_d:
    529      case op_amadd_db_w:
    530      case op_amadd_db_d:
    531      case op_amand_db_w:
    532      case op_amand_db_d:
    533      case op_amor_db_w:
    534      case op_amor_db_d:
    535      case op_amxor_db_w:
    536      case op_amxor_db_d:
    537      case op_ammax_db_w:
    538      case op_ammax_db_d:
    539      case op_ammin_db_w:
    540      case op_ammin_db_d:
    541      case op_ammax_db_wu:
    542      case op_ammax_db_du:
    543      case op_ammin_db_wu:
    544      case op_ammin_db_du:
    545      case op_dbar:
    546      case op_ibar:
    547        kType = kOp17Type;
    548        break;
    549      default:
    550        kType = kUnsupported;
    551    }
    552  }
    553 
    554  if (kType == kUnsupported) {
    555    // Check for kOp22Type
    556    switch (bits(31, 10) << 10) {
    557      case op_clo_w:
    558      case op_clz_w:
    559      case op_cto_w:
    560      case op_ctz_w:
    561      case op_clo_d:
    562      case op_clz_d:
    563      case op_cto_d:
    564      case op_ctz_d:
    565      case op_revb_2h:
    566      case op_revb_4h:
    567      case op_revb_2w:
    568      case op_revb_d:
    569      case op_revh_2w:
    570      case op_revh_d:
    571      case op_bitrev_4b:
    572      case op_bitrev_8b:
    573      case op_bitrev_w:
    574      case op_bitrev_d:
    575      case op_ext_w_h:
    576      case op_ext_w_b:
    577      case op_fabs_s:
    578      case op_fabs_d:
    579      case op_fneg_s:
    580      case op_fneg_d:
    581      case op_fsqrt_s:
    582      case op_fsqrt_d:
    583      case op_fmov_s:
    584      case op_fmov_d:
    585      case op_movgr2fr_w:
    586      case op_movgr2fr_d:
    587      case op_movgr2frh_w:
    588      case op_movfr2gr_s:
    589      case op_movfr2gr_d:
    590      case op_movfrh2gr_s:
    591      case op_movfcsr2gr:
    592      case op_movfr2cf:
    593      case op_movgr2cf:
    594      case op_fcvt_s_d:
    595      case op_fcvt_d_s:
    596      case op_ftintrm_w_s:
    597      case op_ftintrm_w_d:
    598      case op_ftintrm_l_s:
    599      case op_ftintrm_l_d:
    600      case op_ftintrp_w_s:
    601      case op_ftintrp_w_d:
    602      case op_ftintrp_l_s:
    603      case op_ftintrp_l_d:
    604      case op_ftintrz_w_s:
    605      case op_ftintrz_w_d:
    606      case op_ftintrz_l_s:
    607      case op_ftintrz_l_d:
    608      case op_ftintrne_w_s:
    609      case op_ftintrne_w_d:
    610      case op_ftintrne_l_s:
    611      case op_ftintrne_l_d:
    612      case op_ftint_w_s:
    613      case op_ftint_w_d:
    614      case op_ftint_l_s:
    615      case op_ftint_l_d:
    616      case op_ffint_s_w:
    617      case op_ffint_s_l:
    618      case op_ffint_d_w:
    619      case op_ffint_d_l:
    620      case op_frint_s:
    621      case op_frint_d:
    622        kType = kOp22Type;
    623        break;
    624      default:
    625        kType = kUnsupported;
    626    }
    627  }
    628 
    629  if (kType == kUnsupported) {
    630    // Check for kOp24Type
    631    switch (bits(31, 8) << 8) {
    632      case op_movcf2fr:
    633      case op_movcf2gr:
    634        kType = kOp24Type;
    635        break;
    636      default:
    637        kType = kUnsupported;
    638    }
    639  }
    640 
    641  return kType;
    642 }
    643 
    644 // C/C++ argument slots size.
    645 const int kCArgSlotCount = 0;
    646 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t);
    647 
    648 class CachePage {
    649 public:
    650  static const int LINE_VALID = 0;
    651  static const int LINE_INVALID = 1;
    652 
    653  static const int kPageShift = 12;
    654  static const int kPageSize = 1 << kPageShift;
    655  static const int kPageMask = kPageSize - 1;
    656  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
    657  static const int kLineLength = 1 << kLineShift;
    658  static const int kLineMask = kLineLength - 1;
    659 
    660  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
    661 
    662  char* validityByte(int offset) {
    663    return &validity_map_[offset >> kLineShift];
    664  }
    665 
    666  char* cachedData(int offset) { return &data_[offset]; }
    667 
    668 private:
    669  char data_[kPageSize];  // The cached data.
    670  static const int kValidityMapSize = kPageSize >> kLineShift;
    671  char validity_map_[kValidityMapSize];  // One byte per line.
    672 };
    673 
    674 // Protects the icache() and redirection() properties of the
    675 // Simulator.
    676 class AutoLockSimulatorCache : public LockGuard<Mutex> {
    677  using Base = LockGuard<Mutex>;
    678 
    679 public:
    680  explicit AutoLockSimulatorCache()
    681      : Base(SimulatorProcess::singleton_->cacheLock_) {}
    682 };
    683 
    684 mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    685    SimulatorProcess::ICacheCheckingDisableCount(
    686        1);  // Checking is disabled by default.
    687 SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
    688 
    689 int64_t Simulator::StopSimAt = -1;
    690 
    691 Simulator* Simulator::Create() {
    692  auto sim = MakeUnique<Simulator>();
    693  if (!sim) {
    694    return nullptr;
    695  }
    696 
    697  if (!sim->init()) {
    698    return nullptr;
    699  }
    700 
    701  int64_t stopAt;
    702  char* stopAtStr = getenv("LOONG64_SIM_STOP_AT");
    703  if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) {
    704    fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt);
    705    Simulator::StopSimAt = stopAt;
    706  }
    707 
    708  return sim.release();
    709 }
    710 
    711 void Simulator::Destroy(Simulator* sim) { js_delete(sim); }
    712 
    713 // The loong64Debugger class is used by the simulator while debugging simulated
    714 // code.
    715 class loong64Debugger {
    716 public:
    717  explicit loong64Debugger(Simulator* sim) : sim_(sim) {}
    718 
    719  void stop(SimInstruction* instr);
    720  void debug();
    721  // Print all registers with a nice formatting.
    722  void printAllRegs();
    723  void printAllRegsIncludingFPU();
    724 
    725 private:
    726  // We set the breakpoint code to 0x7fff to easily recognize it.
    727  static const Instr kBreakpointInstr = op_break | (0x7fff & CODEMask);
    728  static const Instr kNopInstr = 0x0;
    729 
    730  Simulator* sim_;
    731 
    732  int64_t getRegisterValue(int regnum);
    733  int64_t getFPURegisterValueLong(int regnum);
    734  float getFPURegisterValueFloat(int regnum);
    735  double getFPURegisterValueDouble(int regnum);
    736  bool getValue(const char* desc, int64_t* value);
    737 
    738  // Set or delete a breakpoint. Returns true if successful.
    739  bool setBreakpoint(SimInstruction* breakpc);
    740  bool deleteBreakpoint(SimInstruction* breakpc);
    741 
    742  // Undo and redo all breakpoints. This is needed to bracket disassembly and
    743  // execution to skip past breakpoints when run from the debugger.
    744  void undoBreakpoints();
    745  void redoBreakpoints();
    746 };
    747 
    748 static void UNIMPLEMENTED() {
    749  printf("UNIMPLEMENTED instruction.\n");
    750  MOZ_CRASH();
    751 }
    752 static void UNREACHABLE() {
    753  printf("UNREACHABLE instruction.\n");
    754  MOZ_CRASH();
    755 }
    756 static void UNSUPPORTED() {
    757  printf("Unsupported instruction.\n");
    758  MOZ_CRASH();
    759 }
    760 
    761 void loong64Debugger::stop(SimInstruction* instr) {
    762  // Get the stop code.
    763  uint32_t code = instr->bits(25, 6);
    764  // Retrieve the encoded address, which comes just after this stop.
    765  char* msg =
    766      *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize);
    767  // Update this stop description.
    768  if (!sim_->watchedStops_[code].desc_) {
    769    sim_->watchedStops_[code].desc_ = msg;
    770  }
    771  // Print the stop message and code if it is not the default code.
    772  if (code != kMaxStopCode) {
    773    printf("Simulator hit stop %u: %s\n", code, msg);
    774  } else {
    775    printf("Simulator hit %s\n", msg);
    776  }
    777  sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
    778  debug();
    779 }
    780 
    781 int64_t loong64Debugger::getRegisterValue(int regnum) {
    782  if (regnum == kPCRegister) {
    783    return sim_->get_pc();
    784  }
    785  return sim_->getRegister(regnum);
    786 }
    787 
    788 int64_t loong64Debugger::getFPURegisterValueLong(int regnum) {
    789  return sim_->getFpuRegister(regnum);
    790 }
    791 
    792 float loong64Debugger::getFPURegisterValueFloat(int regnum) {
    793  return sim_->getFpuRegisterFloat(regnum);
    794 }
    795 
    796 double loong64Debugger::getFPURegisterValueDouble(int regnum) {
    797  return sim_->getFpuRegisterDouble(regnum);
    798 }
    799 
    800 bool loong64Debugger::getValue(const char* desc, int64_t* value) {
    801  Register reg = Register::FromName(desc);
    802  if (reg != InvalidReg) {
    803    *value = getRegisterValue(reg.code());
    804    return true;
    805  }
    806 
    807  if (strncmp(desc, "0x", 2) == 0) {
    808    return sscanf(desc + 2, "%" PRIx64, reinterpret_cast<uint64_t*>(value)) ==
    809           1;
    810  }
    811  return sscanf(desc, "%" PRIu64, reinterpret_cast<uint64_t*>(value)) == 1;
    812 }
    813 
    814 bool loong64Debugger::setBreakpoint(SimInstruction* breakpc) {
    815  // Check if a breakpoint can be set. If not return without any side-effects.
    816  if (sim_->break_pc_ != nullptr) {
    817    return false;
    818  }
    819 
    820  // Set the breakpoint.
    821  sim_->break_pc_ = breakpc;
    822  sim_->break_instr_ = breakpc->instructionBits();
    823  // Not setting the breakpoint instruction in the code itself. It will be set
    824  // when the debugger shell continues.
    825  return true;
    826 }
    827 
    828 bool loong64Debugger::deleteBreakpoint(SimInstruction* breakpc) {
    829  if (sim_->break_pc_ != nullptr) {
    830    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    831  }
    832 
    833  sim_->break_pc_ = nullptr;
    834  sim_->break_instr_ = 0;
    835  return true;
    836 }
    837 
    838 void loong64Debugger::undoBreakpoints() {
    839  if (sim_->break_pc_) {
    840    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    841  }
    842 }
    843 
    844 void loong64Debugger::redoBreakpoints() {
    845  if (sim_->break_pc_) {
    846    sim_->break_pc_->setInstructionBits(kBreakpointInstr);
    847  }
    848 }
    849 
    850 void loong64Debugger::printAllRegs() {
    851  int64_t value;
    852  for (uint32_t i = 0; i < Registers::Total; i++) {
    853    value = getRegisterValue(i);
    854    printf("%3s: 0x%016" PRIx64 " %20" PRIi64 "   ", Registers::GetName(i),
    855           value, value);
    856 
    857    if (i % 2) {
    858      printf("\n");
    859    }
    860  }
    861  printf("\n");
    862 
    863  value = getRegisterValue(Simulator::pc);
    864  printf(" pc: 0x%016" PRIx64 "\n", value);
    865 }
    866 
    867 void loong64Debugger::printAllRegsIncludingFPU() {
    868  printAllRegs();
    869 
    870  printf("\n\n");
    871  // f0, f1, f2, ... f31.
    872  for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
    873    printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
    874           FloatRegisters::GetName(i), getFPURegisterValueLong(i),
    875           getFPURegisterValueFloat(i), getFPURegisterValueDouble(i));
    876  }
    877 }
    878 
    879 static char* ReadLine(const char* prompt) {
    880  UniqueChars result;
    881  char lineBuf[256];
    882  int offset = 0;
    883  bool keepGoing = true;
    884  fprintf(stdout, "%s", prompt);
    885  fflush(stdout);
    886  while (keepGoing) {
    887    if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
    888      // fgets got an error. Just give up.
    889      return nullptr;
    890    }
    891    int len = strlen(lineBuf);
    892    if (len > 0 && lineBuf[len - 1] == '\n') {
    893      // Since we read a new line we are done reading the line. This
    894      // will exit the loop after copying this buffer into the result.
    895      keepGoing = false;
    896    }
    897    if (!result) {
    898      // Allocate the initial result and make room for the terminating '\0'
    899      result.reset(js_pod_malloc<char>(len + 1));
    900      if (!result) {
    901        return nullptr;
    902      }
    903    } else {
    904      // Allocate a new result with enough room for the new addition.
    905      int new_len = offset + len + 1;
    906      char* new_result = js_pod_malloc<char>(new_len);
    907      if (!new_result) {
    908        return nullptr;
    909      }
    910      // Copy the existing input into the new array and set the new
    911      // array as the result.
    912      memcpy(new_result, result.get(), offset * sizeof(char));
    913      result.reset(new_result);
    914    }
    915    // Copy the newly read line into the result.
    916    memcpy(result.get() + offset, lineBuf, len * sizeof(char));
    917    offset += len;
    918  }
    919 
    920  MOZ_ASSERT(result);
    921  result[offset] = '\0';
    922  return result.release();
    923 }
    924 
    925 static void DisassembleInstruction(uint64_t pc) {
    926  printf("Not supported on loongarch64 yet\n");
    927 }
    928 
    929 void loong64Debugger::debug() {
    930  intptr_t lastPC = -1;
    931  bool done = false;
    932 
    933 #define COMMAND_SIZE 63
    934 #define ARG_SIZE 255
    935 
    936 #define STR(a) #a
    937 #define XSTR(a) STR(a)
    938 
    939  char cmd[COMMAND_SIZE + 1];
    940  char arg1[ARG_SIZE + 1];
    941  char arg2[ARG_SIZE + 1];
    942  char* argv[3] = {cmd, arg1, arg2};
    943 
    944  // Make sure to have a proper terminating character if reaching the limit.
    945  cmd[COMMAND_SIZE] = 0;
    946  arg1[ARG_SIZE] = 0;
    947  arg2[ARG_SIZE] = 0;
    948 
    949  // Undo all set breakpoints while running in the debugger shell. This will
    950  // make them invisible to all commands.
    951  undoBreakpoints();
    952 
    953  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
    954    if (lastPC != sim_->get_pc()) {
    955      DisassembleInstruction(sim_->get_pc());
    956      printf("  0x%016" PRIi64 "  \n", sim_->get_pc());
    957      lastPC = sim_->get_pc();
    958    }
    959    char* line = ReadLine("sim> ");
    960    if (line == nullptr) {
    961      break;
    962    } else {
    963      char* last_input = sim_->lastDebuggerInput();
    964      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
    965        line = last_input;
    966      } else {
    967        // Ownership is transferred to sim_;
    968        sim_->setLastDebuggerInput(line);
    969      }
    970      // Use sscanf to parse the individual parts of the command line. At the
    971      // moment no command expects more than two parameters.
    972      int argc = sscanf(line,
    973                              "%" XSTR(COMMAND_SIZE) "s "
    974                              "%" XSTR(ARG_SIZE) "s "
    975                              "%" XSTR(ARG_SIZE) "s",
    976                              cmd, arg1, arg2);
    977      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
    978        SimInstruction* instr =
    979            reinterpret_cast<SimInstruction*>(sim_->get_pc());
    980        if (!instr->isTrap()) {
    981          sim_->instructionDecode(
    982              reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    983        } else {
    984          // Allow si to jump over generated breakpoints.
    985          printf("/!\\ Jumping over generated breakpoint.\n");
    986          sim_->set_pc(sim_->get_pc() + SimInstruction::kInstrSize);
    987        }
    988        sim_->icount_++;
    989      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
    990        // Execute the one instruction we broke at with breakpoints disabled.
    991        sim_->instructionDecode(
    992            reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    993        sim_->icount_++;
    994        // Leave the debugger shell.
    995        done = true;
    996      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
    997        if (argc == 2) {
    998          int64_t value;
    999          if (strcmp(arg1, "all") == 0) {
   1000            printAllRegs();
   1001          } else if (strcmp(arg1, "allf") == 0) {
   1002            printAllRegsIncludingFPU();
   1003          } else {
   1004            Register reg = Register::FromName(arg1);
   1005            FloatRegisters::Code fReg = FloatRegisters::FromName(arg1);
   1006            if (reg != InvalidReg) {
   1007              value = getRegisterValue(reg.code());
   1008              printf("%s: 0x%016" PRIi64 " %20" PRIi64 " \n", arg1, value,
   1009                     value);
   1010            } else if (fReg != FloatRegisters::Invalid) {
   1011              printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
   1012                     FloatRegisters::GetName(fReg),
   1013                     getFPURegisterValueLong(fReg),
   1014                     getFPURegisterValueFloat(fReg),
   1015                     getFPURegisterValueDouble(fReg));
   1016            } else {
   1017              printf("%s unrecognized\n", arg1);
   1018            }
   1019          }
   1020        } else {
   1021          printf("print <register> or print <fpu register> single\n");
   1022        }
   1023      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
   1024        int64_t* cur = nullptr;
   1025        int64_t* end = nullptr;
   1026        int next_arg = 1;
   1027 
   1028        if (strcmp(cmd, "stack") == 0) {
   1029          cur = reinterpret_cast<int64_t*>(sim_->getRegister(Simulator::sp));
   1030        } else {  // Command "mem".
   1031          int64_t value;
   1032          if (!getValue(arg1, &value)) {
   1033            printf("%s unrecognized\n", arg1);
   1034            continue;
   1035          }
   1036          cur = reinterpret_cast<int64_t*>(value);
   1037          next_arg++;
   1038        }
   1039 
   1040        int64_t words;
   1041        if (argc == next_arg) {
   1042          words = 10;
   1043        } else {
   1044          if (!getValue(argv[next_arg], &words)) {
   1045            words = 10;
   1046          }
   1047        }
   1048        end = cur + words;
   1049 
   1050        while (cur < end) {
   1051          printf("  %p:  0x%016" PRIx64 " %20" PRIi64, cur, *cur, *cur);
   1052          printf("\n");
   1053          cur++;
   1054        }
   1055 
   1056      } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
   1057                 (strcmp(cmd, "di") == 0)) {
   1058        uint8_t* cur = nullptr;
   1059        uint8_t* end = nullptr;
   1060 
   1061        if (argc == 1) {
   1062          cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
   1063          end = cur + (10 * SimInstruction::kInstrSize);
   1064        } else if (argc == 2) {
   1065          Register reg = Register::FromName(arg1);
   1066          if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
   1067            // The argument is an address or a register name.
   1068            int64_t value;
   1069            if (getValue(arg1, &value)) {
   1070              cur = reinterpret_cast<uint8_t*>(value);
   1071              // Disassemble 10 instructions at <arg1>.
   1072              end = cur + (10 * SimInstruction::kInstrSize);
   1073            }
   1074          } else {
   1075            // The argument is the number of instructions.
   1076            int64_t value;
   1077            if (getValue(arg1, &value)) {
   1078              cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
   1079              // Disassemble <arg1> instructions.
   1080              end = cur + (value * SimInstruction::kInstrSize);
   1081            }
   1082          }
   1083        } else {
   1084          int64_t value1;
   1085          int64_t value2;
   1086          if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
   1087            cur = reinterpret_cast<uint8_t*>(value1);
   1088            end = cur + (value2 * SimInstruction::kInstrSize);
   1089          }
   1090        }
   1091 
   1092        while (cur < end) {
   1093          DisassembleInstruction(uint64_t(cur));
   1094          cur += SimInstruction::kInstrSize;
   1095        }
   1096      } else if (strcmp(cmd, "gdb") == 0) {
   1097        printf("relinquishing control to gdb\n");
   1098 #if defined(__x86_64__)
   1099        asm("int $3");
   1100 #elif defined(__aarch64__)
   1101        // see masm.breakpoint for arm64
   1102        asm("brk #0xf000");
   1103 #endif
   1104        printf("regaining control from gdb\n");
   1105      } else if (strcmp(cmd, "break") == 0) {
   1106        if (argc == 2) {
   1107          int64_t value;
   1108          if (getValue(arg1, &value)) {
   1109            if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) {
   1110              printf("setting breakpoint failed\n");
   1111            }
   1112          } else {
   1113            printf("%s unrecognized\n", arg1);
   1114          }
   1115        } else {
   1116          printf("break <address>\n");
   1117        }
   1118      } else if (strcmp(cmd, "del") == 0) {
   1119        if (!deleteBreakpoint(nullptr)) {
   1120          printf("deleting breakpoint failed\n");
   1121        }
   1122      } else if (strcmp(cmd, "flags") == 0) {
   1123        printf("No flags on LOONG64 !\n");
   1124      } else if (strcmp(cmd, "stop") == 0) {
   1125        int64_t value;
   1126        intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
   1127        SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc);
   1128        SimInstruction* msg_address = reinterpret_cast<SimInstruction*>(
   1129            stop_pc + SimInstruction::kInstrSize);
   1130        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
   1131          // Remove the current stop.
   1132          if (sim_->isStopInstruction(stop_instr)) {
   1133            stop_instr->setInstructionBits(kNopInstr);
   1134            msg_address->setInstructionBits(kNopInstr);
   1135          } else {
   1136            printf("Not at debugger stop.\n");
   1137          }
   1138        } else if (argc == 3) {
   1139          // Print information about all/the specified breakpoint(s).
   1140          if (strcmp(arg1, "info") == 0) {
   1141            if (strcmp(arg2, "all") == 0) {
   1142              printf("Stop information:\n");
   1143              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
   1144                   i++) {
   1145                sim_->printStopInfo(i);
   1146              }
   1147            } else if (getValue(arg2, &value)) {
   1148              sim_->printStopInfo(value);
   1149            } else {
   1150              printf("Unrecognized argument.\n");
   1151            }
   1152          } else if (strcmp(arg1, "enable") == 0) {
   1153            // Enable all/the specified breakpoint(s).
   1154            if (strcmp(arg2, "all") == 0) {
   1155              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
   1156                   i++) {
   1157                sim_->enableStop(i);
   1158              }
   1159            } else if (getValue(arg2, &value)) {
   1160              sim_->enableStop(value);
   1161            } else {
   1162              printf("Unrecognized argument.\n");
   1163            }
   1164          } else if (strcmp(arg1, "disable") == 0) {
   1165            // Disable all/the specified breakpoint(s).
   1166            if (strcmp(arg2, "all") == 0) {
   1167              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
   1168                   i++) {
   1169                sim_->disableStop(i);
   1170              }
   1171            } else if (getValue(arg2, &value)) {
   1172              sim_->disableStop(value);
   1173            } else {
   1174              printf("Unrecognized argument.\n");
   1175            }
   1176          }
   1177        } else {
   1178          printf("Wrong usage. Use help command for more information.\n");
   1179        }
   1180      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
   1181        printf("cont\n");
   1182        printf("  continue execution (alias 'c')\n");
   1183        printf("stepi\n");
   1184        printf("  step one instruction (alias 'si')\n");
   1185        printf("print <register>\n");
   1186        printf("  print register content (alias 'p')\n");
   1187        printf("  use register name 'all' to print all registers\n");
   1188        printf("printobject <register>\n");
   1189        printf("  print an object from a register (alias 'po')\n");
   1190        printf("stack [<words>]\n");
   1191        printf("  dump stack content, default dump 10 words)\n");
   1192        printf("mem <address> [<words>]\n");
   1193        printf("  dump memory content, default dump 10 words)\n");
   1194        printf("flags\n");
   1195        printf("  print flags\n");
   1196        printf("disasm [<instructions>]\n");
   1197        printf("disasm [<address/register>]\n");
   1198        printf("disasm [[<address/register>] <instructions>]\n");
   1199        printf("  disassemble code, default is 10 instructions\n");
   1200        printf("  from pc (alias 'di')\n");
   1201        printf("gdb\n");
   1202        printf("  enter gdb\n");
   1203        printf("break <address>\n");
   1204        printf("  set a break point on the address\n");
   1205        printf("del\n");
   1206        printf("  delete the breakpoint\n");
   1207        printf("stop feature:\n");
   1208        printf("  Description:\n");
   1209        printf("    Stops are debug instructions inserted by\n");
   1210        printf("    the Assembler::stop() function.\n");
   1211        printf("    When hitting a stop, the Simulator will\n");
   1212        printf("    stop and and give control to the Debugger.\n");
   1213        printf("    All stop codes are watched:\n");
   1214        printf("    - They can be enabled / disabled: the Simulator\n");
   1215        printf("       will / won't stop when hitting them.\n");
   1216        printf("    - The Simulator keeps track of how many times they \n");
   1217        printf("      are met. (See the info command.) Going over a\n");
   1218        printf("      disabled stop still increases its counter. \n");
   1219        printf("  Commands:\n");
   1220        printf("    stop info all/<code> : print infos about number <code>\n");
   1221        printf("      or all stop(s).\n");
   1222        printf("    stop enable/disable all/<code> : enables / disables\n");
   1223        printf("      all or number <code> stop(s)\n");
   1224        printf("    stop unstop\n");
   1225        printf("      ignore the stop instruction at the current location\n");
   1226        printf("      from now on\n");
   1227      } else {
   1228        printf("Unknown command: %s\n", cmd);
   1229      }
   1230    }
   1231  }
   1232 
   1233  // Add all the breakpoints back to stop execution and enter the debugger
   1234  // shell when hit.
   1235  redoBreakpoints();
   1236 
   1237 #undef COMMAND_SIZE
   1238 #undef ARG_SIZE
   1239 
   1240 #undef STR
   1241 #undef XSTR
   1242 }
   1243 
   1244 static bool AllOnOnePage(uintptr_t start, int size) {
   1245  intptr_t start_page = (start & ~CachePage::kPageMask);
   1246  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
   1247  return start_page == end_page;
   1248 }
   1249 
   1250 void Simulator::setLastDebuggerInput(char* input) {
   1251  js_free(lastDebuggerInput_);
   1252  lastDebuggerInput_ = input;
   1253 }
   1254 
   1255 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1256                                     void* page) {
   1257  SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
   1258  if (p) {
   1259    return p->value();
   1260  }
   1261  AutoEnterOOMUnsafeRegion oomUnsafe;
   1262  CachePage* new_page = js_new<CachePage>();
   1263  if (!new_page || !i_cache.add(p, page, new_page)) {
   1264    oomUnsafe.crash("Simulator CachePage");
   1265  }
   1266  return new_page;
   1267 }
   1268 
   1269 // Flush from start up to and not including start + size.
   1270 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1271                               intptr_t start, int size) {
   1272  MOZ_ASSERT(size <= CachePage::kPageSize);
   1273  MOZ_ASSERT(AllOnOnePage(start, size - 1));
   1274  MOZ_ASSERT((start & CachePage::kLineMask) == 0);
   1275  MOZ_ASSERT((size & CachePage::kLineMask) == 0);
   1276  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
   1277  int offset = (start & CachePage::kPageMask);
   1278  CachePage* cache_page = GetCachePageLocked(i_cache, page);
   1279  char* valid_bytemap = cache_page->validityByte(offset);
   1280  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
   1281 }
   1282 
   1283 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache,
   1284                              void* start_addr, size_t size) {
   1285  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
   1286  int intra_line = (start & CachePage::kLineMask);
   1287  start -= intra_line;
   1288  size += intra_line;
   1289  size = ((size - 1) | CachePage::kLineMask) + 1;
   1290  int offset = (start & CachePage::kPageMask);
   1291  while (!AllOnOnePage(start, size - 1)) {
   1292    int bytes_to_flush = CachePage::kPageSize - offset;
   1293    FlushOnePageLocked(i_cache, start, bytes_to_flush);
   1294    start += bytes_to_flush;
   1295    size -= bytes_to_flush;
   1296    MOZ_ASSERT((start & CachePage::kPageMask) == 0);
   1297    offset = 0;
   1298  }
   1299  if (size != 0) {
   1300    FlushOnePageLocked(i_cache, start, size);
   1301  }
   1302 }
   1303 
   1304 /* static */
   1305 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) {
   1306  intptr_t address = reinterpret_cast<intptr_t>(instr);
   1307  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
   1308  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
   1309  int offset = (address & CachePage::kPageMask);
   1310  CachePage* cache_page = GetCachePageLocked(icache(), page);
   1311  char* cache_valid_byte = cache_page->validityByte(offset);
   1312  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
   1313  char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
   1314 
   1315  if (cache_hit) {
   1316    // Check that the data in memory matches the contents of the I-cache.
   1317    mozilla::DebugOnly<int> cmpret =
   1318        memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset),
   1319               SimInstruction::kInstrSize);
   1320    MOZ_ASSERT(cmpret == 0);
   1321  } else {
   1322    // Cache miss.  Load memory into the cache.
   1323    memcpy(cached_line, line, CachePage::kLineLength);
   1324    *cache_valid_byte = CachePage::LINE_VALID;
   1325  }
   1326 }
   1327 
   1328 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) {
   1329  return U32(reinterpret_cast<uintptr_t>(l)) >> 2;
   1330 }
   1331 
   1332 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) {
   1333  MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
   1334  MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
   1335  return k == l;
   1336 }
   1337 
   1338 /* static */
   1339 void SimulatorProcess::FlushICache(void* start_addr, size_t size) {
   1340  if (!ICacheCheckingDisableCount) {
   1341    AutoLockSimulatorCache als;
   1342    js::jit::FlushICacheLocked(icache(), start_addr, size);
   1343  }
   1344 }
   1345 
   1346 Simulator::Simulator() {
   1347  // Set up simulator support first. Some of this information is needed to
   1348  // setup the architecture state.
   1349 
   1350  // Note, allocation and anything that depends on allocated memory is
   1351  // deferred until init(), in order to handle OOM properly.
   1352 
   1353  stack_ = nullptr;
   1354  stackLimit_ = 0;
   1355  pc_modified_ = false;
   1356  icount_ = 0;
   1357  break_count_ = 0;
   1358  break_pc_ = nullptr;
   1359  break_instr_ = 0;
   1360  single_stepping_ = false;
   1361  single_step_callback_ = nullptr;
   1362  single_step_callback_arg_ = nullptr;
   1363 
   1364  // Set up architecture state.
   1365  // All registers are initialized to zero to start with.
   1366  for (int i = 0; i < Register::kNumSimuRegisters; i++) {
   1367    registers_[i] = 0;
   1368  }
   1369  for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) {
   1370    FPUregisters_[i] = 0;
   1371  }
   1372 
   1373  for (int i = 0; i < kNumCFRegisters; i++) {
   1374    CFregisters_[i] = 0;
   1375  }
   1376 
   1377  FCSR_ = 0;
   1378  LLBit_ = false;
   1379  LLAddr_ = 0;
   1380  lastLLValue_ = 0;
   1381 
   1382  // The ra and pc are initialized to a known bad value that will cause an
   1383  // access violation if the simulator ever tries to execute it.
   1384  registers_[pc] = bad_ra;
   1385  registers_[ra] = bad_ra;
   1386 
   1387  for (int i = 0; i < kNumExceptions; i++) {
   1388    exceptions[i] = 0;
   1389  }
   1390 
   1391  lastDebuggerInput_ = nullptr;
   1392 }
   1393 
   1394 bool Simulator::init() {
   1395  // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
   1396  static const size_t stackSize = 2 * 1024 * 1024;
   1397  stack_ = js_pod_malloc<char>(stackSize);
   1398  if (!stack_) {
   1399    return false;
   1400  }
   1401 
   1402  // Leave a safety margin of 1MB to prevent overrunning the stack when
   1403  // pushing values (total stack size is 2MB).
   1404  stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
   1405 
   1406  // The sp is initialized to point to the bottom (high address) of the
   1407  // allocated stack area. To be safe in potential stack underflows we leave
   1408  // some buffer below.
   1409  registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64;
   1410 
   1411  return true;
   1412 }
   1413 
   1414 // When the generated code calls an external reference we need to catch that in
   1415 // the simulator.  The external reference will be a function compiled for the
   1416 // host architecture.  We need to call that function instead of trying to
   1417 // execute it with the simulator.  We do that by redirecting the external
   1418 // reference to a swi (software-interrupt) instruction that is handled by
   1419 // the simulator.  We write the original destination of the jump just at a known
   1420 // offset from the swi instruction so the simulator knows what to call.
   1421 class Redirection {
   1422  friend class SimulatorProcess;
   1423 
   1424  // sim's lock must already be held.
   1425  Redirection(void* nativeFunction, ABIFunctionType type)
   1426      : nativeFunction_(nativeFunction),
   1427        swiInstruction_(kCallRedirInstr),
   1428        type_(type),
   1429        next_(nullptr) {
   1430    next_ = SimulatorProcess::redirection();
   1431    if (!SimulatorProcess::ICacheCheckingDisableCount) {
   1432      FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(),
   1433                        SimInstruction::kInstrSize);
   1434    }
   1435    SimulatorProcess::setRedirection(this);
   1436  }
   1437 
   1438 public:
   1439  void* addressOfSwiInstruction() { return &swiInstruction_; }
   1440  void* nativeFunction() const { return nativeFunction_; }
   1441  ABIFunctionType type() const { return type_; }
   1442 
   1443  static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
   1444    AutoLockSimulatorCache als;
   1445 
   1446    Redirection* current = SimulatorProcess::redirection();
   1447    for (; current != nullptr; current = current->next_) {
   1448      if (current->nativeFunction_ == nativeFunction) {
   1449        MOZ_ASSERT(current->type() == type);
   1450        return current;
   1451      }
   1452    }
   1453 
   1454    // Note: we can't use js_new here because the constructor is private.
   1455    AutoEnterOOMUnsafeRegion oomUnsafe;
   1456    Redirection* redir = js_pod_malloc<Redirection>(1);
   1457    if (!redir) {
   1458      oomUnsafe.crash("Simulator redirection");
   1459    }
   1460    new (redir) Redirection(nativeFunction, type);
   1461    return redir;
   1462  }
   1463 
   1464  static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
   1465    uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
   1466    uint8_t* addrOfRedirection =
   1467        addrOfSwi - offsetof(Redirection, swiInstruction_);
   1468    return reinterpret_cast<Redirection*>(addrOfRedirection);
   1469  }
   1470 
   1471 private:
   1472  void* nativeFunction_;
   1473  uint32_t swiInstruction_;
   1474  ABIFunctionType type_;
   1475  Redirection* next_;
   1476 };
   1477 
   1478 Simulator::~Simulator() { js_free(stack_); }
   1479 
   1480 SimulatorProcess::SimulatorProcess()
   1481    : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) {
   1482  if (getenv("LOONG64_SIM_ICACHE_CHECKS")) {
   1483    ICacheCheckingDisableCount = 0;
   1484  }
   1485 }
   1486 
   1487 SimulatorProcess::~SimulatorProcess() {
   1488  Redirection* r = redirection_;
   1489  while (r) {
   1490    Redirection* next = r->next_;
   1491    js_delete(r);
   1492    r = next;
   1493  }
   1494 }
   1495 
   1496 /* static */
   1497 void* Simulator::RedirectNativeFunction(void* nativeFunction,
   1498                                        ABIFunctionType type) {
   1499  Redirection* redirection = Redirection::Get(nativeFunction, type);
   1500  return redirection->addressOfSwiInstruction();
   1501 }
   1502 
   1503 // Get the active Simulator for the current thread.
   1504 Simulator* Simulator::Current() {
   1505  JSContext* cx = TlsContext.get();
   1506  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
   1507  return cx->simulator();
   1508 }
   1509 
   1510 // Sets the register in the architecture state. It will also deal with updating
   1511 // Simulator internal state for special registers such as PC.
   1512 void Simulator::setRegister(int reg, int64_t value) {
   1513  MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
   1514  if (reg == pc) {
   1515    pc_modified_ = true;
   1516  }
   1517 
   1518  // Zero register always holds 0.
   1519  registers_[reg] = (reg == 0) ? 0 : value;
   1520 }
   1521 
   1522 void Simulator::setFpuRegister(int fpureg, int64_t value) {
   1523  MOZ_ASSERT((fpureg >= 0) &&
   1524             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1525  FPUregisters_[fpureg] = value;
   1526 }
   1527 
   1528 void Simulator::setFpuRegisterHiWord(int fpureg, int32_t value) {
   1529  // Set ONLY upper 32-bits, leaving lower bits untouched.
   1530  MOZ_ASSERT((fpureg >= 0) &&
   1531             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1532  int32_t* phiword;
   1533  phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
   1534 
   1535  *phiword = value;
   1536 }
   1537 
   1538 void Simulator::setFpuRegisterWord(int fpureg, int32_t value) {
   1539  // Set ONLY lower 32-bits, leaving upper bits untouched.
   1540  MOZ_ASSERT((fpureg >= 0) &&
   1541             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1542  int32_t* pword;
   1543  pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
   1544 
   1545  *pword = value;
   1546 }
   1547 
   1548 void Simulator::setFpuRegisterWordInvalidResult(float original, float rounded,
   1549                                                int fpureg) {
   1550  double max_int32 = static_cast<double>(INT32_MAX);
   1551  double min_int32 = static_cast<double>(INT32_MIN);
   1552 
   1553  if (std::isnan(original)) {
   1554    setFpuRegisterWord(fpureg, 0);
   1555  } else if (rounded > max_int32) {
   1556    setFpuRegister(fpureg, kFPUInvalidResult);
   1557  } else if (rounded < min_int32) {
   1558    setFpuRegister(fpureg, kFPUInvalidResultNegative);
   1559  } else {
   1560    UNREACHABLE();
   1561  }
   1562 }
   1563 
   1564 void Simulator::setFpuRegisterWordInvalidResult(double original, double rounded,
   1565                                                int fpureg) {
   1566  double max_int32 = static_cast<double>(INT32_MAX);
   1567  double min_int32 = static_cast<double>(INT32_MIN);
   1568 
   1569  if (std::isnan(original)) {
   1570    setFpuRegisterWord(fpureg, 0);
   1571  } else if (rounded > max_int32) {
   1572    setFpuRegisterWord(fpureg, kFPUInvalidResult);
   1573  } else if (rounded < min_int32) {
   1574    setFpuRegisterWord(fpureg, kFPUInvalidResultNegative);
   1575  } else {
   1576    UNREACHABLE();
   1577  }
   1578 }
   1579 
   1580 void Simulator::setFpuRegisterInvalidResult(float original, float rounded,
   1581                                            int fpureg) {
   1582  double max_int32 = static_cast<double>(INT32_MAX);
   1583  double min_int32 = static_cast<double>(INT32_MIN);
   1584 
   1585  if (std::isnan(original)) {
   1586    setFpuRegister(fpureg, 0);
   1587  } else if (rounded > max_int32) {
   1588    setFpuRegister(fpureg, kFPUInvalidResult);
   1589  } else if (rounded < min_int32) {
   1590    setFpuRegister(fpureg, kFPUInvalidResultNegative);
   1591  } else {
   1592    UNREACHABLE();
   1593  }
   1594 }
   1595 
   1596 void Simulator::setFpuRegisterInvalidResult(double original, double rounded,
   1597                                            int fpureg) {
   1598  double max_int32 = static_cast<double>(INT32_MAX);
   1599  double min_int32 = static_cast<double>(INT32_MIN);
   1600 
   1601  if (std::isnan(original)) {
   1602    setFpuRegister(fpureg, 0);
   1603  } else if (rounded > max_int32) {
   1604    setFpuRegister(fpureg, kFPUInvalidResult);
   1605  } else if (rounded < min_int32) {
   1606    setFpuRegister(fpureg, kFPUInvalidResultNegative);
   1607  } else {
   1608    UNREACHABLE();
   1609  }
   1610 }
   1611 
   1612 void Simulator::setFpuRegisterInvalidResult64(float original, float rounded,
   1613                                              int fpureg) {
   1614  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
   1615  // loading the most accurate representation into max_int64, which is 2^63.
   1616  double max_int64 = static_cast<double>(INT64_MAX);
   1617  double min_int64 = static_cast<double>(INT64_MIN);
   1618 
   1619  if (std::isnan(original)) {
   1620    setFpuRegister(fpureg, 0);
   1621  } else if (rounded >= max_int64) {
   1622    setFpuRegister(fpureg, kFPU64InvalidResult);
   1623  } else if (rounded < min_int64) {
   1624    setFpuRegister(fpureg, kFPU64InvalidResultNegative);
   1625  } else {
   1626    UNREACHABLE();
   1627  }
   1628 }
   1629 
   1630 void Simulator::setFpuRegisterInvalidResult64(double original, double rounded,
   1631                                              int fpureg) {
   1632  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
   1633  // loading the most accurate representation into max_int64, which is 2^63.
   1634  double max_int64 = static_cast<double>(INT64_MAX);
   1635  double min_int64 = static_cast<double>(INT64_MIN);
   1636 
   1637  if (std::isnan(original)) {
   1638    setFpuRegister(fpureg, 0);
   1639  } else if (rounded >= max_int64) {
   1640    setFpuRegister(fpureg, kFPU64InvalidResult);
   1641  } else if (rounded < min_int64) {
   1642    setFpuRegister(fpureg, kFPU64InvalidResultNegative);
   1643  } else {
   1644    UNREACHABLE();
   1645  }
   1646 }
   1647 
   1648 void Simulator::setFpuRegisterFloat(int fpureg, float value) {
   1649  MOZ_ASSERT((fpureg >= 0) &&
   1650             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1651  *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]) = value;
   1652 }
   1653 
   1654 void Simulator::setFpuRegisterDouble(int fpureg, double value) {
   1655  MOZ_ASSERT((fpureg >= 0) &&
   1656             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1657  *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value;
   1658 }
   1659 
   1660 void Simulator::setCFRegister(int cfreg, bool value) {
   1661  MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters));
   1662  CFregisters_[cfreg] = value;
   1663 }
   1664 
   1665 bool Simulator::getCFRegister(int cfreg) const {
   1666  MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters));
   1667  return CFregisters_[cfreg];
   1668 }
   1669 
   1670 // Get the register from the architecture state. This function does handle
   1671 // the special case of accessing the PC register.
   1672 int64_t Simulator::getRegister(int reg) const {
   1673  MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
   1674  if (reg == 0) {
   1675    return 0;
   1676  }
   1677  return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
   1678 }
   1679 
   1680 int64_t Simulator::getFpuRegister(int fpureg) const {
   1681  MOZ_ASSERT((fpureg >= 0) &&
   1682             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1683  return FPUregisters_[fpureg];
   1684 }
   1685 
   1686 int32_t Simulator::getFpuRegisterWord(int fpureg) const {
   1687  MOZ_ASSERT((fpureg >= 0) &&
   1688             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1689  return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
   1690 }
   1691 
   1692 int32_t Simulator::getFpuRegisterSignedWord(int fpureg) const {
   1693  MOZ_ASSERT((fpureg >= 0) &&
   1694             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1695  return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
   1696 }
   1697 
   1698 int32_t Simulator::getFpuRegisterHiWord(int fpureg) const {
   1699  MOZ_ASSERT((fpureg >= 0) &&
   1700             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1701  return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1);
   1702 }
   1703 
   1704 float Simulator::getFpuRegisterFloat(int fpureg) const {
   1705  MOZ_ASSERT((fpureg >= 0) &&
   1706             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1707  return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]);
   1708 }
   1709 
   1710 double Simulator::getFpuRegisterDouble(int fpureg) const {
   1711  MOZ_ASSERT((fpureg >= 0) &&
   1712             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1713  return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]);
   1714 }
   1715 
   1716 void Simulator::setCallResultDouble(double result) {
   1717  setFpuRegisterDouble(f0, result);
   1718 }
   1719 
   1720 void Simulator::setCallResultFloat(float result) {
   1721  setFpuRegisterFloat(f0, result);
   1722 }
   1723 
   1724 void Simulator::setCallResult(int64_t res) { setRegister(a0, res); }
   1725 #ifdef XP_DARWIN
   1726 // add a dedicated setCallResult for intptr_t on Darwin
   1727 void Simulator::setCallResult(intptr_t res) { setRegister(v0, I64(res)); }
   1728 #endif
   1729 void Simulator::setCallResult(__int128_t res) {
   1730  setRegister(a0, I64(res));
   1731  setRegister(a1, I64(res >> 64));
   1732 }
   1733 
   1734 // Helper functions for setting and testing the FCSR register's bits.
   1735 void Simulator::setFCSRBit(uint32_t cc, bool value) {
   1736  if (value) {
   1737    FCSR_ |= (1 << cc);
   1738  } else {
   1739    FCSR_ &= ~(1 << cc);
   1740  }
   1741 }
   1742 
   1743 bool Simulator::testFCSRBit(uint32_t cc) { return FCSR_ & (1 << cc); }
   1744 
   1745 unsigned int Simulator::getFCSRRoundingMode() {
   1746  return FCSR_ & kFPURoundingModeMask;
   1747 }
   1748 
   1749 // Sets the rounding error codes in FCSR based on the result of the rounding.
   1750 // Returns true if the operation was invalid.
   1751 template <typename T>
   1752 bool Simulator::setFCSRRoundError(double original, double rounded) {
   1753  bool ret = false;
   1754 
   1755  setFCSRBit(kFCSRInexactCauseBit, false);
   1756  setFCSRBit(kFCSRUnderflowCauseBit, false);
   1757  setFCSRBit(kFCSROverflowCauseBit, false);
   1758  setFCSRBit(kFCSRInvalidOpCauseBit, false);
   1759 
   1760  if (!std::isfinite(original) || !std::isfinite(rounded)) {
   1761    setFCSRBit(kFCSRInvalidOpFlagBit, true);
   1762    setFCSRBit(kFCSRInvalidOpCauseBit, true);
   1763    ret = true;
   1764  }
   1765 
   1766  if (original != rounded) {
   1767    setFCSRBit(kFCSRInexactFlagBit, true);
   1768    setFCSRBit(kFCSRInexactCauseBit, true);
   1769  }
   1770 
   1771  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
   1772    setFCSRBit(kFCSRUnderflowFlagBit, true);
   1773    setFCSRBit(kFCSRUnderflowCauseBit, true);
   1774    ret = true;
   1775  }
   1776 
   1777  if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
   1778      (long double)rounded < (long double)std::numeric_limits<T>::min()) {
   1779    setFCSRBit(kFCSROverflowFlagBit, true);
   1780    setFCSRBit(kFCSROverflowCauseBit, true);
   1781    // The reference is not really clear but it seems this is required:
   1782    setFCSRBit(kFCSRInvalidOpFlagBit, true);
   1783    setFCSRBit(kFCSRInvalidOpCauseBit, true);
   1784    ret = true;
   1785  }
   1786 
   1787  return ret;
   1788 }
   1789 
   1790 // For cvt instructions only
   1791 template <typename T>
   1792 void Simulator::roundAccordingToFCSR(T toRound, T* rounded,
   1793                                     int32_t* rounded_int) {
   1794  switch ((FCSR_ >> 8) & 3) {
   1795    case kRoundToNearest:
   1796      *rounded = std::floor(toRound + 0.5);
   1797      *rounded_int = static_cast<int32_t>(*rounded);
   1798      if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
   1799        // If the number is halfway between two integers,
   1800        // round to the even one.
   1801        *rounded_int -= 1;
   1802        *rounded -= 1.;
   1803      }
   1804      break;
   1805    case kRoundToZero:
   1806      *rounded = trunc(toRound);
   1807      *rounded_int = static_cast<int32_t>(*rounded);
   1808      break;
   1809    case kRoundToPlusInf:
   1810      *rounded = std::ceil(toRound);
   1811      *rounded_int = static_cast<int32_t>(*rounded);
   1812      break;
   1813    case kRoundToMinusInf:
   1814      *rounded = std::floor(toRound);
   1815      *rounded_int = static_cast<int32_t>(*rounded);
   1816      break;
   1817  }
   1818 }
   1819 
   1820 template <typename T>
   1821 void Simulator::round64AccordingToFCSR(T toRound, T* rounded,
   1822                                       int64_t* rounded_int) {
   1823  switch ((FCSR_ >> 8) & 3) {
   1824    case kRoundToNearest:
   1825      *rounded = std::floor(toRound + 0.5);
   1826      *rounded_int = static_cast<int64_t>(*rounded);
   1827      if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
   1828        // If the number is halfway between two integers,
   1829        // round to the even one.
   1830        *rounded_int -= 1;
   1831        *rounded -= 1.;
   1832      }
   1833      break;
   1834    case kRoundToZero:
   1835      *rounded = trunc(toRound);
   1836      *rounded_int = static_cast<int64_t>(*rounded);
   1837      break;
   1838    case kRoundToPlusInf:
   1839      *rounded = std::ceil(toRound);
   1840      *rounded_int = static_cast<int64_t>(*rounded);
   1841      break;
   1842    case kRoundToMinusInf:
   1843      *rounded = std::floor(toRound);
   1844      *rounded_int = static_cast<int64_t>(*rounded);
   1845      break;
   1846  }
   1847 }
   1848 
   1849 // Raw access to the PC register.
   1850 void Simulator::set_pc(int64_t value) {
   1851  pc_modified_ = true;
   1852  registers_[pc] = value;
   1853 }
   1854 
   1855 bool Simulator::has_bad_pc() const {
   1856  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
   1857 }
   1858 
   1859 // Raw access to the PC register without the special adjustment when reading.
   1860 int64_t Simulator::get_pc() const { return registers_[pc]; }
   1861 
   1862 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() {
   1863  wasm::RegisterState state;
   1864  state.pc = (void*)get_pc();
   1865  state.fp = (void*)getRegister(fp);
   1866  state.sp = (void*)getRegister(sp);
   1867  state.lr = (void*)getRegister(ra);
   1868  return state;
   1869 }
   1870 
   1871 uint8_t Simulator::readBU(uint64_t addr) {
   1872  if (handleWasmSegFault(addr, 1)) {
   1873    return 0xff;
   1874  }
   1875 
   1876  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1877  return *ptr;
   1878 }
   1879 
   1880 int8_t Simulator::readB(uint64_t addr) {
   1881  if (handleWasmSegFault(addr, 1)) {
   1882    return -1;
   1883  }
   1884 
   1885  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1886  return *ptr;
   1887 }
   1888 
   1889 void Simulator::writeB(uint64_t addr, uint8_t value) {
   1890  if (handleWasmSegFault(addr, 1)) {
   1891    return;
   1892  }
   1893 
   1894  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1895  *ptr = value;
   1896 }
   1897 
   1898 void Simulator::writeB(uint64_t addr, int8_t value) {
   1899  if (handleWasmSegFault(addr, 1)) {
   1900    return;
   1901  }
   1902 
   1903  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1904  *ptr = value;
   1905 }
   1906 
   1907 uint16_t Simulator::readHU(uint64_t addr, SimInstruction* instr) {
   1908  if (handleWasmSegFault(addr, 2)) {
   1909    return 0xffff;
   1910  }
   1911 
   1912  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1913  return *ptr;
   1914 }
   1915 
   1916 int16_t Simulator::readH(uint64_t addr, SimInstruction* instr) {
   1917  if (handleWasmSegFault(addr, 2)) {
   1918    return -1;
   1919  }
   1920 
   1921  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1922  return *ptr;
   1923 }
   1924 
   1925 void Simulator::writeH(uint64_t addr, uint16_t value, SimInstruction* instr) {
   1926  if (handleWasmSegFault(addr, 2)) {
   1927    return;
   1928  }
   1929 
   1930  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1931  LLBit_ = false;
   1932  *ptr = value;
   1933  return;
   1934 }
   1935 
   1936 void Simulator::writeH(uint64_t addr, int16_t value, SimInstruction* instr) {
   1937  if (handleWasmSegFault(addr, 2)) {
   1938    return;
   1939  }
   1940 
   1941  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1942  LLBit_ = false;
   1943  *ptr = value;
   1944  return;
   1945 }
   1946 
   1947 uint32_t Simulator::readWU(uint64_t addr, SimInstruction* instr) {
   1948  if (handleWasmSegFault(addr, 4)) {
   1949    return -1;
   1950  }
   1951 
   1952  uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
   1953  return *ptr;
   1954 }
   1955 
   1956 int32_t Simulator::readW(uint64_t addr, SimInstruction* instr) {
   1957  if (handleWasmSegFault(addr, 4)) {
   1958    return -1;
   1959  }
   1960 
   1961  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1962  return *ptr;
   1963 }
   1964 
   1965 void Simulator::writeW(uint64_t addr, uint32_t value, SimInstruction* instr) {
   1966  if (handleWasmSegFault(addr, 4)) {
   1967    return;
   1968  }
   1969 
   1970  uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
   1971  LLBit_ = false;
   1972  *ptr = value;
   1973  return;
   1974 }
   1975 
   1976 void Simulator::writeW(uint64_t addr, int32_t value, SimInstruction* instr) {
   1977  if (handleWasmSegFault(addr, 4)) {
   1978    return;
   1979  }
   1980 
   1981  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1982  LLBit_ = false;
   1983  *ptr = value;
   1984  return;
   1985 }
   1986 
   1987 int64_t Simulator::readDW(uint64_t addr, SimInstruction* instr) {
   1988  if (handleWasmSegFault(addr, 8)) {
   1989    return -1;
   1990  }
   1991 
   1992  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
   1993  return *ptr;
   1994 }
   1995 
   1996 void Simulator::writeDW(uint64_t addr, int64_t value, SimInstruction* instr) {
   1997  if (handleWasmSegFault(addr, 8)) {
   1998    return;
   1999  }
   2000 
   2001  int64_t* ptr = reinterpret_cast<int64_t*>(addr);
   2002  LLBit_ = false;
   2003  *ptr = value;
   2004  return;
   2005 }
   2006 
   2007 double Simulator::readD(uint64_t addr, SimInstruction* instr) {
   2008  if (handleWasmSegFault(addr, 8)) {
   2009    return NAN;
   2010  }
   2011 
   2012  double* ptr = reinterpret_cast<double*>(addr);
   2013  return *ptr;
   2014 }
   2015 
   2016 void Simulator::writeD(uint64_t addr, double value, SimInstruction* instr) {
   2017  if (handleWasmSegFault(addr, 8)) {
   2018    return;
   2019  }
   2020 
   2021  double* ptr = reinterpret_cast<double*>(addr);
   2022  LLBit_ = false;
   2023  *ptr = value;
   2024  return;
   2025 }
   2026 
   2027 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) {
   2028  if ((addr & 3) == 0) {
   2029    if (handleWasmSegFault(addr, 4)) {
   2030      return -1;
   2031    }
   2032 
   2033    volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr);
   2034    int32_t value = *ptr;
   2035    lastLLValue_ = value;
   2036    LLAddr_ = addr;
   2037    // Note that any memory write or "external" interrupt should reset this
   2038    // value to false.
   2039    LLBit_ = true;
   2040    return value;
   2041  }
   2042  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2043         reinterpret_cast<intptr_t>(instr));
   2044  MOZ_CRASH();
   2045  return 0;
   2046 }
   2047 
   2048 int Simulator::storeConditionalW(uint64_t addr, int value,
   2049                                 SimInstruction* instr) {
   2050  // Correct behavior in this case, as defined by architecture, is to just
   2051  // return 0, but there is no point at allowing that. It is certainly an
   2052  // indicator of a bug.
   2053  if (addr != LLAddr_) {
   2054    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   2055           ", expected: 0x%016" PRIxPTR "\n",
   2056           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   2057    MOZ_CRASH();
   2058  }
   2059 
   2060  if ((addr & 3) == 0) {
   2061    SharedMem<int32_t*> ptr =
   2062        SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
   2063 
   2064    if (!LLBit_) {
   2065      return 0;
   2066    }
   2067 
   2068    LLBit_ = false;
   2069    LLAddr_ = 0;
   2070    int32_t expected = int32_t(lastLLValue_);
   2071    int32_t old =
   2072        AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value));
   2073    return (old == expected) ? 1 : 0;
   2074  }
   2075  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2076         reinterpret_cast<intptr_t>(instr));
   2077  MOZ_CRASH();
   2078  return 0;
   2079 }
   2080 
   2081 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) {
   2082  if ((addr & kPointerAlignmentMask) == 0) {
   2083    if (handleWasmSegFault(addr, 8)) {
   2084      return -1;
   2085    }
   2086 
   2087    volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr);
   2088    int64_t value = *ptr;
   2089    lastLLValue_ = value;
   2090    LLAddr_ = addr;
   2091    // Note that any memory write or "external" interrupt should reset this
   2092    // value to false.
   2093    LLBit_ = true;
   2094    return value;
   2095  }
   2096  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2097         reinterpret_cast<intptr_t>(instr));
   2098  MOZ_CRASH();
   2099  return 0;
   2100 }
   2101 
   2102 int Simulator::storeConditionalD(uint64_t addr, int64_t value,
   2103                                 SimInstruction* instr) {
   2104  // Correct behavior in this case, as defined by architecture, is to just
   2105  // return 0, but there is no point at allowing that. It is certainly an
   2106  // indicator of a bug.
   2107  if (addr != LLAddr_) {
   2108    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   2109           ", expected: 0x%016" PRIxPTR "\n",
   2110           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   2111    MOZ_CRASH();
   2112  }
   2113 
   2114  if ((addr & kPointerAlignmentMask) == 0) {
   2115    SharedMem<int64_t*> ptr =
   2116        SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr));
   2117 
   2118    if (!LLBit_) {
   2119      return 0;
   2120    }
   2121 
   2122    LLBit_ = false;
   2123    LLAddr_ = 0;
   2124    int64_t expected = lastLLValue_;
   2125    int64_t old =
   2126        AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value));
   2127    return (old == expected) ? 1 : 0;
   2128  }
   2129  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2130         reinterpret_cast<intptr_t>(instr));
   2131  MOZ_CRASH();
   2132  return 0;
   2133 }
   2134 
   2135 uintptr_t Simulator::stackLimit() const { return stackLimit_; }
   2136 
   2137 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; }
   2138 
   2139 bool Simulator::overRecursed(uintptr_t newsp) const {
   2140  if (newsp == 0) {
   2141    newsp = getRegister(sp);
   2142  }
   2143  return newsp <= stackLimit();
   2144 }
   2145 
   2146 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
   2147  uintptr_t newsp = getRegister(sp) - extra;
   2148  return newsp <= stackLimit();
   2149 }
   2150 
   2151 // Unsupported instructions use format to print an error and stop execution.
   2152 void Simulator::format(SimInstruction* instr, const char* format) {
   2153  printf("Simulator found unsupported instruction:\n 0x%016" PRIxPTR ": %s\n",
   2154         reinterpret_cast<intptr_t>(instr), format);
   2155  MOZ_CRASH();
   2156 }
   2157 
   2158 inline int32_t Simulator::rj_reg(SimInstruction* instr) const {
   2159  return instr->rjValue();
   2160 }
   2161 
   2162 inline int64_t Simulator::rj(SimInstruction* instr) const {
   2163  return getRegister(rj_reg(instr));
   2164 }
   2165 
   2166 inline uint64_t Simulator::rj_u(SimInstruction* instr) const {
   2167  return static_cast<uint64_t>(getRegister(rj_reg(instr)));
   2168 }
   2169 
   2170 inline int32_t Simulator::rk_reg(SimInstruction* instr) const {
   2171  return instr->rkValue();
   2172 }
   2173 
   2174 inline int64_t Simulator::rk(SimInstruction* instr) const {
   2175  return getRegister(rk_reg(instr));
   2176 }
   2177 
   2178 inline uint64_t Simulator::rk_u(SimInstruction* instr) const {
   2179  return static_cast<uint64_t>(getRegister(rk_reg(instr)));
   2180 }
   2181 
   2182 inline int32_t Simulator::rd_reg(SimInstruction* instr) const {
   2183  return instr->rdValue();
   2184 }
   2185 
   2186 inline int64_t Simulator::rd(SimInstruction* instr) const {
   2187  return getRegister(rd_reg(instr));
   2188 }
   2189 
   2190 inline uint64_t Simulator::rd_u(SimInstruction* instr) const {
   2191  return static_cast<uint64_t>(getRegister(rd_reg(instr)));
   2192 }
   2193 
   2194 inline int32_t Simulator::fa_reg(SimInstruction* instr) const {
   2195  return instr->faValue();
   2196 }
   2197 
   2198 inline float Simulator::fa_float(SimInstruction* instr) const {
   2199  return getFpuRegisterFloat(fa_reg(instr));
   2200 }
   2201 
   2202 inline double Simulator::fa_double(SimInstruction* instr) const {
   2203  return getFpuRegisterDouble(fa_reg(instr));
   2204 }
   2205 
   2206 inline int32_t Simulator::fj_reg(SimInstruction* instr) const {
   2207  return instr->fjValue();
   2208 }
   2209 
   2210 inline float Simulator::fj_float(SimInstruction* instr) const {
   2211  return getFpuRegisterFloat(fj_reg(instr));
   2212 }
   2213 
   2214 inline double Simulator::fj_double(SimInstruction* instr) const {
   2215  return getFpuRegisterDouble(fj_reg(instr));
   2216 }
   2217 
   2218 inline int32_t Simulator::fk_reg(SimInstruction* instr) const {
   2219  return instr->fkValue();
   2220 }
   2221 
   2222 inline float Simulator::fk_float(SimInstruction* instr) const {
   2223  return getFpuRegisterFloat(fk_reg(instr));
   2224 }
   2225 
   2226 inline double Simulator::fk_double(SimInstruction* instr) const {
   2227  return getFpuRegisterDouble(fk_reg(instr));
   2228 }
   2229 
   2230 inline int32_t Simulator::fd_reg(SimInstruction* instr) const {
   2231  return instr->fdValue();
   2232 }
   2233 
   2234 inline float Simulator::fd_float(SimInstruction* instr) const {
   2235  return getFpuRegisterFloat(fd_reg(instr));
   2236 }
   2237 
   2238 inline double Simulator::fd_double(SimInstruction* instr) const {
   2239  return getFpuRegisterDouble(fd_reg(instr));
   2240 }
   2241 
   2242 inline int32_t Simulator::cj_reg(SimInstruction* instr) const {
   2243  return instr->cjValue();
   2244 }
   2245 
   2246 inline bool Simulator::cj(SimInstruction* instr) const {
   2247  return getCFRegister(cj_reg(instr));
   2248 }
   2249 
   2250 inline int32_t Simulator::cd_reg(SimInstruction* instr) const {
   2251  return instr->cdValue();
   2252 }
   2253 
   2254 inline bool Simulator::cd(SimInstruction* instr) const {
   2255  return getCFRegister(cd_reg(instr));
   2256 }
   2257 
   2258 inline int32_t Simulator::ca_reg(SimInstruction* instr) const {
   2259  return instr->caValue();
   2260 }
   2261 
   2262 inline bool Simulator::ca(SimInstruction* instr) const {
   2263  return getCFRegister(ca_reg(instr));
   2264 }
   2265 
   2266 inline uint32_t Simulator::sa2(SimInstruction* instr) const {
   2267  return instr->sa2Value();
   2268 }
   2269 
   2270 inline uint32_t Simulator::sa3(SimInstruction* instr) const {
   2271  return instr->sa3Value();
   2272 }
   2273 
   2274 inline uint32_t Simulator::ui5(SimInstruction* instr) const {
   2275  return instr->imm5Value();
   2276 }
   2277 
   2278 inline uint32_t Simulator::ui6(SimInstruction* instr) const {
   2279  return instr->imm6Value();
   2280 }
   2281 
   2282 inline uint32_t Simulator::lsbw(SimInstruction* instr) const {
   2283  return instr->lsbwValue();
   2284 }
   2285 
   2286 inline uint32_t Simulator::msbw(SimInstruction* instr) const {
   2287  return instr->msbwValue();
   2288 }
   2289 
   2290 inline uint32_t Simulator::lsbd(SimInstruction* instr) const {
   2291  return instr->lsbdValue();
   2292 }
   2293 
   2294 inline uint32_t Simulator::msbd(SimInstruction* instr) const {
   2295  return instr->msbdValue();
   2296 }
   2297 
   2298 inline uint32_t Simulator::cond(SimInstruction* instr) const {
   2299  return instr->condValue();
   2300 }
   2301 
   2302 inline int32_t Simulator::si12(SimInstruction* instr) const {
   2303  return (instr->imm12Value() << 20) >> 20;
   2304 }
   2305 
   2306 inline uint32_t Simulator::ui12(SimInstruction* instr) const {
   2307  return instr->imm12Value();
   2308 }
   2309 
   2310 inline int32_t Simulator::si14(SimInstruction* instr) const {
   2311  return (instr->imm14Value() << 18) >> 18;
   2312 }
   2313 
   2314 inline int32_t Simulator::si16(SimInstruction* instr) const {
   2315  return (instr->imm16Value() << 16) >> 16;
   2316 }
   2317 
   2318 inline int32_t Simulator::si20(SimInstruction* instr) const {
   2319  return (instr->imm20Value() << 12) >> 12;
   2320 }
   2321 
   2322 ABI_FUNCTION_TYPE_SIM_PROTOTYPES
   2323 
   2324 // Software interrupt instructions are used by the simulator to call into C++.
   2325 void Simulator::softwareInterrupt(SimInstruction* instr) {
   2326  // the break_ instruction could get us here.
   2327  mozilla::DebugOnly<int32_t> opcode_hi15 = instr->bits(31, 17);
   2328  MOZ_ASSERT(opcode_hi15 == 0x15);
   2329  uint32_t code = instr->bits(14, 0);
   2330 
   2331  if (instr->instructionBits() == kCallRedirInstr) {
   2332    Redirection* redirection = Redirection::FromSwiInstruction(instr);
   2333    uintptr_t nativeFn =
   2334        reinterpret_cast<uintptr_t>(redirection->nativeFunction());
   2335 
   2336    // Get the SP for reading stack arguments
   2337    int64_t* sp_ = reinterpret_cast<int64_t*>(getRegister(sp));
   2338 
   2339    // Store argument register values in local variables for ease of use below.
   2340    int64_t a0_ = getRegister(a0);
   2341    int64_t a1_ = getRegister(a1);
   2342    int64_t a2_ = getRegister(a2);
   2343    int64_t a3_ = getRegister(a3);
   2344    int64_t a4_ = getRegister(a4);
   2345    int64_t a5_ = getRegister(a5);
   2346    int64_t a6_ = getRegister(a6);
   2347    int64_t a7_ = getRegister(a7);
   2348    float f0_s = getFpuRegisterFloat(f0);
   2349    float f1_s = getFpuRegisterFloat(f1);
   2350    float f2_s = getFpuRegisterFloat(f2);
   2351    float f3_s = getFpuRegisterFloat(f3);
   2352    float f4_s = getFpuRegisterFloat(f4);
   2353    double f0_d = getFpuRegisterDouble(f0);
   2354    double f1_d = getFpuRegisterDouble(f1);
   2355    double f2_d = getFpuRegisterDouble(f2);
   2356    double f3_d = getFpuRegisterDouble(f3);
   2357 
   2358    // This is dodgy but it works because the C entry stubs are never moved.
   2359    // See comment in codegen-arm.cc and bug 1242173.
   2360    int64_t saved_ra = getRegister(ra);
   2361 
   2362    bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0;
   2363    if (!stack_aligned) {
   2364      fprintf(stderr, "Runtime call with unaligned stack!\n");
   2365      MOZ_CRASH();
   2366    }
   2367 
   2368    if (single_stepping_) {
   2369      single_step_callback_(single_step_callback_arg_, this, nullptr);
   2370    }
   2371 
   2372    switch (redirection->type()) {
   2373      ABI_FUNCTION_TYPE_LOONGARCH64_SIM_DISPATCH
   2374 
   2375      default:
   2376        MOZ_CRASH("Unknown function type.");
   2377    }
   2378 
   2379    if (single_stepping_) {
   2380      single_step_callback_(single_step_callback_arg_, this, nullptr);
   2381    }
   2382 
   2383    setRegister(ra, saved_ra);
   2384    set_pc(getRegister(ra));
   2385  } else if ((instr->bits(31, 15) << 15 == op_break) && code == kWasmTrapCode) {
   2386    uint8_t* newPC;
   2387    if (wasm::HandleIllegalInstruction(registerState(), &newPC)) {
   2388      set_pc(int64_t(newPC));
   2389      return;
   2390    }
   2391  } else if ((instr->bits(31, 15) << 15 == op_break) && code <= kMaxStopCode &&
   2392             code != 6) {
   2393    if (isWatchpoint(code)) {
   2394      // printWatchpoint(code);
   2395    } else {
   2396      increaseStopCounter(code);
   2397      handleStop(code, instr);
   2398    }
   2399  } else {
   2400    // All remaining break_ codes, and all traps are handled here.
   2401    loong64Debugger dbg(this);
   2402    dbg.debug();
   2403  }
   2404 }
   2405 
   2406 // Stop helper functions.
   2407 bool Simulator::isWatchpoint(uint32_t code) {
   2408  return (code <= kMaxWatchpointCode);
   2409 }
   2410 
   2411 void Simulator::printWatchpoint(uint32_t code) {
   2412  loong64Debugger dbg(this);
   2413  ++break_count_;
   2414  printf("\n---- break %d marker: %20" PRIi64 "  (instr count: %20" PRIi64
   2415         ") ----\n",
   2416         code, break_count_, icount_);
   2417  dbg.printAllRegs();  // Print registers and continue running.
   2418 }
   2419 
   2420 void Simulator::handleStop(uint32_t code, SimInstruction* instr) {
   2421  // Stop if it is enabled, otherwise go on jumping over the stop
   2422  // and the message address.
   2423  if (isEnabledStop(code)) {
   2424    loong64Debugger dbg(this);
   2425    dbg.stop(instr);
   2426  } else {
   2427    set_pc(get_pc() + 1 * SimInstruction::kInstrSize);
   2428  }
   2429 }
   2430 
   2431 bool Simulator::isStopInstruction(SimInstruction* instr) {
   2432  int32_t opcode_hi15 = instr->bits(31, 17);
   2433  uint32_t code = static_cast<uint32_t>(instr->bits(14, 0));
   2434  return (opcode_hi15 == 0x15) && code > kMaxWatchpointCode &&
   2435         code <= kMaxStopCode;
   2436 }
   2437 
   2438 bool Simulator::isEnabledStop(uint32_t code) {
   2439  MOZ_ASSERT(code <= kMaxStopCode);
   2440  MOZ_ASSERT(code > kMaxWatchpointCode);
   2441  return !(watchedStops_[code].count_ & kStopDisabledBit);
   2442 }
   2443 
   2444 void Simulator::enableStop(uint32_t code) {
   2445  if (!isEnabledStop(code)) {
   2446    watchedStops_[code].count_ &= ~kStopDisabledBit;
   2447  }
   2448 }
   2449 
   2450 void Simulator::disableStop(uint32_t code) {
   2451  if (isEnabledStop(code)) {
   2452    watchedStops_[code].count_ |= kStopDisabledBit;
   2453  }
   2454 }
   2455 
   2456 void Simulator::increaseStopCounter(uint32_t code) {
   2457  MOZ_ASSERT(code <= kMaxStopCode);
   2458  if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) {
   2459    printf(
   2460        "Stop counter for code %i has overflowed.\n"
   2461        "Enabling this code and reseting the counter to 0.\n",
   2462        code);
   2463    watchedStops_[code].count_ = 0;
   2464    enableStop(code);
   2465  } else {
   2466    watchedStops_[code].count_++;
   2467  }
   2468 }
   2469 
   2470 // Print a stop status.
   2471 void Simulator::printStopInfo(uint32_t code) {
   2472  if (code <= kMaxWatchpointCode) {
   2473    printf("That is a watchpoint, not a stop.\n");
   2474    return;
   2475  } else if (code > kMaxStopCode) {
   2476    printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
   2477    return;
   2478  }
   2479  const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
   2480  int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit;
   2481  // Don't print the state of unused breakpoints.
   2482  if (count != 0) {
   2483    if (watchedStops_[code].desc_) {
   2484      printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state,
   2485             count, watchedStops_[code].desc_);
   2486    } else {
   2487      printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
   2488             count);
   2489    }
   2490  }
   2491 }
   2492 
   2493 void Simulator::signalExceptions() {
   2494  for (int i = 1; i < kNumExceptions; i++) {
   2495    if (exceptions[i] != 0) {
   2496      MOZ_CRASH("Error: Exception raised.");
   2497    }
   2498  }
   2499 }
   2500 
   2501 // ReverseBits(value) returns |value| in reverse bit order.
   2502 template <typename T>
   2503 T ReverseBits(T value) {
   2504  MOZ_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
   2505             (sizeof(value) == 4) || (sizeof(value) == 8));
   2506  T result = 0;
   2507  for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
   2508    result = (result << 1) | (value & 1);
   2509    value >>= 1;
   2510  }
   2511  return result;
   2512 }
   2513 
   2514 // Min/Max template functions for Double and Single arguments.
   2515 
   2516 template <typename T>
   2517 static T FPAbs(T a);
   2518 
   2519 template <>
   2520 double FPAbs<double>(double a) {
   2521  return fabs(a);
   2522 }
   2523 
   2524 template <>
   2525 float FPAbs<float>(float a) {
   2526  return fabsf(a);
   2527 }
   2528 
   2529 enum class MaxMinKind : int { kMin = 0, kMax = 1 };
   2530 
   2531 template <typename T>
   2532 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
   2533  if (std::isnan(a) && std::isnan(b)) {
   2534    *result = a;
   2535  } else if (std::isnan(a)) {
   2536    *result = b;
   2537  } else if (std::isnan(b)) {
   2538    *result = a;
   2539  } else if (b == a) {
   2540    // Handle -0.0 == 0.0 case.
   2541    // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
   2542    // negates the result.
   2543    *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
   2544  } else {
   2545    return false;
   2546  }
   2547  return true;
   2548 }
   2549 
   2550 template <typename T>
   2551 static T FPUMin(T a, T b) {
   2552  T result;
   2553  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
   2554    return result;
   2555  } else {
   2556    return b < a ? b : a;
   2557  }
   2558 }
   2559 
   2560 template <typename T>
   2561 static T FPUMax(T a, T b) {
   2562  T result;
   2563  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
   2564    return result;
   2565  } else {
   2566    return b > a ? b : a;
   2567  }
   2568 }
   2569 
   2570 template <typename T>
   2571 static T FPUMinA(T a, T b) {
   2572  T result;
   2573  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
   2574    if (FPAbs(a) < FPAbs(b)) {
   2575      result = a;
   2576    } else if (FPAbs(b) < FPAbs(a)) {
   2577      result = b;
   2578    } else {
   2579      result = a < b ? a : b;
   2580    }
   2581  }
   2582  return result;
   2583 }
   2584 
   2585 template <typename T>
   2586 static T FPUMaxA(T a, T b) {
   2587  T result;
   2588  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
   2589    if (FPAbs(a) > FPAbs(b)) {
   2590      result = a;
   2591    } else if (FPAbs(b) > FPAbs(a)) {
   2592      result = b;
   2593    } else {
   2594      result = a > b ? a : b;
   2595    }
   2596  }
   2597  return result;
   2598 }
   2599 
   2600 enum class KeepSign : bool { no = false, yes };
   2601 
   2602 // Handle execution based on instruction types.
   2603 // decodeTypeImmediate
   2604 void Simulator::decodeTypeOp6(SimInstruction* instr) {
   2605  // Next pc.
   2606  int64_t next_pc = bad_ra;
   2607 
   2608  // Used for memory instructions.
   2609  int64_t alu_out = 0;
   2610 
   2611  // Branch instructions common part.
   2612  auto BranchAndLinkHelper = [this, &next_pc](SimInstruction* instr) {
   2613    int64_t current_pc = get_pc();
   2614    setRegister(ra, current_pc + SimInstruction::kInstrSize);
   2615    int32_t offs26_low16 =
   2616        static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
   2617    int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6;
   2618    int32_t offs26 = offs26_low16 | offs26_high10;
   2619    next_pc = current_pc + (offs26 << 2);
   2620    set_pc(next_pc);
   2621  };
   2622 
   2623  auto BranchOff16Helper = [this, &next_pc](SimInstruction* instr,
   2624                                            bool do_branch) {
   2625    int64_t current_pc = get_pc();
   2626    int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16;
   2627    int32_t offs = do_branch ? (offs16 << 2) : SimInstruction::kInstrSize;
   2628    next_pc = current_pc + offs;
   2629    set_pc(next_pc);
   2630  };
   2631 
   2632  auto BranchOff21Helper = [this, &next_pc](SimInstruction* instr,
   2633                                            bool do_branch) {
   2634    int64_t current_pc = get_pc();
   2635    int32_t offs21_low16 =
   2636        static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
   2637    int32_t offs21_high5 = static_cast<int32_t>(instr->bits(4, 0) << 27) >> 11;
   2638    int32_t offs = offs21_low16 | offs21_high5;
   2639    offs = do_branch ? (offs << 2) : SimInstruction::kInstrSize;
   2640    next_pc = current_pc + offs;
   2641    set_pc(next_pc);
   2642  };
   2643 
   2644  auto BranchOff26Helper = [this, &next_pc](SimInstruction* instr) {
   2645    int64_t current_pc = get_pc();
   2646    int32_t offs26_low16 =
   2647        static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
   2648    int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6;
   2649    int32_t offs26 = offs26_low16 | offs26_high10;
   2650    next_pc = current_pc + (offs26 << 2);
   2651    set_pc(next_pc);
   2652  };
   2653 
   2654  auto JumpOff16Helper = [this, &next_pc](SimInstruction* instr) {
   2655    int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16;
   2656    setRegister(rd_reg(instr), get_pc() + SimInstruction::kInstrSize);
   2657    next_pc = rj(instr) + (offs16 << 2);
   2658    set_pc(next_pc);
   2659  };
   2660 
   2661  switch (instr->bits(31, 26) << 26) {
   2662    case op_addu16i_d: {
   2663      int32_t si16_upper = static_cast<int32_t>(si16(instr)) << 16;
   2664      alu_out = static_cast<int64_t>(si16_upper) + rj(instr);
   2665      setRegister(rd_reg(instr), alu_out);
   2666      break;
   2667    }
   2668    case op_beqz: {
   2669      BranchOff21Helper(instr, rj(instr) == 0);
   2670      break;
   2671    }
   2672    case op_bnez: {
   2673      BranchOff21Helper(instr, rj(instr) != 0);
   2674      break;
   2675    }
   2676    case op_bcz: {
   2677      if (instr->bits(9, 8) == 0b00) {
   2678        // BCEQZ
   2679        BranchOff21Helper(instr, cj(instr) == false);
   2680      } else if (instr->bits(9, 8) == 0b01) {
   2681        // BCNEZ
   2682        BranchOff21Helper(instr, cj(instr) == true);
   2683      } else {
   2684        UNREACHABLE();
   2685      }
   2686      break;
   2687    }
   2688    case op_jirl: {
   2689      JumpOff16Helper(instr);
   2690      break;
   2691    }
   2692    case op_b: {
   2693      BranchOff26Helper(instr);
   2694      break;
   2695    }
   2696    case op_bl: {
   2697      BranchAndLinkHelper(instr);
   2698      break;
   2699    }
   2700    case op_beq: {
   2701      BranchOff16Helper(instr, rj(instr) == rd(instr));
   2702      break;
   2703    }
   2704    case op_bne: {
   2705      BranchOff16Helper(instr, rj(instr) != rd(instr));
   2706      break;
   2707    }
   2708    case op_blt: {
   2709      BranchOff16Helper(instr, rj(instr) < rd(instr));
   2710      break;
   2711    }
   2712    case op_bge: {
   2713      BranchOff16Helper(instr, rj(instr) >= rd(instr));
   2714      break;
   2715    }
   2716    case op_bltu: {
   2717      BranchOff16Helper(instr, rj_u(instr) < rd_u(instr));
   2718      break;
   2719    }
   2720    case op_bgeu: {
   2721      BranchOff16Helper(instr, rj_u(instr) >= rd_u(instr));
   2722      break;
   2723    }
   2724    default:
   2725      UNREACHABLE();
   2726  }
   2727 }
   2728 
   2729 void Simulator::decodeTypeOp7(SimInstruction* instr) {
   2730  int64_t alu_out;
   2731 
   2732  switch (instr->bits(31, 25) << 25) {
   2733    case op_lu12i_w: {
   2734      int32_t si20_upper = static_cast<int32_t>(si20(instr) << 12);
   2735      setRegister(rd_reg(instr), static_cast<int64_t>(si20_upper));
   2736      break;
   2737    }
   2738    case op_lu32i_d: {
   2739      int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 12;
   2740      int64_t lower_32bit_mask = 0xFFFFFFFF;
   2741      alu_out = (static_cast<int64_t>(si20_signExtend) << 32) |
   2742                (rd(instr) & lower_32bit_mask);
   2743      setRegister(rd_reg(instr), alu_out);
   2744      break;
   2745    }
   2746    case op_pcaddi: {
   2747      int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 10;
   2748      int64_t current_pc = get_pc();
   2749      alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
   2750      setRegister(rd_reg(instr), alu_out);
   2751      break;
   2752    }
   2753    case op_pcalau12i: {
   2754      int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12);
   2755      int64_t current_pc = get_pc();
   2756      int64_t clear_lower12bit_mask = 0xFFFFFFFFFFFFF000;
   2757      alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
   2758      setRegister(rd_reg(instr), alu_out & clear_lower12bit_mask);
   2759      break;
   2760    }
   2761    case op_pcaddu12i: {
   2762      int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12);
   2763      int64_t current_pc = get_pc();
   2764      alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
   2765      setRegister(rd_reg(instr), alu_out);
   2766      break;
   2767    }
   2768    case op_pcaddu18i: {
   2769      int64_t si20_signExtend = (static_cast<int64_t>(si20(instr)) << 44) >> 26;
   2770      int64_t current_pc = get_pc();
   2771      alu_out = si20_signExtend + current_pc;
   2772      setRegister(rd_reg(instr), alu_out);
   2773      break;
   2774    }
   2775    default:
   2776      UNREACHABLE();
   2777  }
   2778 }
   2779 
   2780 void Simulator::decodeTypeOp8(SimInstruction* instr) {
   2781  int64_t addr = 0x0;
   2782  int64_t si14_se = (static_cast<int64_t>(si14(instr)) << 50) >> 48;
   2783 
   2784  switch (instr->bits(31, 24) << 24) {
   2785    case op_ldptr_w: {
   2786      setRegister(rd_reg(instr), readW(rj(instr) + si14_se, instr));
   2787      break;
   2788    }
   2789    case op_stptr_w: {
   2790      writeW(rj(instr) + si14_se, static_cast<int32_t>(rd(instr)), instr);
   2791      break;
   2792    }
   2793    case op_ldptr_d: {
   2794      setRegister(rd_reg(instr), readDW(rj(instr) + si14_se, instr));
   2795      break;
   2796    }
   2797    case op_stptr_d: {
   2798      writeDW(rj(instr) + si14_se, rd(instr), instr);
   2799      break;
   2800    }
   2801    case op_ll_w: {
   2802      addr = si14_se + rj(instr);
   2803      setRegister(rd_reg(instr), loadLinkedW(addr, instr));
   2804      break;
   2805    }
   2806    case op_sc_w: {
   2807      addr = si14_se + rj(instr);
   2808      setRegister(
   2809          rd_reg(instr),
   2810          storeConditionalW(addr, static_cast<int32_t>(rd(instr)), instr));
   2811      break;
   2812    }
   2813    case op_ll_d: {
   2814      addr = si14_se + rj(instr);
   2815      setRegister(rd_reg(instr), loadLinkedD(addr, instr));
   2816      break;
   2817    }
   2818    case op_sc_d: {
   2819      addr = si14_se + rj(instr);
   2820      setRegister(rd_reg(instr), storeConditionalD(addr, rd(instr), instr));
   2821      break;
   2822    }
   2823    default:
   2824      UNREACHABLE();
   2825  }
   2826 }
   2827 
   2828 void Simulator::decodeTypeOp10(SimInstruction* instr) {
   2829  int64_t alu_out = 0x0;
   2830  int64_t si12_se = (static_cast<int64_t>(si12(instr)) << 52) >> 52;
   2831  uint64_t si12_ze = (static_cast<uint64_t>(ui12(instr)) << 52) >> 52;
   2832 
   2833  switch (instr->bits(31, 22) << 22) {
   2834    case op_bstrins_d: {
   2835      uint8_t lsbd_ = lsbd(instr);
   2836      uint8_t msbd_ = msbd(instr);
   2837      MOZ_ASSERT(lsbd_ <= msbd_);
   2838      uint8_t size = msbd_ - lsbd_ + 1;
   2839      if (size < 64) {
   2840        uint64_t mask = (1ULL << size) - 1;
   2841        alu_out =
   2842            (rd_u(instr) & ~(mask << lsbd_)) | ((rj_u(instr) & mask) << lsbd_);
   2843        setRegister(rd_reg(instr), alu_out);
   2844      } else if (size == 64) {
   2845        setRegister(rd_reg(instr), rj(instr));
   2846      }
   2847      break;
   2848    }
   2849    case op_bstrpick_d: {
   2850      uint8_t lsbd_ = lsbd(instr);
   2851      uint8_t msbd_ = msbd(instr);
   2852      MOZ_ASSERT(lsbd_ <= msbd_);
   2853      uint8_t size = msbd_ - lsbd_ + 1;
   2854      if (size < 64) {
   2855        uint64_t mask = (1ULL << size) - 1;
   2856        alu_out = (rj_u(instr) & (mask << lsbd_)) >> lsbd_;
   2857        setRegister(rd_reg(instr), alu_out);
   2858      } else if (size == 64) {
   2859        setRegister(rd_reg(instr), rj(instr));
   2860      }
   2861      break;
   2862    }
   2863    case op_slti: {
   2864      setRegister(rd_reg(instr), rj(instr) < si12_se ? 1 : 0);
   2865      break;
   2866    }
   2867    case op_sltui: {
   2868      setRegister(rd_reg(instr),
   2869                  rj_u(instr) < static_cast<uint64_t>(si12_se) ? 1 : 0);
   2870      break;
   2871    }
   2872    case op_addi_w: {
   2873      int32_t alu32_out =
   2874          static_cast<int32_t>(rj(instr)) + static_cast<int32_t>(si12_se);
   2875      setRegister(rd_reg(instr), alu32_out);
   2876      break;
   2877    }
   2878    case op_addi_d: {
   2879      setRegister(rd_reg(instr), rj(instr) + si12_se);
   2880      break;
   2881    }
   2882    case op_lu52i_d: {
   2883      int64_t si12_se = static_cast<int64_t>(si12(instr)) << 52;
   2884      uint64_t mask = (1ULL << 52) - 1;
   2885      alu_out = si12_se + (rj(instr) & mask);
   2886      setRegister(rd_reg(instr), alu_out);
   2887      break;
   2888    }
   2889    case op_andi: {
   2890      setRegister(rd_reg(instr), rj(instr) & si12_ze);
   2891      break;
   2892    }
   2893    case op_ori: {
   2894      setRegister(rd_reg(instr), rj_u(instr) | si12_ze);
   2895      break;
   2896    }
   2897    case op_xori: {
   2898      setRegister(rd_reg(instr), rj_u(instr) ^ si12_ze);
   2899      break;
   2900    }
   2901    case op_ld_b: {
   2902      setRegister(rd_reg(instr), readB(rj(instr) + si12_se));
   2903      break;
   2904    }
   2905    case op_ld_h: {
   2906      setRegister(rd_reg(instr), readH(rj(instr) + si12_se, instr));
   2907      break;
   2908    }
   2909    case op_ld_w: {
   2910      setRegister(rd_reg(instr), readW(rj(instr) + si12_se, instr));
   2911      break;
   2912    }
   2913    case op_ld_d: {
   2914      setRegister(rd_reg(instr), readDW(rj(instr) + si12_se, instr));
   2915      break;
   2916    }
   2917    case op_st_b: {
   2918      writeB(rj(instr) + si12_se, static_cast<int8_t>(rd(instr)));
   2919      break;
   2920    }
   2921    case op_st_h: {
   2922      writeH(rj(instr) + si12_se, static_cast<int16_t>(rd(instr)), instr);
   2923      break;
   2924    }
   2925    case op_st_w: {
   2926      writeW(rj(instr) + si12_se, static_cast<int32_t>(rd(instr)), instr);
   2927      break;
   2928    }
   2929    case op_st_d: {
   2930      writeDW(rj(instr) + si12_se, rd(instr), instr);
   2931      break;
   2932    }
   2933    case op_ld_bu: {
   2934      setRegister(rd_reg(instr), readBU(rj(instr) + si12_se));
   2935      break;
   2936    }
   2937    case op_ld_hu: {
   2938      setRegister(rd_reg(instr), readHU(rj(instr) + si12_se, instr));
   2939      break;
   2940    }
   2941    case op_ld_wu: {
   2942      setRegister(rd_reg(instr), readWU(rj(instr) + si12_se, instr));
   2943      break;
   2944    }
   2945    case op_fld_s: {
   2946      setFpuRegister(fd_reg(instr), kFPUInvalidResult);  // Trash upper 32 bits.
   2947      setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + si12_se, instr));
   2948      break;
   2949    }
   2950    case op_fst_s: {
   2951      int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr)));
   2952      writeW(rj(instr) + si12_se, alu_out_32, instr);
   2953      break;
   2954    }
   2955    case op_fld_d: {
   2956      setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + si12_se, instr));
   2957      break;
   2958    }
   2959    case op_fst_d: {
   2960      writeD(rj(instr) + si12_se, getFpuRegisterDouble(fd_reg(instr)), instr);
   2961      break;
   2962    }
   2963    case op_preld:
   2964      UNIMPLEMENTED();
   2965      break;
   2966    default:
   2967      UNREACHABLE();
   2968  }
   2969 }
   2970 
   2971 void Simulator::decodeTypeOp11(SimInstruction* instr) {
   2972  int64_t alu_out = 0x0;
   2973 
   2974  switch (instr->bits(31, 21) << 21) {
   2975    case op_bstr_w: {
   2976      MOZ_ASSERT(instr->bit(21) == 1);
   2977      uint8_t lsbw_ = lsbw(instr);
   2978      uint8_t msbw_ = msbw(instr);
   2979      MOZ_ASSERT(lsbw_ <= msbw_);
   2980      uint8_t size = msbw_ - lsbw_ + 1;
   2981      uint64_t mask = (1ULL << size) - 1;
   2982      if (instr->bit(15) == 0) {
   2983        // BSTRINS_W
   2984        alu_out = static_cast<int32_t>((rd_u(instr) & ~(mask << lsbw_)) |
   2985                                       ((rj_u(instr) & mask) << lsbw_));
   2986      } else {
   2987        // BSTRPICK_W
   2988        alu_out =
   2989            static_cast<int32_t>((rj_u(instr) & (mask << lsbw_)) >> lsbw_);
   2990      }
   2991      setRegister(rd_reg(instr), alu_out);
   2992      break;
   2993    }
   2994    default:
   2995      UNREACHABLE();
   2996  }
   2997 }
   2998 
   2999 void Simulator::decodeTypeOp12(SimInstruction* instr) {
   3000  switch (instr->bits(31, 20) << 20) {
   3001    case op_fmadd_s: {
   3002      setFpuRegisterFloat(
   3003          fd_reg(instr),
   3004          std::fma(fj_float(instr), fk_float(instr), fa_float(instr)));
   3005      break;
   3006    }
   3007    case op_fmadd_d: {
   3008      setFpuRegisterDouble(
   3009          fd_reg(instr),
   3010          std::fma(fj_double(instr), fk_double(instr), fa_double(instr)));
   3011      break;
   3012    }
   3013    case op_fmsub_s: {
   3014      setFpuRegisterFloat(
   3015          fd_reg(instr),
   3016          std::fma(-fj_float(instr), fk_float(instr), fa_float(instr)));
   3017      break;
   3018    }
   3019    case op_fmsub_d: {
   3020      setFpuRegisterDouble(
   3021          fd_reg(instr),
   3022          std::fma(-fj_double(instr), fk_double(instr), fa_double(instr)));
   3023      break;
   3024    }
   3025    case op_fnmadd_s: {
   3026      setFpuRegisterFloat(
   3027          fd_reg(instr),
   3028          std::fma(-fj_float(instr), fk_float(instr), -fa_float(instr)));
   3029      break;
   3030    }
   3031    case op_fnmadd_d: {
   3032      setFpuRegisterDouble(
   3033          fd_reg(instr),
   3034          std::fma(-fj_double(instr), fk_double(instr), -fa_double(instr)));
   3035      break;
   3036    }
   3037    case op_fnmsub_s: {
   3038      setFpuRegisterFloat(
   3039          fd_reg(instr),
   3040          std::fma(fj_float(instr), fk_float(instr), -fa_float(instr)));
   3041      break;
   3042    }
   3043    case op_fnmsub_d: {
   3044      setFpuRegisterDouble(
   3045          fd_reg(instr),
   3046          std::fma(fj_double(instr), fk_double(instr), -fa_double(instr)));
   3047      break;
   3048    }
   3049    case op_fcmp_cond_s: {
   3050      MOZ_ASSERT(instr->bits(4, 3) == 0);
   3051      float fj = fj_float(instr);
   3052      float fk = fk_float(instr);
   3053      switch (cond(instr)) {
   3054        case AssemblerLOONG64::CAF: {
   3055          setCFRegister(cd_reg(instr), false);
   3056          break;
   3057        }
   3058        case AssemblerLOONG64::CUN: {
   3059          setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk));
   3060          break;
   3061        }
   3062        case AssemblerLOONG64::CEQ: {
   3063          setCFRegister(cd_reg(instr), fj == fk);
   3064          break;
   3065        }
   3066        case AssemblerLOONG64::CUEQ: {
   3067          setCFRegister(cd_reg(instr),
   3068                        (fj == fk) || std::isnan(fj) || std::isnan(fk));
   3069          break;
   3070        }
   3071        case AssemblerLOONG64::CLT: {
   3072          setCFRegister(cd_reg(instr), fj < fk);
   3073          break;
   3074        }
   3075        case AssemblerLOONG64::CULT: {
   3076          setCFRegister(cd_reg(instr),
   3077                        (fj < fk) || std::isnan(fj) || std::isnan(fk));
   3078          break;
   3079        }
   3080        case AssemblerLOONG64::CLE: {
   3081          setCFRegister(cd_reg(instr), fj <= fk);
   3082          break;
   3083        }
   3084        case AssemblerLOONG64::CULE: {
   3085          setCFRegister(cd_reg(instr),
   3086                        (fj <= fk) || std::isnan(fj) || std::isnan(fk));
   3087          break;
   3088        }
   3089        case AssemblerLOONG64::CNE: {
   3090          setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk));
   3091          break;
   3092        }
   3093        case AssemblerLOONG64::COR: {
   3094          setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk));
   3095          break;
   3096        }
   3097        case AssemblerLOONG64::CUNE: {
   3098          setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk) ||
   3099                                           std::isnan(fj) || std::isnan(fk));
   3100          break;
   3101        }
   3102        case AssemblerLOONG64::SAF:
   3103          UNIMPLEMENTED();
   3104          break;
   3105        case AssemblerLOONG64::SUN:
   3106          UNIMPLEMENTED();
   3107          break;
   3108        case AssemblerLOONG64::SEQ:
   3109          UNIMPLEMENTED();
   3110          break;
   3111        case AssemblerLOONG64::SUEQ:
   3112          UNIMPLEMENTED();
   3113          break;
   3114        case AssemblerLOONG64::SLT:
   3115          UNIMPLEMENTED();
   3116          break;
   3117        case AssemblerLOONG64::SULT:
   3118          UNIMPLEMENTED();
   3119          break;
   3120        case AssemblerLOONG64::SLE:
   3121          UNIMPLEMENTED();
   3122          break;
   3123        case AssemblerLOONG64::SULE:
   3124          UNIMPLEMENTED();
   3125          break;
   3126        case AssemblerLOONG64::SNE:
   3127          UNIMPLEMENTED();
   3128          break;
   3129        case AssemblerLOONG64::SOR:
   3130          UNIMPLEMENTED();
   3131          break;
   3132        case AssemblerLOONG64::SUNE:
   3133          UNIMPLEMENTED();
   3134          break;
   3135        default:
   3136          UNREACHABLE();
   3137      }
   3138      break;
   3139    }
   3140    case op_fcmp_cond_d: {
   3141      MOZ_ASSERT(instr->bits(4, 3) == 0);
   3142      double fj = fj_double(instr);
   3143      double fk = fk_double(instr);
   3144      switch (cond(instr)) {
   3145        case AssemblerLOONG64::CAF: {
   3146          setCFRegister(cd_reg(instr), false);
   3147          break;
   3148        }
   3149        case AssemblerLOONG64::CUN: {
   3150          setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk));
   3151          break;
   3152        }
   3153        case AssemblerLOONG64::CEQ: {
   3154          setCFRegister(cd_reg(instr), fj == fk);
   3155          break;
   3156        }
   3157        case AssemblerLOONG64::CUEQ: {
   3158          setCFRegister(cd_reg(instr),
   3159                        (fj == fk) || std::isnan(fj) || std::isnan(fk));
   3160          break;
   3161        }
   3162        case AssemblerLOONG64::CLT: {
   3163          setCFRegister(cd_reg(instr), fj < fk);
   3164          break;
   3165        }
   3166        case AssemblerLOONG64::CULT: {
   3167          setCFRegister(cd_reg(instr),
   3168                        (fj < fk) || std::isnan(fj) || std::isnan(fk));
   3169          break;
   3170        }
   3171        case AssemblerLOONG64::CLE: {
   3172          setCFRegister(cd_reg(instr), fj <= fk);
   3173          break;
   3174        }
   3175        case AssemblerLOONG64::CULE: {
   3176          setCFRegister(cd_reg(instr),
   3177                        (fj <= fk) || std::isnan(fj) || std::isnan(fk));
   3178          break;
   3179        }
   3180        case AssemblerLOONG64::CNE: {
   3181          setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk));
   3182          break;
   3183        }
   3184        case AssemblerLOONG64::COR: {
   3185          setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk));
   3186          break;
   3187        }
   3188        case AssemblerLOONG64::CUNE: {
   3189          setCFRegister(cd_reg(instr),
   3190                        (fj != fk) || std::isnan(fj) || std::isnan(fk));
   3191          break;
   3192        }
   3193        case AssemblerLOONG64::SAF:
   3194          UNIMPLEMENTED();
   3195          break;
   3196        case AssemblerLOONG64::SUN:
   3197          UNIMPLEMENTED();
   3198          break;
   3199        case AssemblerLOONG64::SEQ:
   3200          UNIMPLEMENTED();
   3201          break;
   3202        case AssemblerLOONG64::SUEQ:
   3203          UNIMPLEMENTED();
   3204          break;
   3205        case AssemblerLOONG64::SLT:
   3206          UNIMPLEMENTED();
   3207          break;
   3208        case AssemblerLOONG64::SULT:
   3209          UNIMPLEMENTED();
   3210          break;
   3211        case AssemblerLOONG64::SLE:
   3212          UNIMPLEMENTED();
   3213          break;
   3214        case AssemblerLOONG64::SULE:
   3215          UNIMPLEMENTED();
   3216          break;
   3217        case AssemblerLOONG64::SNE:
   3218          UNIMPLEMENTED();
   3219          break;
   3220        case AssemblerLOONG64::SOR:
   3221          UNIMPLEMENTED();
   3222          break;
   3223        case AssemblerLOONG64::SUNE:
   3224          UNIMPLEMENTED();
   3225          break;
   3226        default:
   3227          UNREACHABLE();
   3228      }
   3229      break;
   3230    }
   3231    default:
   3232      UNREACHABLE();
   3233  }
   3234 }
   3235 
   3236 void Simulator::decodeTypeOp14(SimInstruction* instr) {
   3237  int64_t alu_out = 0x0;
   3238 
   3239  switch (instr->bits(31, 18) << 18) {
   3240    case op_bytepick_d: {
   3241      uint8_t sa = sa3(instr) * 8;
   3242      if (sa == 0) {
   3243        alu_out = rk(instr);
   3244      } else {
   3245        int64_t mask = (1ULL << 63) >> (sa - 1);
   3246        int64_t rk_hi = (rk(instr) & (~mask)) << sa;
   3247        int64_t rj_lo = (rj(instr) & mask) >> (64 - sa);
   3248        alu_out = rk_hi | rj_lo;
   3249      }
   3250      setRegister(rd_reg(instr), alu_out);
   3251      break;
   3252    }
   3253    case op_fsel: {
   3254      MOZ_ASSERT(instr->bits(19, 18) == 0);
   3255      if (ca(instr) == 0) {
   3256        setFpuRegisterDouble(fd_reg(instr), fj_double(instr));
   3257      } else {
   3258        setFpuRegisterDouble(fd_reg(instr), fk_double(instr));
   3259      }
   3260      break;
   3261    }
   3262    default:
   3263      UNREACHABLE();
   3264  }
   3265 }
   3266 
   3267 void Simulator::decodeTypeOp15(SimInstruction* instr) {
   3268  int64_t alu_out = 0x0;
   3269  int32_t alu32_out = 0x0;
   3270 
   3271  switch (instr->bits(31, 17) << 17) {
   3272    case op_bytepick_w: {
   3273      MOZ_ASSERT(instr->bit(17) == 0);
   3274      uint8_t sa = sa2(instr) * 8;
   3275      if (sa == 0) {
   3276        alu32_out = static_cast<int32_t>(rk(instr));
   3277      } else {
   3278        int32_t mask = (1 << 31) >> (sa - 1);
   3279        int32_t rk_hi = (static_cast<int32_t>(rk(instr)) & (~mask)) << sa;
   3280        int32_t rj_lo = (static_cast<uint32_t>(rj(instr)) & mask) >> (32 - sa);
   3281        alu32_out = rk_hi | rj_lo;
   3282      }
   3283      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3284      break;
   3285    }
   3286    case op_alsl_w: {
   3287      uint8_t sa = sa2(instr) + 1;
   3288      alu32_out = (static_cast<int32_t>(rj(instr)) << sa) +
   3289                  static_cast<int32_t>(rk(instr));
   3290      setRegister(rd_reg(instr), alu32_out);
   3291      break;
   3292    }
   3293    case op_alsl_wu: {
   3294      uint8_t sa = sa2(instr) + 1;
   3295      alu32_out = (static_cast<int32_t>(rj(instr)) << sa) +
   3296                  static_cast<int32_t>(rk(instr));
   3297      setRegister(rd_reg(instr), static_cast<uint32_t>(alu32_out));
   3298      break;
   3299    }
   3300    case op_alsl_d: {
   3301      MOZ_ASSERT(instr->bit(17) == 0);
   3302      uint8_t sa = sa2(instr) + 1;
   3303      alu_out = (rj(instr) << sa) + rk(instr);
   3304      setRegister(rd_reg(instr), alu_out);
   3305      break;
   3306    }
   3307    default:
   3308      UNREACHABLE();
   3309  }
   3310 }
   3311 
   3312 void Simulator::decodeTypeOp16(SimInstruction* instr) {
   3313  int64_t alu_out;
   3314  switch (instr->bits(31, 16) << 16) {
   3315    case op_slli_d: {
   3316      MOZ_ASSERT(instr->bit(17) == 0);
   3317      MOZ_ASSERT(instr->bits(17, 16) == 0b01);
   3318      setRegister(rd_reg(instr), rj(instr) << ui6(instr));
   3319      break;
   3320    }
   3321    case op_srli_d: {
   3322      MOZ_ASSERT(instr->bit(17) == 0);
   3323      setRegister(rd_reg(instr), rj_u(instr) >> ui6(instr));
   3324      break;
   3325    }
   3326    case op_srai_d: {
   3327      MOZ_ASSERT(instr->bit(17) == 0);
   3328      setRegister(rd_reg(instr), rj(instr) >> ui6(instr));
   3329      break;
   3330    }
   3331    case op_rotri_d: {
   3332      MOZ_ASSERT(instr->bit(17) == 0);
   3333      MOZ_ASSERT(instr->bits(17, 16) == 0b01);
   3334      alu_out = static_cast<int64_t>(RotateRight64(rj_u(instr), ui6(instr)));
   3335      setRegister(rd_reg(instr), alu_out);
   3336      break;
   3337    }
   3338    default:
   3339      UNREACHABLE();
   3340  }
   3341 }
   3342 
   3343 void Simulator::decodeTypeOp17(SimInstruction* instr) {
   3344  int64_t alu_out;
   3345  int32_t alu32_out;
   3346 
   3347  switch (instr->bits(31, 15) << 15) {
   3348    case op_slli_w: {
   3349      MOZ_ASSERT(instr->bit(17) == 0);
   3350      MOZ_ASSERT(instr->bits(17, 15) == 0b001);
   3351      alu32_out = static_cast<int32_t>(rj(instr)) << ui5(instr);
   3352      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3353      break;
   3354    }
   3355    case op_srai_w: {
   3356      MOZ_ASSERT(instr->bit(17) == 0);
   3357      MOZ_ASSERT(instr->bits(17, 15) == 0b001);
   3358      alu32_out = static_cast<int32_t>(rj(instr)) >> ui5(instr);
   3359      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3360      break;
   3361    }
   3362    case op_rotri_w: {
   3363      MOZ_ASSERT(instr->bit(17) == 0);
   3364      MOZ_ASSERT(instr->bits(17, 15) == 0b001);
   3365      alu32_out = static_cast<int32_t>(
   3366          RotateRight32(static_cast<const uint32_t>(rj_u(instr)),
   3367                        static_cast<const uint32_t>(ui5(instr))));
   3368      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3369      break;
   3370    }
   3371    case op_srli_w: {
   3372      MOZ_ASSERT(instr->bit(17) == 0);
   3373      MOZ_ASSERT(instr->bits(17, 15) == 0b001);
   3374      alu32_out = static_cast<uint32_t>(rj(instr)) >> ui5(instr);
   3375      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3376      break;
   3377    }
   3378    case op_add_w: {
   3379      int32_t alu32_out = static_cast<int32_t>(rj(instr) + rk(instr));
   3380      // Sign-extend result of 32bit operation into 64bit register.
   3381      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3382      break;
   3383    }
   3384    case op_add_d:
   3385      setRegister(rd_reg(instr), rj(instr) + rk(instr));
   3386      break;
   3387    case op_sub_w: {
   3388      int32_t alu32_out = static_cast<int32_t>(rj(instr) - rk(instr));
   3389      // Sign-extend result of 32bit operation into 64bit register.
   3390      setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
   3391      break;
   3392    }
   3393    case op_sub_d:
   3394      setRegister(rd_reg(instr), rj(instr) - rk(instr));
   3395      break;
   3396    case op_slt:
   3397      setRegister(rd_reg(instr), rj(instr) < rk(instr) ? 1 : 0);
   3398      break;
   3399    case op_sltu:
   3400      setRegister(rd_reg(instr), rj_u(instr) < rk_u(instr) ? 1 : 0);
   3401      break;
   3402    case op_maskeqz:
   3403      setRegister(rd_reg(instr), rk(instr) == 0 ? 0 : rj(instr));
   3404      break;
   3405    case op_masknez:
   3406      setRegister(rd_reg(instr), rk(instr) != 0 ? 0 : rj(instr));
   3407      break;
   3408    case op_nor:
   3409      setRegister(rd_reg(instr), ~(rj(instr) | rk(instr)));
   3410      break;
   3411    case op_and:
   3412      setRegister(rd_reg(instr), rj(instr) & rk(instr));
   3413      break;
   3414    case op_or:
   3415      setRegister(rd_reg(instr), rj(instr) | rk(instr));
   3416      break;
   3417    case op_xor:
   3418      setRegister(rd_reg(instr), rj(instr) ^ rk(instr));
   3419      break;
   3420    case op_orn:
   3421      setRegister(rd_reg(instr), rj(instr) | (~rk(instr)));
   3422      break;
   3423    case op_andn:
   3424      setRegister(rd_reg(instr), rj(instr) & (~rk(instr)));
   3425      break;
   3426    case op_sll_w:
   3427      setRegister(rd_reg(instr), (int32_t)rj(instr) << (rk_u(instr) & 0x1f));
   3428      break;
   3429    case op_srl_w: {
   3430      alu_out =
   3431          static_cast<int32_t>((uint32_t)rj_u(instr) >> (rk_u(instr) & 0x1f));
   3432      setRegister(rd_reg(instr), alu_out);
   3433      break;
   3434    }
   3435    case op_sra_w:
   3436      setRegister(rd_reg(instr), (int32_t)rj(instr) >> (rk_u(instr) & 0x1f));
   3437      break;
   3438    case op_sll_d:
   3439      setRegister(rd_reg(instr), rj(instr) << (rk_u(instr) & 0x3f));
   3440      break;
   3441    case op_srl_d: {
   3442      alu_out = static_cast<int64_t>(rj_u(instr) >> (rk_u(instr) & 0x3f));
   3443      setRegister(rd_reg(instr), alu_out);
   3444      break;
   3445    }
   3446    case op_sra_d:
   3447      setRegister(rd_reg(instr), rj(instr) >> (rk_u(instr) & 0x3f));
   3448      break;
   3449    case op_rotr_w: {
   3450      alu_out = static_cast<int32_t>(
   3451          RotateRight32(static_cast<const uint32_t>(rj_u(instr)),
   3452                        static_cast<const uint32_t>(rk_u(instr) & 0x1f)));
   3453      setRegister(rd_reg(instr), alu_out);
   3454      break;
   3455    }
   3456    case op_rotr_d: {
   3457      alu_out = static_cast<int64_t>(
   3458          RotateRight64((rj_u(instr)), (rk_u(instr) & 0x3f)));
   3459      setRegister(rd_reg(instr), alu_out);
   3460      break;
   3461    }
   3462    case op_mul_w: {
   3463      alu_out =
   3464          static_cast<int32_t>(rj(instr)) * static_cast<int32_t>(rk(instr));
   3465      setRegister(rd_reg(instr), alu_out);
   3466      break;
   3467    }
   3468    case op_mulh_w: {
   3469      int32_t rj_lo = static_cast<int32_t>(rj(instr));
   3470      int32_t rk_lo = static_cast<int32_t>(rk(instr));
   3471      alu_out = static_cast<int64_t>(rj_lo) * static_cast<int64_t>(rk_lo);
   3472      setRegister(rd_reg(instr), alu_out >> 32);
   3473      break;
   3474    }
   3475    case op_mulh_wu: {
   3476      uint32_t rj_lo = static_cast<uint32_t>(rj_u(instr));
   3477      uint32_t rk_lo = static_cast<uint32_t>(rk_u(instr));
   3478      alu_out = static_cast<uint64_t>(rj_lo) * static_cast<uint64_t>(rk_lo);
   3479      setRegister(rd_reg(instr), alu_out >> 32);
   3480      break;
   3481    }
   3482    case op_mul_d:
   3483      setRegister(rd_reg(instr), rj(instr) * rk(instr));
   3484      break;
   3485    case op_mulh_d:
   3486      setRegister(rd_reg(instr), MultiplyHighSigned(rj(instr), rk(instr)));
   3487      break;
   3488    case op_mulh_du:
   3489      setRegister(rd_reg(instr),
   3490                  MultiplyHighUnsigned(rj_u(instr), rk_u(instr)));
   3491      break;
   3492    case op_mulw_d_w: {
   3493      int64_t rj_i32 = static_cast<int32_t>(rj(instr));
   3494      int64_t rk_i32 = static_cast<int32_t>(rk(instr));
   3495      setRegister(rd_reg(instr), rj_i32 * rk_i32);
   3496      break;
   3497    }
   3498    case op_mulw_d_wu: {
   3499      uint64_t rj_u32 = static_cast<uint32_t>(rj_u(instr));
   3500      uint64_t rk_u32 = static_cast<uint32_t>(rk_u(instr));
   3501      setRegister(rd_reg(instr), rj_u32 * rk_u32);
   3502      break;
   3503    }
   3504    case op_div_w: {
   3505      int32_t rj_i32 = static_cast<int32_t>(rj(instr));
   3506      int32_t rk_i32 = static_cast<int32_t>(rk(instr));
   3507      if (rj_i32 == INT_MIN && rk_i32 == -1) {
   3508        setRegister(rd_reg(instr), INT_MIN);
   3509      } else if (rk_i32 != 0) {
   3510        setRegister(rd_reg(instr), rj_i32 / rk_i32);
   3511      }
   3512      break;
   3513    }
   3514    case op_mod_w: {
   3515      int32_t rj_i32 = static_cast<int32_t>(rj(instr));
   3516      int32_t rk_i32 = static_cast<int32_t>(rk(instr));
   3517      if (rj_i32 == INT_MIN && rk_i32 == -1) {
   3518        setRegister(rd_reg(instr), 0);
   3519      } else if (rk_i32 != 0) {
   3520        setRegister(rd_reg(instr), rj_i32 % rk_i32);
   3521      }
   3522      break;
   3523    }
   3524    case op_div_wu: {
   3525      uint32_t rj_u32 = static_cast<uint32_t>(rj(instr));
   3526      uint32_t rk_u32 = static_cast<uint32_t>(rk(instr));
   3527      if (rk_u32 != 0) {
   3528        setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 / rk_u32));
   3529      }
   3530      break;
   3531    }
   3532    case op_mod_wu: {
   3533      uint32_t rj_u32 = static_cast<uint32_t>(rj(instr));
   3534      uint32_t rk_u32 = static_cast<uint32_t>(rk(instr));
   3535      if (rk_u32 != 0) {
   3536        setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 % rk_u32));
   3537      }
   3538      break;
   3539    }
   3540    case op_div_d: {
   3541      if (rj(instr) == INT64_MIN && rk(instr) == -1) {
   3542        setRegister(rd_reg(instr), INT64_MIN);
   3543      } else if (rk(instr) != 0) {
   3544        setRegister(rd_reg(instr), rj(instr) / rk(instr));
   3545      }
   3546      break;
   3547    }
   3548    case op_mod_d: {
   3549      if (rj(instr) == LONG_MIN && rk(instr) == -1) {
   3550        setRegister(rd_reg(instr), 0);
   3551      } else if (rk(instr) != 0) {
   3552        setRegister(rd_reg(instr), rj(instr) % rk(instr));
   3553      }
   3554      break;
   3555    }
   3556    case op_div_du: {
   3557      if (rk_u(instr) != 0) {
   3558        setRegister(rd_reg(instr),
   3559                    static_cast<int64_t>(rj_u(instr) / rk_u(instr)));
   3560      }
   3561      break;
   3562    }
   3563    case op_mod_du: {
   3564      if (rk_u(instr) != 0) {
   3565        setRegister(rd_reg(instr),
   3566                    static_cast<int64_t>(rj_u(instr) % rk_u(instr)));
   3567      }
   3568      break;
   3569    }
   3570    case op_break:
   3571      softwareInterrupt(instr);
   3572      break;
   3573    case op_fadd_s: {
   3574      setFpuRegisterFloat(fd_reg(instr), fj_float(instr) + fk_float(instr));
   3575      break;
   3576    }
   3577    case op_fadd_d: {
   3578      setFpuRegisterDouble(fd_reg(instr), fj_double(instr) + fk_double(instr));
   3579      break;
   3580    }
   3581    case op_fsub_s: {
   3582      setFpuRegisterFloat(fd_reg(instr), fj_float(instr) - fk_float(instr));
   3583      break;
   3584    }
   3585    case op_fsub_d: {
   3586      setFpuRegisterDouble(fd_reg(instr), fj_double(instr) - fk_double(instr));
   3587      break;
   3588    }
   3589    case op_fmul_s: {
   3590      setFpuRegisterFloat(fd_reg(instr), fj_float(instr) * fk_float(instr));
   3591      break;
   3592    }
   3593    case op_fmul_d: {
   3594      setFpuRegisterDouble(fd_reg(instr), fj_double(instr) * fk_double(instr));
   3595      break;
   3596    }
   3597    case op_fdiv_s: {
   3598      setFpuRegisterFloat(fd_reg(instr), fj_float(instr) / fk_float(instr));
   3599      break;
   3600    }
   3601 
   3602    case op_fdiv_d: {
   3603      setFpuRegisterDouble(fd_reg(instr), fj_double(instr) / fk_double(instr));
   3604      break;
   3605    }
   3606    case op_fmax_s: {
   3607      setFpuRegisterFloat(fd_reg(instr),
   3608                          FPUMax(fk_float(instr), fj_float(instr)));
   3609      break;
   3610    }
   3611    case op_fmax_d: {
   3612      setFpuRegisterDouble(fd_reg(instr),
   3613                           FPUMax(fk_double(instr), fj_double(instr)));
   3614      break;
   3615    }
   3616    case op_fmin_s: {
   3617      setFpuRegisterFloat(fd_reg(instr),
   3618                          FPUMin(fk_float(instr), fj_float(instr)));
   3619      break;
   3620    }
   3621    case op_fmin_d: {
   3622      setFpuRegisterDouble(fd_reg(instr),
   3623                           FPUMin(fk_double(instr), fj_double(instr)));
   3624      break;
   3625    }
   3626    case op_fmaxa_s: {
   3627      setFpuRegisterFloat(fd_reg(instr),
   3628                          FPUMaxA(fk_float(instr), fj_float(instr)));
   3629      break;
   3630    }
   3631    case op_fmaxa_d: {
   3632      setFpuRegisterDouble(fd_reg(instr),
   3633                           FPUMaxA(fk_double(instr), fj_double(instr)));
   3634      break;
   3635    }
   3636    case op_fmina_s: {
   3637      setFpuRegisterFloat(fd_reg(instr),
   3638                          FPUMinA(fk_float(instr), fj_float(instr)));
   3639      break;
   3640    }
   3641    case op_fmina_d: {
   3642      setFpuRegisterDouble(fd_reg(instr),
   3643                           FPUMinA(fk_double(instr), fj_double(instr)));
   3644      break;
   3645    }
   3646    case op_ldx_b:
   3647      setRegister(rd_reg(instr), readB(rj(instr) + rk(instr)));
   3648      break;
   3649    case op_ldx_h:
   3650      setRegister(rd_reg(instr), readH(rj(instr) + rk(instr), instr));
   3651      break;
   3652    case op_ldx_w:
   3653      setRegister(rd_reg(instr), readW(rj(instr) + rk(instr), instr));
   3654      break;
   3655    case op_ldx_d:
   3656      setRegister(rd_reg(instr), readDW(rj(instr) + rk(instr), instr));
   3657      break;
   3658    case op_stx_b:
   3659      writeB(rj(instr) + rk(instr), static_cast<int8_t>(rd(instr)));
   3660      break;
   3661    case op_stx_h:
   3662      writeH(rj(instr) + rk(instr), static_cast<int16_t>(rd(instr)), instr);
   3663      break;
   3664    case op_stx_w:
   3665      writeW(rj(instr) + rk(instr), static_cast<int32_t>(rd(instr)), instr);
   3666      break;
   3667    case op_stx_d:
   3668      writeDW(rj(instr) + rk(instr), rd(instr), instr);
   3669      break;
   3670    case op_ldx_bu:
   3671      setRegister(rd_reg(instr), readBU(rj(instr) + rk(instr)));
   3672      break;
   3673    case op_ldx_hu:
   3674      setRegister(rd_reg(instr), readHU(rj(instr) + rk(instr), instr));
   3675      break;
   3676    case op_ldx_wu:
   3677      setRegister(rd_reg(instr), readWU(rj(instr) + rk(instr), instr));
   3678      break;
   3679    case op_fldx_s:
   3680      setFpuRegister(fd_reg(instr), kFPUInvalidResult);  // Trash upper 32 bits.
   3681      setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + rk(instr), instr));
   3682      break;
   3683    case op_fldx_d:
   3684      setFpuRegister(fd_reg(instr), kFPUInvalidResult);  // Trash upper 32 bits.
   3685      setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + rk(instr), instr));
   3686      break;
   3687    case op_fstx_s: {
   3688      int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr)));
   3689      writeW(rj(instr) + rk(instr), alu_out_32, instr);
   3690      break;
   3691    }
   3692    case op_fstx_d: {
   3693      writeD(rj(instr) + rk(instr), getFpuRegisterDouble(fd_reg(instr)), instr);
   3694      break;
   3695    }
   3696    case op_amswap_w:
   3697      UNIMPLEMENTED();
   3698      break;
   3699    case op_amswap_d:
   3700      UNIMPLEMENTED();
   3701      break;
   3702    case op_amadd_w:
   3703      UNIMPLEMENTED();
   3704      break;
   3705    case op_amadd_d:
   3706      UNIMPLEMENTED();
   3707      break;
   3708    case op_amand_w:
   3709      UNIMPLEMENTED();
   3710      break;
   3711    case op_amand_d:
   3712      UNIMPLEMENTED();
   3713      break;
   3714    case op_amor_w:
   3715      UNIMPLEMENTED();
   3716      break;
   3717    case op_amor_d:
   3718      UNIMPLEMENTED();
   3719      break;
   3720    case op_amxor_w:
   3721      UNIMPLEMENTED();
   3722      break;
   3723    case op_amxor_d:
   3724      UNIMPLEMENTED();
   3725      break;
   3726    case op_ammax_w:
   3727      UNIMPLEMENTED();
   3728      break;
   3729    case op_ammax_d:
   3730      UNIMPLEMENTED();
   3731      break;
   3732    case op_ammin_w:
   3733      UNIMPLEMENTED();
   3734      break;
   3735    case op_ammin_d:
   3736      UNIMPLEMENTED();
   3737      break;
   3738    case op_ammax_wu:
   3739      UNIMPLEMENTED();
   3740      break;
   3741    case op_ammax_du:
   3742      UNIMPLEMENTED();
   3743      break;
   3744    case op_ammin_wu:
   3745      UNIMPLEMENTED();
   3746      break;
   3747    case op_ammin_du:
   3748      UNIMPLEMENTED();
   3749      break;
   3750    case op_amswap_db_w:
   3751      UNIMPLEMENTED();
   3752      break;
   3753    case op_amswap_db_d:
   3754      UNIMPLEMENTED();
   3755      break;
   3756    case op_amadd_db_w:
   3757      UNIMPLEMENTED();
   3758      break;
   3759    case op_amadd_db_d:
   3760      UNIMPLEMENTED();
   3761      break;
   3762    case op_amand_db_w:
   3763      UNIMPLEMENTED();
   3764      break;
   3765    case op_amand_db_d:
   3766      UNIMPLEMENTED();
   3767      break;
   3768    case op_amor_db_w:
   3769      UNIMPLEMENTED();
   3770      break;
   3771    case op_amor_db_d:
   3772      UNIMPLEMENTED();
   3773      break;
   3774    case op_amxor_db_w:
   3775      UNIMPLEMENTED();
   3776      break;
   3777    case op_amxor_db_d:
   3778      UNIMPLEMENTED();
   3779      break;
   3780    case op_ammax_db_w:
   3781      UNIMPLEMENTED();
   3782      break;
   3783    case op_ammax_db_d:
   3784      UNIMPLEMENTED();
   3785      break;
   3786    case op_ammin_db_w:
   3787      UNIMPLEMENTED();
   3788      break;
   3789    case op_ammin_db_d:
   3790      UNIMPLEMENTED();
   3791      break;
   3792    case op_ammax_db_wu:
   3793      UNIMPLEMENTED();
   3794      break;
   3795    case op_ammax_db_du:
   3796      UNIMPLEMENTED();
   3797      break;
   3798    case op_ammin_db_wu:
   3799      UNIMPLEMENTED();
   3800      break;
   3801    case op_ammin_db_du:
   3802      UNIMPLEMENTED();
   3803      break;
   3804    case op_dbar:
   3805      // TODO(loong64): dbar simulation
   3806      break;
   3807    case op_ibar:
   3808      UNIMPLEMENTED();
   3809      break;
   3810    case op_fcopysign_s:
   3811      setFpuRegisterFloat(fd_reg(instr),
   3812                          std::copysign(fj_float(instr), fk_float(instr)));
   3813      break;
   3814    case op_fcopysign_d:
   3815      setFpuRegisterDouble(fd_reg(instr),
   3816                           std::copysign(fj_double(instr), fk_double(instr)));
   3817      break;
   3818    default:
   3819      UNREACHABLE();
   3820  }
   3821 }
   3822 
   3823 void Simulator::decodeTypeOp22(SimInstruction* instr) {
   3824  int64_t alu_out;
   3825 
   3826  switch (instr->bits(31, 10) << 10) {
   3827    case op_clz_w: {
   3828      alu_out = U32(rj_u(instr)) ? __builtin_clz(U32(rj_u(instr))) : 32;
   3829      setRegister(rd_reg(instr), alu_out);
   3830      break;
   3831    }
   3832    case op_ctz_w: {
   3833      alu_out = U32(rj_u(instr)) ? __builtin_ctz(U32(rj_u(instr))) : 32;
   3834      setRegister(rd_reg(instr), alu_out);
   3835      break;
   3836    }
   3837    case op_clz_d: {
   3838      alu_out = U64(rj_u(instr)) ? __builtin_clzll(U64(rj_u(instr))) : 64;
   3839      setRegister(rd_reg(instr), alu_out);
   3840      break;
   3841    }
   3842    case op_ctz_d: {
   3843      alu_out = U64(rj_u(instr)) ? __builtin_ctzll(U64(rj_u(instr))) : 64;
   3844      setRegister(rd_reg(instr), alu_out);
   3845      break;
   3846    }
   3847    case op_revb_2h: {
   3848      uint32_t input = static_cast<uint32_t>(rj(instr));
   3849      uint64_t output = 0;
   3850 
   3851      uint32_t mask = 0xFF000000;
   3852      for (int i = 0; i < 4; i++) {
   3853        uint32_t tmp = mask & input;
   3854        if (i % 2 == 0) {
   3855          tmp = tmp >> 8;
   3856        } else {
   3857          tmp = tmp << 8;
   3858        }
   3859        output = output | tmp;
   3860        mask = mask >> 8;
   3861      }
   3862 
   3863      alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
   3864      setRegister(rd_reg(instr), alu_out);
   3865      break;
   3866    }
   3867    case op_revb_4h: {
   3868      uint64_t input = rj_u(instr);
   3869      uint64_t output = 0;
   3870 
   3871      uint64_t mask = 0xFF00000000000000;
   3872      for (int i = 0; i < 8; i++) {
   3873        uint64_t tmp = mask & input;
   3874        if (i % 2 == 0) {
   3875          tmp = tmp >> 8;
   3876        } else {
   3877          tmp = tmp << 8;
   3878        }
   3879        output = output | tmp;
   3880        mask = mask >> 8;
   3881      }
   3882 
   3883      alu_out = static_cast<int64_t>(output);
   3884      setRegister(rd_reg(instr), alu_out);
   3885      break;
   3886    }
   3887    case op_revb_2w: {
   3888      uint64_t input = rj_u(instr);
   3889      uint64_t output = 0;
   3890 
   3891      uint64_t mask = 0xFF000000FF000000;
   3892      for (int i = 0; i < 4; i++) {
   3893        uint64_t tmp = mask & input;
   3894        if (i <= 1) {
   3895          tmp = tmp >> (24 - i * 16);
   3896        } else {
   3897          tmp = tmp << (i * 16 - 24);
   3898        }
   3899        output = output | tmp;
   3900        mask = mask >> 8;
   3901      }
   3902 
   3903      alu_out = static_cast<int64_t>(output);
   3904      setRegister(rd_reg(instr), alu_out);
   3905      break;
   3906    }
   3907    case op_revb_d: {
   3908      uint64_t input = rj_u(instr);
   3909      uint64_t output = 0;
   3910 
   3911      uint64_t mask = 0xFF00000000000000;
   3912      for (int i = 0; i < 8; i++) {
   3913        uint64_t tmp = mask & input;
   3914        if (i <= 3) {
   3915          tmp = tmp >> (56 - i * 16);
   3916        } else {
   3917          tmp = tmp << (i * 16 - 56);
   3918        }
   3919        output = output | tmp;
   3920        mask = mask >> 8;
   3921      }
   3922 
   3923      alu_out = static_cast<int64_t>(output);
   3924      setRegister(rd_reg(instr), alu_out);
   3925      break;
   3926    }
   3927    case op_revh_2w: {
   3928      uint64_t input = rj_u(instr);
   3929      uint64_t output = 0;
   3930 
   3931      uint64_t mask = 0xFFFF000000000000;
   3932      for (int i = 0; i < 4; i++) {
   3933        uint64_t tmp = mask & input;
   3934        if (i % 2 == 0) {
   3935          tmp = tmp >> 16;
   3936        } else {
   3937          tmp = tmp << 16;
   3938        }
   3939        output = output | tmp;
   3940        mask = mask >> 16;
   3941      }
   3942 
   3943      alu_out = static_cast<int64_t>(output);
   3944      setRegister(rd_reg(instr), alu_out);
   3945      break;
   3946    }
   3947    case op_revh_d: {
   3948      uint64_t input = rj_u(instr);
   3949      uint64_t output = 0;
   3950 
   3951      uint64_t mask = 0xFFFF000000000000;
   3952      for (int i = 0; i < 4; i++) {
   3953        uint64_t tmp = mask & input;
   3954        if (i <= 1) {
   3955          tmp = tmp >> (48 - i * 32);
   3956        } else {
   3957          tmp = tmp << (i * 32 - 48);
   3958        }
   3959        output = output | tmp;
   3960        mask = mask >> 16;
   3961      }
   3962 
   3963      alu_out = static_cast<int64_t>(output);
   3964      setRegister(rd_reg(instr), alu_out);
   3965      break;
   3966    }
   3967    case op_bitrev_4b: {
   3968      uint32_t input = static_cast<uint32_t>(rj(instr));
   3969      uint32_t output = 0;
   3970      uint8_t i_byte, o_byte;
   3971 
   3972      // Reverse the bit in byte for each individual byte
   3973      for (int i = 0; i < 4; i++) {
   3974        output = output >> 8;
   3975        i_byte = input & 0xFF;
   3976 
   3977        // Fast way to reverse bits in byte
   3978        // Devised by Sean Anderson, July 13, 2001
   3979        o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
   3980                                       (i_byte * 0x8020LU & 0x88440LU)) *
   3981                                          0x10101LU >>
   3982                                      16);
   3983 
   3984        output = output | (static_cast<uint32_t>(o_byte << 24));
   3985        input = input >> 8;
   3986      }
   3987 
   3988      alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
   3989      setRegister(rd_reg(instr), alu_out);
   3990      break;
   3991    }
   3992    case op_bitrev_8b: {
   3993      uint64_t input = rj_u(instr);
   3994      uint64_t output = 0;
   3995      uint8_t i_byte, o_byte;
   3996 
   3997      // Reverse the bit in byte for each individual byte
   3998      for (int i = 0; i < 8; i++) {
   3999        output = output >> 8;
   4000        i_byte = input & 0xFF;
   4001 
   4002        // Fast way to reverse bits in byte
   4003        // Devised by Sean Anderson, July 13, 2001
   4004        o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
   4005                                       (i_byte * 0x8020LU & 0x88440LU)) *
   4006                                          0x10101LU >>
   4007                                      16);
   4008 
   4009        output = output | (static_cast<uint64_t>(o_byte) << 56);
   4010        input = input >> 8;
   4011      }
   4012 
   4013      alu_out = static_cast<int64_t>(output);
   4014      setRegister(rd_reg(instr), alu_out);
   4015      break;
   4016    }
   4017    case op_bitrev_w: {
   4018      uint32_t input = static_cast<uint32_t>(rj(instr));
   4019      uint32_t output = 0;
   4020      output = ReverseBits(input);
   4021      alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
   4022      setRegister(rd_reg(instr), alu_out);
   4023      break;
   4024    }
   4025    case op_bitrev_d: {
   4026      alu_out = static_cast<int64_t>(ReverseBits(rj_u(instr)));
   4027      setRegister(rd_reg(instr), alu_out);
   4028      break;
   4029    }
   4030    case op_ext_w_b: {
   4031      uint8_t input = static_cast<uint8_t>(rj(instr));
   4032      alu_out = static_cast<int64_t>(static_cast<int8_t>(input));
   4033      setRegister(rd_reg(instr), alu_out);
   4034      break;
   4035    }
   4036    case op_ext_w_h: {
   4037      uint16_t input = static_cast<uint16_t>(rj(instr));
   4038      alu_out = static_cast<int64_t>(static_cast<int16_t>(input));
   4039      setRegister(rd_reg(instr), alu_out);
   4040      break;
   4041    }
   4042    case op_fabs_s: {
   4043      setFpuRegisterFloat(fd_reg(instr), std::abs(fj_float(instr)));
   4044      break;
   4045    }
   4046    case op_fabs_d: {
   4047      setFpuRegisterDouble(fd_reg(instr), std::abs(fj_double(instr)));
   4048      break;
   4049    }
   4050    case op_fneg_s: {
   4051      setFpuRegisterFloat(fd_reg(instr), -fj_float(instr));
   4052      break;
   4053    }
   4054    case op_fneg_d: {
   4055      setFpuRegisterDouble(fd_reg(instr), -fj_double(instr));
   4056      break;
   4057    }
   4058    case op_fsqrt_s: {
   4059      if (fj_float(instr) >= 0) {
   4060        setFpuRegisterFloat(fd_reg(instr), std::sqrt(fj_float(instr)));
   4061      } else {
   4062        setFpuRegisterFloat(fd_reg(instr), std::sqrt(-1));  // qnan
   4063        setFCSRBit(kFCSRInvalidOpFlagBit, true);
   4064      }
   4065      break;
   4066    }
   4067    case op_fsqrt_d: {
   4068      if (fj_double(instr) >= 0) {
   4069        setFpuRegisterDouble(fd_reg(instr), std::sqrt(fj_double(instr)));
   4070      } else {
   4071        setFpuRegisterDouble(fd_reg(instr), std::sqrt(-1));  // qnan
   4072        setFCSRBit(kFCSRInvalidOpFlagBit, true);
   4073      }
   4074      break;
   4075    }
   4076    case op_fmov_s: {
   4077      setFpuRegisterFloat(fd_reg(instr), fj_float(instr));
   4078      break;
   4079    }
   4080    case op_fmov_d: {
   4081      setFpuRegisterDouble(fd_reg(instr), fj_double(instr));
   4082      break;
   4083    }
   4084    case op_movgr2fr_w: {
   4085      setFpuRegisterWord(fd_reg(instr), static_cast<int32_t>(rj(instr)));
   4086      break;
   4087    }
   4088    case op_movgr2fr_d: {
   4089      setFpuRegister(fd_reg(instr), rj(instr));
   4090      break;
   4091    }
   4092    case op_movgr2frh_w: {
   4093      setFpuRegisterHiWord(fd_reg(instr), static_cast<int32_t>(rj(instr)));
   4094      break;
   4095    }
   4096    case op_movfr2gr_s: {
   4097      setRegister(rd_reg(instr),
   4098                  static_cast<int64_t>(getFpuRegisterWord(fj_reg(instr))));
   4099      break;
   4100    }
   4101    case op_movfr2gr_d: {
   4102      setRegister(rd_reg(instr), getFpuRegister(fj_reg(instr)));
   4103      break;
   4104    }
   4105    case op_movfrh2gr_s: {
   4106      setRegister(rd_reg(instr), getFpuRegisterHiWord(fj_reg(instr)));
   4107      break;
   4108    }
   4109    case op_movgr2fcsr: {
   4110      // fcsr could be 0-3
   4111      MOZ_ASSERT(rd_reg(instr) < 4);
   4112      FCSR_ = static_cast<uint32_t>(rj(instr));
   4113      break;
   4114    }
   4115    case op_movfcsr2gr: {
   4116      setRegister(rd_reg(instr), FCSR_);
   4117      break;
   4118    }
   4119    case op_fcvt_s_d: {
   4120      setFpuRegisterFloat(fd_reg(instr), static_cast<float>(fj_double(instr)));
   4121      break;
   4122    }
   4123    case op_fcvt_d_s: {
   4124      setFpuRegisterDouble(fd_reg(instr), static_cast<double>(fj_float(instr)));
   4125      break;
   4126    }
   4127    case op_ftintrm_w_s: {
   4128      float fj = fj_float(instr);
   4129      float rounded = std::floor(fj);
   4130      int32_t result = static_cast<int32_t>(rounded);
   4131      setFpuRegisterWord(fd_reg(instr), result);
   4132      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4133        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4134      }
   4135      break;
   4136    }
   4137    case op_ftintrm_w_d: {
   4138      double fj = fj_double(instr);
   4139      double rounded = std::floor(fj);
   4140      int32_t result = static_cast<int32_t>(rounded);
   4141      setFpuRegisterWord(fd_reg(instr), result);
   4142      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4143        setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
   4144      }
   4145      break;
   4146    }
   4147    case op_ftintrm_l_s: {
   4148      float fj = fj_float(instr);
   4149      float rounded = std::floor(fj);
   4150      int64_t result = static_cast<int64_t>(rounded);
   4151      setFpuRegister(fd_reg(instr), result);
   4152      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4153        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4154      }
   4155      break;
   4156    }
   4157    case op_ftintrm_l_d: {
   4158      double fj = fj_double(instr);
   4159      double rounded = std::floor(fj);
   4160      int64_t result = static_cast<int64_t>(rounded);
   4161      setFpuRegister(fd_reg(instr), result);
   4162      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4163        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4164      }
   4165      break;
   4166    }
   4167    case op_ftintrp_w_s: {
   4168      float fj = fj_float(instr);
   4169      float rounded = std::ceil(fj);
   4170      int32_t result = static_cast<int32_t>(rounded);
   4171      setFpuRegisterWord(fd_reg(instr), result);
   4172      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4173        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4174      }
   4175      break;
   4176    }
   4177    case op_ftintrp_w_d: {
   4178      double fj = fj_double(instr);
   4179      double rounded = std::ceil(fj);
   4180      int32_t result = static_cast<int32_t>(rounded);
   4181      setFpuRegisterWord(fd_reg(instr), result);
   4182      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4183        setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
   4184      }
   4185      break;
   4186    }
   4187    case op_ftintrp_l_s: {
   4188      float fj = fj_float(instr);
   4189      float rounded = std::ceil(fj);
   4190      int64_t result = static_cast<int64_t>(rounded);
   4191      setFpuRegister(fd_reg(instr), result);
   4192      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4193        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4194      }
   4195      break;
   4196    }
   4197    case op_ftintrp_l_d: {
   4198      double fj = fj_double(instr);
   4199      double rounded = std::ceil(fj);
   4200      int64_t result = static_cast<int64_t>(rounded);
   4201      setFpuRegister(fd_reg(instr), result);
   4202      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4203        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4204      }
   4205      break;
   4206    }
   4207    case op_ftintrz_w_s: {
   4208      float fj = fj_float(instr);
   4209      float rounded = std::trunc(fj);
   4210      int32_t result = static_cast<int32_t>(rounded);
   4211      setFpuRegisterWord(fd_reg(instr), result);
   4212      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4213        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4214      }
   4215      break;
   4216    }
   4217    case op_ftintrz_w_d: {
   4218      double fj = fj_double(instr);
   4219      double rounded = std::trunc(fj);
   4220      int32_t result = static_cast<int32_t>(rounded);
   4221      setFpuRegisterWord(fd_reg(instr), result);
   4222      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4223        setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
   4224      }
   4225      break;
   4226    }
   4227    case op_ftintrz_l_s: {
   4228      float fj = fj_float(instr);
   4229      float rounded = std::trunc(fj);
   4230      int64_t result = static_cast<int64_t>(rounded);
   4231      setFpuRegister(fd_reg(instr), result);
   4232      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4233        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4234      }
   4235      break;
   4236    }
   4237    case op_ftintrz_l_d: {
   4238      double fj = fj_double(instr);
   4239      double rounded = std::trunc(fj);
   4240      int64_t result = static_cast<int64_t>(rounded);
   4241      setFpuRegister(fd_reg(instr), result);
   4242      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4243        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4244      }
   4245      break;
   4246    }
   4247    case op_ftintrne_w_s: {
   4248      float fj = fj_float(instr);
   4249      float rounded = std::floor(fj + 0.5);
   4250      int32_t result = static_cast<int32_t>(rounded);
   4251      if ((result & 1) != 0 && result - fj == 0.5) {
   4252        // If the number is halfway between two integers,
   4253        // round to the even one.
   4254        result--;
   4255      }
   4256      setFpuRegisterWord(fd_reg(instr), result);
   4257      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4258        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4259      }
   4260      break;
   4261    }
   4262    case op_ftintrne_w_d: {
   4263      double fj = fj_double(instr);
   4264      double rounded = std::floor(fj + 0.5);
   4265      int32_t result = static_cast<int32_t>(rounded);
   4266      if ((result & 1) != 0 && result - fj == 0.5) {
   4267        // If the number is halfway between two integers,
   4268        // round to the even one.
   4269        result--;
   4270      }
   4271      setFpuRegisterWord(fd_reg(instr), result);
   4272      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4273        setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
   4274      }
   4275      break;
   4276    }
   4277    case op_ftintrne_l_s: {
   4278      float fj = fj_float(instr);
   4279      float rounded = std::floor(fj + 0.5);
   4280      int64_t result = static_cast<int64_t>(rounded);
   4281      if ((result & 1) != 0 && result - fj == 0.5) {
   4282        // If the number is halfway between two integers,
   4283        // round to the even one.
   4284        result--;
   4285      }
   4286      setFpuRegister(fd_reg(instr), result);
   4287      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4288        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4289      }
   4290      break;
   4291    }
   4292    case op_ftintrne_l_d: {
   4293      double fj = fj_double(instr);
   4294      double rounded = std::floor(fj + 0.5);
   4295      int64_t result = static_cast<int64_t>(rounded);
   4296      if ((result & 1) != 0 && result - fj == 0.5) {
   4297        // If the number is halfway between two integers,
   4298        // round to the even one.
   4299        result--;
   4300      }
   4301      setFpuRegister(fd_reg(instr), result);
   4302      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4303        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4304      }
   4305      break;
   4306    }
   4307    case op_ftint_w_s: {
   4308      float fj = fj_float(instr);
   4309      float rounded;
   4310      int32_t result;
   4311      roundAccordingToFCSR<float>(fj, &rounded, &result);
   4312      setFpuRegisterWord(fd_reg(instr), result);
   4313      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4314        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4315      }
   4316      break;
   4317    }
   4318    case op_ftint_w_d: {
   4319      double fj = fj_double(instr);
   4320      double rounded;
   4321      int32_t result;
   4322      roundAccordingToFCSR<double>(fj, &rounded, &result);
   4323      setFpuRegisterWord(fd_reg(instr), result);
   4324      if (setFCSRRoundError<int32_t>(fj, rounded)) {
   4325        setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
   4326      }
   4327      break;
   4328    }
   4329    case op_ftint_l_s: {
   4330      float fj = fj_float(instr);
   4331      float rounded;
   4332      int64_t result;
   4333      round64AccordingToFCSR<float>(fj, &rounded, &result);
   4334      setFpuRegister(fd_reg(instr), result);
   4335      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4336        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4337      }
   4338      break;
   4339    }
   4340    case op_ftint_l_d: {
   4341      double fj = fj_double(instr);
   4342      double rounded;
   4343      int64_t result;
   4344      round64AccordingToFCSR<double>(fj, &rounded, &result);
   4345      setFpuRegister(fd_reg(instr), result);
   4346      if (setFCSRRoundError<int64_t>(fj, rounded)) {
   4347        setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
   4348      }
   4349      break;
   4350    }
   4351    case op_ffint_s_w: {
   4352      alu_out = getFpuRegisterSignedWord(fj_reg(instr));
   4353      setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out));
   4354      break;
   4355    }
   4356    case op_ffint_s_l: {
   4357      alu_out = getFpuRegister(fj_reg(instr));
   4358      setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out));
   4359      break;
   4360    }
   4361    case op_ffint_d_w: {
   4362      alu_out = getFpuRegisterSignedWord(fj_reg(instr));
   4363      setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out));
   4364      break;
   4365    }
   4366    case op_ffint_d_l: {
   4367      alu_out = getFpuRegister(fj_reg(instr));
   4368      setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out));
   4369      break;
   4370    }
   4371    case op_frint_s: {
   4372      float fj = fj_float(instr);
   4373      float result, temp_result;
   4374      double temp;
   4375      float upper = std::ceil(fj);
   4376      float lower = std::floor(fj);
   4377      switch (getFCSRRoundingMode()) {
   4378        case kRoundToNearest:
   4379          if (upper - fj < fj - lower) {
   4380            result = upper;
   4381          } else if (upper - fj > fj - lower) {
   4382            result = lower;
   4383          } else {
   4384            temp_result = upper / 2;
   4385            float reminder = std::modf(temp_result, &temp);
   4386            if (reminder == 0) {
   4387              result = upper;
   4388            } else {
   4389              result = lower;
   4390            }
   4391          }
   4392          break;
   4393        case kRoundToZero:
   4394          result = (fj > 0 ? lower : upper);
   4395          break;
   4396        case kRoundToPlusInf:
   4397          result = upper;
   4398          break;
   4399        case kRoundToMinusInf:
   4400          result = lower;
   4401          break;
   4402      }
   4403      setFpuRegisterFloat(fd_reg(instr), result);
   4404      if (result != fj) {
   4405        setFCSRBit(kFCSRInexactFlagBit, true);
   4406      }
   4407      break;
   4408    }
   4409    case op_frint_d: {
   4410      double fj = fj_double(instr);
   4411      double result, temp, temp_result;
   4412      double upper = std::ceil(fj);
   4413      double lower = std::floor(fj);
   4414      switch (getFCSRRoundingMode()) {
   4415        case kRoundToNearest:
   4416          if (upper - fj < fj - lower) {
   4417            result = upper;
   4418          } else if (upper - fj > fj - lower) {
   4419            result = lower;
   4420          } else {
   4421            temp_result = upper / 2;
   4422            double reminder = std::modf(temp_result, &temp);
   4423            if (reminder == 0) {
   4424              result = upper;
   4425            } else {
   4426              result = lower;
   4427            }
   4428          }
   4429          break;
   4430        case kRoundToZero:
   4431          result = (fj > 0 ? lower : upper);
   4432          break;
   4433        case kRoundToPlusInf:
   4434          result = upper;
   4435          break;
   4436        case kRoundToMinusInf:
   4437          result = lower;
   4438          break;
   4439      }
   4440      setFpuRegisterDouble(fd_reg(instr), result);
   4441      if (result != fj) {
   4442        setFCSRBit(kFCSRInexactFlagBit, true);
   4443      }
   4444      break;
   4445    }
   4446    case op_movfr2cf:
   4447      printf("Sim UNIMPLEMENTED: MOVFR2CF\n");
   4448      UNIMPLEMENTED();
   4449      break;
   4450    case op_movgr2cf:
   4451      printf("Sim UNIMPLEMENTED: MOVGR2CF\n");
   4452      UNIMPLEMENTED();
   4453      break;
   4454    case op_clo_w:
   4455      printf("Sim UNIMPLEMENTED: FCO_W\n");
   4456      UNIMPLEMENTED();
   4457      break;
   4458    case op_cto_w:
   4459      printf("Sim UNIMPLEMENTED: FTO_W\n");
   4460      UNIMPLEMENTED();
   4461      break;
   4462    case op_clo_d:
   4463      printf("Sim UNIMPLEMENTED: FLO_D\n");
   4464      UNIMPLEMENTED();
   4465      break;
   4466    case op_cto_d:
   4467      printf("Sim UNIMPLEMENTED: FTO_D\n");
   4468      UNIMPLEMENTED();
   4469      break;
   4470    // Unimplemented opcodes raised an error in the configuration step before,
   4471    // so we can use the default here to set the destination register in common
   4472    // cases.
   4473    default:
   4474      UNREACHABLE();
   4475  }
   4476 }
   4477 
   4478 void Simulator::decodeTypeOp24(SimInstruction* instr) {
   4479  switch (instr->bits(31, 8) << 8) {
   4480    case op_movcf2fr:
   4481      UNIMPLEMENTED();
   4482      break;
   4483    case op_movcf2gr:
   4484      setRegister(rd_reg(instr), getCFRegister(cj_reg(instr)));
   4485      break;
   4486      UNIMPLEMENTED();
   4487      break;
   4488    default:
   4489      UNREACHABLE();
   4490  }
   4491 }
   4492 
   4493 // Executes the current instruction.
   4494 void Simulator::instructionDecode(SimInstruction* instr) {
   4495  if (!SimulatorProcess::ICacheCheckingDisableCount) {
   4496    AutoLockSimulatorCache als;
   4497    SimulatorProcess::checkICacheLocked(instr);
   4498  }
   4499  pc_modified_ = false;
   4500 
   4501  switch (instr->instructionType()) {
   4502    case SimInstruction::kOp6Type:
   4503      decodeTypeOp6(instr);
   4504      break;
   4505    case SimInstruction::kOp7Type:
   4506      decodeTypeOp7(instr);
   4507      break;
   4508    case SimInstruction::kOp8Type:
   4509      decodeTypeOp8(instr);
   4510      break;
   4511    case SimInstruction::kOp10Type:
   4512      decodeTypeOp10(instr);
   4513      break;
   4514    case SimInstruction::kOp11Type:
   4515      decodeTypeOp11(instr);
   4516      break;
   4517    case SimInstruction::kOp12Type:
   4518      decodeTypeOp12(instr);
   4519      break;
   4520    case SimInstruction::kOp14Type:
   4521      decodeTypeOp14(instr);
   4522      break;
   4523    case SimInstruction::kOp15Type:
   4524      decodeTypeOp15(instr);
   4525      break;
   4526    case SimInstruction::kOp16Type:
   4527      decodeTypeOp16(instr);
   4528      break;
   4529    case SimInstruction::kOp17Type:
   4530      decodeTypeOp17(instr);
   4531      break;
   4532    case SimInstruction::kOp22Type:
   4533      decodeTypeOp22(instr);
   4534      break;
   4535    case SimInstruction::kOp24Type:
   4536      decodeTypeOp24(instr);
   4537      break;
   4538    default:
   4539      UNSUPPORTED();
   4540  }
   4541  if (!pc_modified_) {
   4542    setRegister(pc,
   4543                reinterpret_cast<int64_t>(instr) + SimInstruction::kInstrSize);
   4544  }
   4545 }
   4546 
   4547 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) {
   4548  single_stepping_ = true;
   4549  single_step_callback_ = cb;
   4550  single_step_callback_arg_ = arg;
   4551  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   4552 }
   4553 
   4554 void Simulator::disable_single_stepping() {
   4555  if (!single_stepping_) {
   4556    return;
   4557  }
   4558  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   4559  single_stepping_ = false;
   4560  single_step_callback_ = nullptr;
   4561  single_step_callback_arg_ = nullptr;
   4562 }
   4563 
   4564 template <bool enableStopSimAt>
   4565 void Simulator::execute() {
   4566  if (single_stepping_) {
   4567    single_step_callback_(single_step_callback_arg_, this, nullptr);
   4568  }
   4569 
   4570  // Get the PC to simulate. Cannot use the accessor here as we need the
   4571  // raw PC value and not the one used as input to arithmetic instructions.
   4572  int64_t program_counter = get_pc();
   4573 
   4574  while (program_counter != end_sim_pc) {
   4575    if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
   4576      loong64Debugger dbg(this);
   4577      dbg.debug();
   4578    } else {
   4579      if (single_stepping_) {
   4580        single_step_callback_(single_step_callback_arg_, this,
   4581                              (void*)program_counter);
   4582      }
   4583      SimInstruction* instr =
   4584          reinterpret_cast<SimInstruction*>(program_counter);
   4585      instructionDecode(instr);
   4586      icount_++;
   4587    }
   4588    program_counter = get_pc();
   4589  }
   4590 
   4591  if (single_stepping_) {
   4592    single_step_callback_(single_step_callback_arg_, this, nullptr);
   4593  }
   4594 }
   4595 
   4596 void Simulator::callInternal(uint8_t* entry) {
   4597  // Prepare to execute the code at entry.
   4598  setRegister(pc, reinterpret_cast<int64_t>(entry));
   4599  // Put down marker for end of simulation. The simulator will stop simulation
   4600  // when the PC reaches this value. By saving the "end simulation" value into
   4601  // the LR the simulation stops when returning to this call point.
   4602  setRegister(ra, end_sim_pc);
   4603 
   4604  // Remember the values of callee-saved registers.
   4605  // The code below assumes that r9 is not used as sb (static base) in
   4606  // simulator code and therefore is regarded as a callee-saved register.
   4607  int64_t s0_val = getRegister(s0);
   4608  int64_t s1_val = getRegister(s1);
   4609  int64_t s2_val = getRegister(s2);
   4610  int64_t s3_val = getRegister(s3);
   4611  int64_t s4_val = getRegister(s4);
   4612  int64_t s5_val = getRegister(s5);
   4613  int64_t s6_val = getRegister(s6);
   4614  int64_t s7_val = getRegister(s7);
   4615  int64_t s8_val = getRegister(s8);
   4616  int64_t gp_val = getRegister(gp);
   4617  int64_t sp_val = getRegister(sp);
   4618  int64_t tp_val = getRegister(tp);
   4619  int64_t fp_val = getRegister(fp);
   4620 
   4621  // Set up the callee-saved registers with a known value. To be able to check
   4622  // that they are preserved properly across JS execution.
   4623  int64_t callee_saved_value = icount_;
   4624  setRegister(s0, callee_saved_value);
   4625  setRegister(s1, callee_saved_value);
   4626  setRegister(s2, callee_saved_value);
   4627  setRegister(s3, callee_saved_value);
   4628  setRegister(s4, callee_saved_value);
   4629  setRegister(s5, callee_saved_value);
   4630  setRegister(s6, callee_saved_value);
   4631  setRegister(s7, callee_saved_value);
   4632  setRegister(s8, callee_saved_value);
   4633  setRegister(gp, callee_saved_value);
   4634  setRegister(tp, callee_saved_value);
   4635  setRegister(fp, callee_saved_value);
   4636 
   4637  // Start the simulation.
   4638  if (Simulator::StopSimAt != -1) {
   4639    execute<true>();
   4640  } else {
   4641    execute<false>();
   4642  }
   4643 
   4644  // Check that the callee-saved registers have been preserved.
   4645  MOZ_ASSERT(callee_saved_value == getRegister(s0));
   4646  MOZ_ASSERT(callee_saved_value == getRegister(s1));
   4647  MOZ_ASSERT(callee_saved_value == getRegister(s2));
   4648  MOZ_ASSERT(callee_saved_value == getRegister(s3));
   4649  MOZ_ASSERT(callee_saved_value == getRegister(s4));
   4650  MOZ_ASSERT(callee_saved_value == getRegister(s5));
   4651  MOZ_ASSERT(callee_saved_value == getRegister(s6));
   4652  MOZ_ASSERT(callee_saved_value == getRegister(s7));
   4653  MOZ_ASSERT(callee_saved_value == getRegister(s8));
   4654  MOZ_ASSERT(callee_saved_value == getRegister(gp));
   4655  MOZ_ASSERT(callee_saved_value == getRegister(tp));
   4656  MOZ_ASSERT(callee_saved_value == getRegister(fp));
   4657 
   4658  // Restore callee-saved registers with the original value.
   4659  setRegister(s0, s0_val);
   4660  setRegister(s1, s1_val);
   4661  setRegister(s2, s2_val);
   4662  setRegister(s3, s3_val);
   4663  setRegister(s4, s4_val);
   4664  setRegister(s5, s5_val);
   4665  setRegister(s6, s6_val);
   4666  setRegister(s7, s7_val);
   4667  setRegister(s8, s8_val);
   4668  setRegister(gp, gp_val);
   4669  setRegister(sp, sp_val);
   4670  setRegister(tp, tp_val);
   4671  setRegister(fp, fp_val);
   4672 }
   4673 
   4674 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
   4675  va_list parameters;
   4676  va_start(parameters, argument_count);
   4677 
   4678  int64_t original_stack = getRegister(sp);
   4679  // Compute position of stack on entry to generated code.
   4680  int64_t entry_stack = original_stack;
   4681  if (argument_count > kCArgSlotCount) {
   4682    entry_stack = entry_stack - argument_count * sizeof(int64_t);
   4683  } else {
   4684    entry_stack = entry_stack - kCArgsSlotsSize;
   4685  }
   4686 
   4687  entry_stack &= ~U64(ABIStackAlignment - 1);
   4688 
   4689  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
   4690 
   4691  // Setup the arguments.
   4692  for (int i = 0; i < argument_count; i++) {
   4693    js::jit::Register argReg;
   4694    if (GetIntArgReg(i, &argReg)) {
   4695      setRegister(argReg.code(), va_arg(parameters, int64_t));
   4696    } else {
   4697      stack_argument[i] = va_arg(parameters, int64_t);
   4698    }
   4699  }
   4700 
   4701  va_end(parameters);
   4702  setRegister(sp, entry_stack);
   4703 
   4704  callInternal(entry);
   4705 
   4706  // Pop stack passed arguments.
   4707  MOZ_ASSERT(entry_stack == getRegister(sp));
   4708  setRegister(sp, original_stack);
   4709 
   4710  int64_t result = getRegister(a0);
   4711  return result;
   4712 }
   4713 
   4714 uintptr_t Simulator::pushAddress(uintptr_t address) {
   4715  int new_sp = getRegister(sp) - sizeof(uintptr_t);
   4716  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
   4717  *stack_slot = address;
   4718  setRegister(sp, new_sp);
   4719  return new_sp;
   4720 }
   4721 
   4722 uintptr_t Simulator::popAddress() {
   4723  int current_sp = getRegister(sp);
   4724  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
   4725  uintptr_t address = *stack_slot;
   4726  setRegister(sp, current_sp + sizeof(uintptr_t));
   4727  return address;
   4728 }
   4729 
   4730 }  // namespace jit
   4731 }  // namespace js
   4732 
   4733 js::jit::Simulator* JSContext::simulator() const { return simulator_; }