tor-browser

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

Assembler-mips-shared.h (53356B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_mips_shared_Assembler_mips_shared_h
      8 #define jit_mips_shared_Assembler_mips_shared_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Sprintf.h"
     12 
     13 #include "jit/CompactBuffer.h"
     14 #include "jit/JitCode.h"
     15 #include "jit/JitSpewer.h"
     16 #include "jit/mips-shared/Architecture-mips-shared.h"
     17 #include "jit/shared/Assembler-shared.h"
     18 #include "jit/shared/IonAssemblerBuffer.h"
     19 #include "wasm/WasmTypeDecls.h"
     20 
     21 namespace js {
     22 namespace jit {
     23 
     24 static constexpr Register zero{Registers::zero};
     25 static constexpr Register at{Registers::at};
     26 static constexpr Register v0{Registers::v0};
     27 static constexpr Register v1{Registers::v1};
     28 static constexpr Register a0{Registers::a0};
     29 static constexpr Register a1{Registers::a1};
     30 static constexpr Register a2{Registers::a2};
     31 static constexpr Register a3{Registers::a3};
     32 static constexpr Register a4{Registers::a4};
     33 static constexpr Register a5{Registers::a5};
     34 static constexpr Register a6{Registers::a6};
     35 static constexpr Register a7{Registers::a7};
     36 static constexpr Register t4{Registers::t4};
     37 static constexpr Register t5{Registers::t5};
     38 static constexpr Register t6{Registers::t6};
     39 static constexpr Register t7{Registers::t7};
     40 static constexpr Register s0{Registers::s0};
     41 static constexpr Register s1{Registers::s1};
     42 static constexpr Register s2{Registers::s2};
     43 static constexpr Register s3{Registers::s3};
     44 static constexpr Register s4{Registers::s4};
     45 static constexpr Register s5{Registers::s5};
     46 static constexpr Register s6{Registers::s6};
     47 static constexpr Register s7{Registers::s7};
     48 static constexpr Register t8{Registers::t8};
     49 static constexpr Register t9{Registers::t9};
     50 static constexpr Register k0{Registers::k0};
     51 static constexpr Register k1{Registers::k1};
     52 static constexpr Register gp{Registers::gp};
     53 static constexpr Register sp{Registers::sp};
     54 static constexpr Register fp{Registers::fp};
     55 static constexpr Register ra{Registers::ra};
     56 
     57 // Scratch register set aside for runtime patching.
     58 // See also Assembler::PatchWrite_NearCall, MacroAssembler::patchNopToCall.
     59 static constexpr Register ScratchRegister = t9;
     60 
     61 class AssemblerMIPSShared;
     62 
     63 class UseScratchRegisterScope {
     64 public:
     65  explicit UseScratchRegisterScope(AssemblerMIPSShared& assembler);
     66  explicit UseScratchRegisterScope(AssemblerMIPSShared* assembler);
     67  ~UseScratchRegisterScope();
     68 
     69  Register Acquire();
     70  void Release(const Register& reg);
     71  bool hasAvailable() const;
     72  void Include(const GeneralRegisterSet& list) {
     73    *available_ = GeneralRegisterSet::Union(*available_, list);
     74  }
     75  void Exclude(const GeneralRegisterSet& list) {
     76    *available_ = GeneralRegisterSet::Subtract(*available_, list);
     77  }
     78 
     79 private:
     80  GeneralRegisterSet* available_;
     81  GeneralRegisterSet old_available_;
     82 };
     83 
     84 // Use arg reg from EnterJIT function as OsrFrameReg.
     85 static constexpr Register OsrFrameReg = a3;
     86 static constexpr Register CallTempReg0 = t4;
     87 static constexpr Register CallTempReg1 = t5;
     88 static constexpr Register CallTempReg2 = t6;
     89 static constexpr Register CallTempReg3 = t7;
     90 
     91 static constexpr Register IntArgReg0 = a0;
     92 static constexpr Register IntArgReg1 = a1;
     93 static constexpr Register IntArgReg2 = a2;
     94 static constexpr Register IntArgReg3 = a3;
     95 static constexpr Register IntArgReg4 = a4;
     96 static constexpr Register IntArgReg5 = a5;
     97 static constexpr Register IntArgReg6 = a6;
     98 static constexpr Register IntArgReg7 = a7;
     99 static constexpr Register GlobalReg = s6;  // used by Odin
    100 static constexpr Register HeapReg = s7;    // used by Odin
    101 
    102 static constexpr Register PreBarrierReg = a1;
    103 
    104 static constexpr Register InvalidReg{Registers::invalid_reg};
    105 static constexpr FloatRegister InvalidFloatReg;
    106 
    107 static constexpr Register StackPointer = sp;
    108 static constexpr Register FramePointer = fp;
    109 static constexpr Register ReturnReg = v0;
    110 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
    111 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
    112 
    113 // A bias applied to the GlobalReg to allow the use of instructions with small
    114 // negative immediate offsets which doubles the range of global data that can be
    115 // accessed with a single instruction.
    116 static const int32_t WasmGlobalRegBias = 32768;
    117 
    118 // Registers used by RegExpMatcher and RegExpExecMatch stubs (do not use
    119 // JSReturnOperand).
    120 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
    121 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
    122 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
    123 
    124 // Registers used by RegExpExecTest stub (do not use ReturnReg).
    125 static constexpr Register RegExpExecTestRegExpReg = CallTempReg0;
    126 static constexpr Register RegExpExecTestStringReg = CallTempReg1;
    127 
    128 // Registers used by RegExpSearcher stub (do not use ReturnReg).
    129 static constexpr Register RegExpSearcherRegExpReg = CallTempReg0;
    130 static constexpr Register RegExpSearcherStringReg = CallTempReg1;
    131 static constexpr Register RegExpSearcherLastIndexReg = CallTempReg2;
    132 
    133 static constexpr uint32_t CodeAlignment = 8;
    134 
    135 /* clang-format off */
    136 // MIPS instruction types
    137 //                +---------------------------------------------------------------+
    138 //                |    6      |    5    |    5    |    5    |    5    |    6      |
    139 //                +---------------------------------------------------------------+
    140 // Register type  |  Opcode   |    Rs   |    Rt   |    Rd   |    Sa   | Function  |
    141 //                +---------------------------------------------------------------+
    142 //                |    6      |    5    |    5    |               16              |
    143 //                +---------------------------------------------------------------+
    144 // Immediate type |  Opcode   |    Rs   |    Rt   |    2's complement constant    |
    145 //                +---------------------------------------------------------------+
    146 //                |    6      |                        26                         |
    147 //                +---------------------------------------------------------------+
    148 // Jump type      |  Opcode   |                    jump_target                    |
    149 //                +---------------------------------------------------------------+
    150 //                31 bit                                                      bit 0
    151 /* clang-format on */
    152 
    153 // MIPS instruction encoding constants.
    154 static const uint32_t OpcodeShift = 26;
    155 static const uint32_t OpcodeBits = 6;
    156 static const uint32_t RSShift = 21;
    157 static const uint32_t RSBits = 5;
    158 static const uint32_t RTShift = 16;
    159 static const uint32_t RTBits = 5;
    160 static const uint32_t RDShift = 11;
    161 static const uint32_t RDBits = 5;
    162 static const uint32_t RZShift = 0;
    163 static const uint32_t RZBits = 5;
    164 static const uint32_t SAShift = 6;
    165 static const uint32_t SABits = 5;
    166 static const uint32_t FunctionShift = 0;
    167 static const uint32_t FunctionBits = 6;
    168 static const uint32_t Imm16Shift = 0;
    169 static const uint32_t Imm16Bits = 16;
    170 static const uint32_t Imm26Shift = 0;
    171 static const uint32_t Imm26Bits = 26;
    172 static const uint32_t Imm28Shift = 0;
    173 static const uint32_t Imm28Bits = 28;
    174 static const uint32_t ImmFieldShift = 2;
    175 static const uint32_t FRBits = 5;
    176 static const uint32_t FRShift = 21;
    177 static const uint32_t FSShift = 11;
    178 static const uint32_t FSBits = 5;
    179 static const uint32_t FTShift = 16;
    180 static const uint32_t FTBits = 5;
    181 static const uint32_t FDShift = 6;
    182 static const uint32_t FDBits = 5;
    183 static const uint32_t FCccShift = 8;
    184 static const uint32_t FCccBits = 3;
    185 static const uint32_t FBccShift = 18;
    186 static const uint32_t FBccBits = 3;
    187 static const uint32_t FBtrueShift = 16;
    188 static const uint32_t FBtrueBits = 1;
    189 static const uint32_t FccMask = 0x7;
    190 static const uint32_t FccShift = 2;
    191 
    192 // MIPS instruction  field bit masks.
    193 static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift;
    194 static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift;
    195 static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift;
    196 static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift;
    197 static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift;
    198 static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift;
    199 static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift;
    200 static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift;
    201 static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift;
    202 static const uint32_t RegMask = Registers::Total - 1;
    203 
    204 static const uint32_t BREAK_STACK_UNALIGNED = 1;
    205 static const uint32_t MAX_BREAK_CODE = 1024 - 1;
    206 static const uint32_t WASM_TRAP = 6;  // BRK_OVERFLOW
    207 
    208 class Instruction;
    209 class InstReg;
    210 class InstImm;
    211 class InstJump;
    212 
    213 uint32_t RS(Register r);
    214 uint32_t RT(Register r);
    215 uint32_t RT(FloatRegister r);
    216 uint32_t RD(Register r);
    217 uint32_t RD(FloatRegister r);
    218 uint32_t RZ(Register r);
    219 uint32_t RZ(FloatRegister r);
    220 uint32_t SA(uint32_t value);
    221 uint32_t SA(FloatRegister r);
    222 uint32_t FS(uint32_t value);
    223 
    224 Register toRS(Instruction& i);
    225 Register toRT(Instruction& i);
    226 Register toRD(Instruction& i);
    227 Register toR(Instruction& i);
    228 
    229 // MIPS enums for instruction fields
    230 enum OpcodeField {
    231  op_special = 0 << OpcodeShift,
    232  op_regimm = 1 << OpcodeShift,
    233 
    234  op_j = 2 << OpcodeShift,
    235  op_jal = 3 << OpcodeShift,
    236  op_beq = 4 << OpcodeShift,
    237  op_bne = 5 << OpcodeShift,
    238  op_blez = 6 << OpcodeShift,
    239  op_bgtz = 7 << OpcodeShift,
    240 
    241  op_addi = 8 << OpcodeShift,
    242  op_addiu = 9 << OpcodeShift,
    243  op_slti = 10 << OpcodeShift,
    244  op_sltiu = 11 << OpcodeShift,
    245  op_andi = 12 << OpcodeShift,
    246  op_ori = 13 << OpcodeShift,
    247  op_xori = 14 << OpcodeShift,
    248  op_lui = 15 << OpcodeShift,
    249 
    250  op_cop1 = 17 << OpcodeShift,
    251  op_cop1x = 19 << OpcodeShift,
    252 
    253  op_beql = 20 << OpcodeShift,
    254  op_bnel = 21 << OpcodeShift,
    255  op_blezl = 22 << OpcodeShift,
    256  op_bgtzl = 23 << OpcodeShift,
    257 
    258  op_daddi = 24 << OpcodeShift,
    259  op_daddiu = 25 << OpcodeShift,
    260 
    261  op_ldl = 26 << OpcodeShift,
    262  op_ldr = 27 << OpcodeShift,
    263 
    264  op_special2 = 28 << OpcodeShift,
    265  op_special3 = 31 << OpcodeShift,
    266 
    267  op_lb = 32 << OpcodeShift,
    268  op_lh = 33 << OpcodeShift,
    269  op_lwl = 34 << OpcodeShift,
    270  op_lw = 35 << OpcodeShift,
    271  op_lbu = 36 << OpcodeShift,
    272  op_lhu = 37 << OpcodeShift,
    273  op_lwr = 38 << OpcodeShift,
    274  op_lwu = 39 << OpcodeShift,
    275  op_sb = 40 << OpcodeShift,
    276  op_sh = 41 << OpcodeShift,
    277  op_swl = 42 << OpcodeShift,
    278  op_sw = 43 << OpcodeShift,
    279  op_sdl = 44 << OpcodeShift,
    280  op_sdr = 45 << OpcodeShift,
    281  op_swr = 46 << OpcodeShift,
    282 
    283  op_ll = 48 << OpcodeShift,
    284  op_lwc1 = 49 << OpcodeShift,
    285  op_lwc2 = 50 << OpcodeShift,
    286  op_lld = 52 << OpcodeShift,
    287  op_ldc1 = 53 << OpcodeShift,
    288  op_ldc2 = 54 << OpcodeShift,
    289  op_ld = 55 << OpcodeShift,
    290 
    291  op_sc = 56 << OpcodeShift,
    292  op_swc1 = 57 << OpcodeShift,
    293  op_swc2 = 58 << OpcodeShift,
    294  op_scd = 60 << OpcodeShift,
    295  op_sdc1 = 61 << OpcodeShift,
    296  op_sdc2 = 62 << OpcodeShift,
    297  op_sd = 63 << OpcodeShift,
    298 };
    299 
    300 enum RSField {
    301  rs_zero = 0 << RSShift,
    302  // cop1 encoding of RS field.
    303  rs_mfc1 = 0 << RSShift,
    304  rs_one = 1 << RSShift,
    305  rs_dmfc1 = 1 << RSShift,
    306  rs_cfc1 = 2 << RSShift,
    307  rs_mfhc1 = 3 << RSShift,
    308  rs_mtc1 = 4 << RSShift,
    309  rs_dmtc1 = 5 << RSShift,
    310  rs_ctc1 = 6 << RSShift,
    311  rs_mthc1 = 7 << RSShift,
    312  rs_bc1 = 8 << RSShift,
    313  rs_f = 0x9 << RSShift,
    314  rs_t = 0xd << RSShift,
    315  rs_s_r6 = 20 << RSShift,
    316  rs_d_r6 = 21 << RSShift,
    317  rs_s = 16 << RSShift,
    318  rs_d = 17 << RSShift,
    319  rs_w = 20 << RSShift,
    320  rs_l = 21 << RSShift,
    321  rs_ps = 22 << RSShift
    322 };
    323 
    324 enum RTField {
    325  rt_zero = 0 << RTShift,
    326  // regimm  encoding of RT field.
    327  rt_bltz = 0 << RTShift,
    328  rt_bgez = 1 << RTShift,
    329  rt_bltzal = 16 << RTShift,
    330  rt_bgezal = 17 << RTShift
    331 };
    332 
    333 enum FunctionField {
    334  // special encoding of function field.
    335  ff_sll = 0,
    336  ff_movci = 1,
    337  ff_srl = 2,
    338  ff_sra = 3,
    339  ff_sllv = 4,
    340  ff_srlv = 6,
    341  ff_srav = 7,
    342 
    343  ff_jr = 8,
    344  ff_jalr = 9,
    345  ff_movz = 10,
    346  ff_movn = 11,
    347  ff_break = 13,
    348  ff_sync = 15,
    349 
    350  ff_mfhi = 16,
    351  ff_mflo = 18,
    352 
    353  ff_dsllv = 20,
    354  ff_dsrlv = 22,
    355  ff_dsrav = 23,
    356 
    357  ff_mult = 24,
    358  ff_multu = 25,
    359 
    360  ff_mulu = 25,
    361  ff_muh = 24,
    362  ff_muhu = 25,
    363  ff_dmul = 28,
    364  ff_dmulu = 29,
    365  ff_dmuh = 28,
    366  ff_dmuhu = 29,
    367 
    368  ff_div = 26,
    369  ff_mod = 26,
    370  ff_divu = 27,
    371  ff_modu = 27,
    372  ff_dmult = 28,
    373  ff_dmultu = 29,
    374  ff_ddiv = 30,
    375  ff_dmod = 30,
    376  ff_ddivu = 31,
    377  ff_dmodu = 31,
    378 
    379  ff_add = 32,
    380  ff_addu = 33,
    381  ff_sub = 34,
    382  ff_subu = 35,
    383  ff_and = 36,
    384  ff_or = 37,
    385  ff_xor = 38,
    386  ff_nor = 39,
    387 
    388  ff_slt = 42,
    389  ff_sltu = 43,
    390  ff_dadd = 44,
    391  ff_daddu = 45,
    392  ff_dsub = 46,
    393  ff_dsubu = 47,
    394 
    395  ff_tge = 48,
    396  ff_tgeu = 49,
    397  ff_tlt = 50,
    398  ff_tltu = 51,
    399  ff_teq = 52,
    400  ff_seleqz = 53,
    401  ff_tne = 54,
    402  ff_selnez = 55,
    403  ff_dsll = 56,
    404  ff_dsrl = 58,
    405  ff_dsra = 59,
    406  ff_dsll32 = 60,
    407  ff_dsrl32 = 62,
    408  ff_dsra32 = 63,
    409 
    410  // special2 encoding of function field.
    411  ff_madd = 0,
    412  ff_maddu = 1,
    413 #ifdef MIPSR6
    414  ff_clz = 16,
    415  ff_dclz = 18,
    416  ff_mul = 24,
    417 #else
    418  ff_mul = 2,
    419  ff_clz = 32,
    420  ff_dclz = 36,
    421 #endif
    422  ff_clo = 33,
    423 
    424  // special3 encoding of function field.
    425  ff_ext = 0,
    426  ff_dextm = 1,
    427  ff_dextu = 2,
    428  ff_dext = 3,
    429  ff_ins = 4,
    430  ff_dinsm = 5,
    431  ff_dinsu = 6,
    432  ff_dins = 7,
    433  ff_bshfl = 32,
    434  ff_dbshfl = 36,
    435  ff_sc = 38,
    436  ff_scd = 39,
    437  ff_ll = 54,
    438  ff_lld = 55,
    439 
    440  // cop1 encoding of function field.
    441  ff_add_fmt = 0,
    442  ff_sub_fmt = 1,
    443  ff_mul_fmt = 2,
    444  ff_div_fmt = 3,
    445  ff_sqrt_fmt = 4,
    446  ff_abs_fmt = 5,
    447  ff_mov_fmt = 6,
    448  ff_neg_fmt = 7,
    449 
    450  ff_round_l_fmt = 8,
    451  ff_trunc_l_fmt = 9,
    452  ff_ceil_l_fmt = 10,
    453  ff_floor_l_fmt = 11,
    454 
    455  ff_round_w_fmt = 12,
    456  ff_trunc_w_fmt = 13,
    457  ff_ceil_w_fmt = 14,
    458  ff_floor_w_fmt = 15,
    459 
    460  ff_movf_fmt = 17,
    461  ff_movz_fmt = 18,
    462  ff_movn_fmt = 19,
    463 
    464  ff_min = 28,
    465  ff_max = 30,
    466 
    467  ff_cvt_s_fmt = 32,
    468  ff_cvt_d_fmt = 33,
    469  ff_cvt_w_fmt = 36,
    470  ff_cvt_l_fmt = 37,
    471  ff_cvt_ps_s = 38,
    472 
    473 #ifdef MIPSR6
    474  ff_c_f_fmt = 0,
    475  ff_c_un_fmt = 1,
    476  ff_c_eq_fmt = 2,
    477  ff_c_ueq_fmt = 3,
    478  ff_c_olt_fmt = 4,
    479  ff_c_ult_fmt = 5,
    480  ff_c_ole_fmt = 6,
    481  ff_c_ule_fmt = 7,
    482 #else
    483  ff_c_f_fmt = 48,
    484  ff_c_un_fmt = 49,
    485  ff_c_eq_fmt = 50,
    486  ff_c_ueq_fmt = 51,
    487  ff_c_olt_fmt = 52,
    488  ff_c_ult_fmt = 53,
    489  ff_c_ole_fmt = 54,
    490  ff_c_ule_fmt = 55,
    491 #endif
    492 
    493  ff_madd_s = 32,
    494  ff_madd_d = 33,
    495 
    496  // Loongson encoding of function field.
    497  ff_gsxbx = 0,
    498  ff_gsxhx = 1,
    499  ff_gsxwx = 2,
    500  ff_gsxdx = 3,
    501  ff_gsxwlc1 = 4,
    502  ff_gsxwrc1 = 5,
    503  ff_gsxdlc1 = 6,
    504  ff_gsxdrc1 = 7,
    505  ff_gsxwxc1 = 6,
    506  ff_gsxdxc1 = 7,
    507  ff_gsxq = 0x20,
    508  ff_gsxqc1 = 0x8020,
    509 
    510  ff_null = 0
    511 };
    512 
    513 class Operand;
    514 
    515 // A BOffImm16 is a 16 bit immediate that is used for branches.
    516 class BOffImm16 {
    517  uint32_t data;
    518 
    519 public:
    520  uint32_t encode() {
    521    MOZ_ASSERT(!isInvalid());
    522    return data;
    523  }
    524  int32_t decode() {
    525    MOZ_ASSERT(!isInvalid());
    526    return (int32_t(data << 18) >> 16) + 4;
    527  }
    528 
    529  explicit BOffImm16(int offset) : data((offset - 4) >> 2 & Imm16Mask) {
    530    MOZ_ASSERT((offset & 0x3) == 0);
    531    MOZ_ASSERT(IsInRange(offset));
    532  }
    533  static bool IsInRange(int offset) {
    534    if ((offset - 4) < int(unsigned(INT16_MIN) << 2)) {
    535      return false;
    536    }
    537    if ((offset - 4) > (INT16_MAX << 2)) {
    538      return false;
    539    }
    540    return true;
    541  }
    542  static const uint32_t INVALID = 0x00020000;
    543  BOffImm16() : data(INVALID) {}
    544 
    545  bool isInvalid() { return data == INVALID; }
    546  Instruction* getDest(Instruction* src) const;
    547 
    548  explicit BOffImm16(InstImm inst);
    549 };
    550 
    551 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps.
    552 class JOffImm26 {
    553  uint32_t data;
    554 
    555 public:
    556  uint32_t encode() {
    557    MOZ_ASSERT(!isInvalid());
    558    return data;
    559  }
    560  int32_t decode() {
    561    MOZ_ASSERT(!isInvalid());
    562    return (int32_t(data << 8) >> 6) + 4;
    563  }
    564 
    565  explicit JOffImm26(int offset) : data((offset - 4) >> 2 & Imm26Mask) {
    566    MOZ_ASSERT((offset & 0x3) == 0);
    567    MOZ_ASSERT(IsInRange(offset));
    568  }
    569  static bool IsInRange(int offset) {
    570    if ((offset - 4) < -536870912) {
    571      return false;
    572    }
    573    if ((offset - 4) > 536870908) {
    574      return false;
    575    }
    576    return true;
    577  }
    578  static const uint32_t INVALID = 0x20000000;
    579  JOffImm26() : data(INVALID) {}
    580 
    581  bool isInvalid() { return data == INVALID; }
    582  Instruction* getDest(Instruction* src);
    583 };
    584 
    585 class Imm16 {
    586  uint16_t value;
    587 
    588 public:
    589  Imm16();
    590  explicit Imm16(uint32_t imm) : value(imm) {}
    591  uint32_t encode() { return value; }
    592  int32_t decodeSigned() { return value; }
    593  uint32_t decodeUnsigned() { return value; }
    594  static bool IsInSignedRange(int32_t imm) {
    595    return imm >= INT16_MIN && imm <= INT16_MAX;
    596  }
    597  static bool IsInSignedRange(int64_t imm) {
    598    return imm >= INT16_MIN && imm <= INT16_MAX;
    599  }
    600  static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; }
    601  static Imm16 Lower(Imm32 imm) { return Imm16(imm.value & 0xffff); }
    602  static Imm16 Upper(Imm32 imm) { return Imm16((imm.value >> 16) & 0xffff); }
    603 };
    604 
    605 class Imm8 {
    606  uint8_t value;
    607 
    608 public:
    609  Imm8();
    610  explicit Imm8(uint32_t imm) : value(imm) {}
    611  uint32_t encode(uint32_t shift) { return value << shift; }
    612  int32_t decodeSigned() { return value; }
    613  uint32_t decodeUnsigned() { return value; }
    614  static bool IsInSignedRange(int32_t imm) {
    615    return imm >= INT8_MIN && imm <= INT8_MAX;
    616  }
    617  static bool IsInSignedRange(intptr_t imm) {
    618    return imm >= INT8_MIN && imm <= INT8_MAX;
    619  }
    620  static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; }
    621  static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); }
    622  static Imm8 Upper(Imm16 imm) {
    623    return Imm8((imm.decodeSigned() >> 8) & 0xff);
    624  }
    625 };
    626 
    627 class GSImm13 {
    628  uint16_t value;
    629 
    630 public:
    631  GSImm13();
    632  explicit GSImm13(uint32_t imm) : value(imm & ~0xf) {}
    633  uint32_t encode(uint32_t shift) { return ((value >> 4) & 0x1ff) << shift; }
    634  int32_t decodeSigned() { return value; }
    635  uint32_t decodeUnsigned() { return value; }
    636  static bool IsInRange(int32_t imm) {
    637    return imm >= int32_t(uint32_t(-256) << 4) && imm <= (255 << 4);
    638  }
    639 };
    640 
    641 class Operand {
    642 public:
    643  enum Tag { REG, FREG, MEM };
    644 
    645 private:
    646  Tag tag : 3;
    647  uint32_t reg : 5;
    648  int32_t offset;
    649 
    650 public:
    651  explicit Operand(Register reg_) : tag(REG), reg(reg_.code()) {}
    652 
    653  explicit Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {}
    654 
    655  Operand(Register base, Imm32 off)
    656      : tag(MEM), reg(base.code()), offset(off.value) {}
    657 
    658  Operand(Register base, int32_t off)
    659      : tag(MEM), reg(base.code()), offset(off) {}
    660 
    661  explicit Operand(const Address& addr)
    662      : tag(MEM), reg(addr.base.code()), offset(addr.offset) {}
    663 
    664  Tag getTag() const { return tag; }
    665 
    666  Register toReg() const {
    667    MOZ_ASSERT(tag == REG);
    668    return Register::FromCode(reg);
    669  }
    670 
    671  FloatRegister toFReg() const {
    672    MOZ_ASSERT(tag == FREG);
    673    return FloatRegister::FromCode(reg);
    674  }
    675 
    676  void toAddr(Register* r, Imm32* dest) const {
    677    MOZ_ASSERT(tag == MEM);
    678    *r = Register::FromCode(reg);
    679    *dest = Imm32(offset);
    680  }
    681  Address toAddress() const {
    682    MOZ_ASSERT(tag == MEM);
    683    return Address(Register::FromCode(reg), offset);
    684  }
    685  int32_t disp() const {
    686    MOZ_ASSERT(tag == MEM);
    687    return offset;
    688  }
    689 
    690  int32_t base() const {
    691    MOZ_ASSERT(tag == MEM);
    692    return reg;
    693  }
    694  Register baseReg() const {
    695    MOZ_ASSERT(tag == MEM);
    696    return Register::FromCode(reg);
    697  }
    698 };
    699 
    700 static constexpr int32_t SliceSize = 1024;
    701 typedef js::jit::AssemblerBuffer<SliceSize, Instruction> MIPSBuffer;
    702 
    703 class MIPSBufferWithExecutableCopy : public MIPSBuffer {
    704 public:
    705  void executableCopy(uint8_t* buffer) {
    706    if (this->oom()) {
    707      return;
    708    }
    709 
    710    for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) {
    711      memcpy(buffer, &cur->instructions, cur->length());
    712      buffer += cur->length();
    713    }
    714  }
    715 
    716  bool appendRawCode(const uint8_t* code, size_t numBytes) {
    717    if (this->oom()) {
    718      return false;
    719    }
    720    while (numBytes > SliceSize) {
    721      this->putBytes(SliceSize, code);
    722      numBytes -= SliceSize;
    723      code += SliceSize;
    724    }
    725    this->putBytes(numBytes, code);
    726    return !this->oom();
    727  }
    728 };
    729 
    730 class AssemblerMIPSShared : public AssemblerShared {
    731 public:
    732  enum Condition {
    733    Equal,
    734    NotEqual,
    735    Above,
    736    AboveOrEqual,
    737    Below,
    738    BelowOrEqual,
    739    GreaterThan,
    740    GreaterThanOrEqual,
    741    LessThan,
    742    LessThanOrEqual,
    743    Overflow,
    744    CarrySet,
    745    CarryClear,
    746    Signed,
    747    NotSigned,
    748    Zero,
    749    NonZero,
    750    Always,
    751  };
    752 
    753  enum DoubleCondition {
    754    // These conditions will only evaluate to true if the comparison is ordered
    755    // - i.e. neither operand is NaN.
    756    DoubleOrdered,
    757    DoubleEqual,
    758    DoubleNotEqual,
    759    DoubleGreaterThan,
    760    DoubleGreaterThanOrEqual,
    761    DoubleLessThan,
    762    DoubleLessThanOrEqual,
    763    // If either operand is NaN, these conditions always evaluate to true.
    764    DoubleUnordered,
    765    DoubleEqualOrUnordered,
    766    DoubleNotEqualOrUnordered,
    767    DoubleGreaterThanOrUnordered,
    768    DoubleGreaterThanOrEqualOrUnordered,
    769    DoubleLessThanOrUnordered,
    770    DoubleLessThanOrEqualOrUnordered
    771  };
    772 
    773  enum FPConditionBit { FCC0 = 0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 };
    774 
    775  enum FPControl {
    776    FIR = 0,
    777    UFR,
    778    UNFR = 4,
    779    FCCR = 25,
    780    FEXR,
    781    FENR = 28,
    782    FCSR = 31
    783  };
    784 
    785  enum FCSRBit { CauseI = 12, CauseU, CauseO, CauseZ, CauseV };
    786 
    787  enum FloatFormat { SingleFloat, DoubleFloat };
    788 
    789  enum JumpOrCall { BranchIsJump, BranchIsCall };
    790 
    791  enum FloatTestKind { TestForTrue, TestForFalse };
    792 
    793  // :( this should be protected, but since CodeGenerator
    794  // wants to use it, It needs to go out here :(
    795 
    796  BufferOffset nextOffset() { return m_buffer.nextOffset(); }
    797 
    798 protected:
    799  Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); }
    800 
    801  // structure for fixing up pc-relative loads/jumps when a the machine code
    802  // gets moved (executable copy, gc, etc.)
    803  struct RelativePatch {
    804    // the offset within the code buffer where the value is loaded that
    805    // we want to fix-up
    806    BufferOffset offset;
    807    void* target;
    808    RelocationKind kind;
    809 
    810    RelativePatch(BufferOffset offset, void* target, RelocationKind kind)
    811        : offset(offset), target(target), kind(kind) {}
    812  };
    813 
    814  js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
    815 
    816  CompactBufferWriter jumpRelocations_;
    817  CompactBufferWriter dataRelocations_;
    818 
    819  MIPSBufferWithExecutableCopy m_buffer;
    820 
    821 #ifdef JS_JITSPEW
    822  Sprinter* printer;
    823 #endif
    824 
    825 public:
    826  AssemblerMIPSShared()
    827      : m_buffer(),
    828 #ifdef JS_JITSPEW
    829        printer(nullptr),
    830 #endif
    831        isFinished(false),
    832        scratch_register_list_((1 << at.code()) | (1 << t8.code())) {
    833  }
    834 
    835  static Condition InvertCondition(Condition cond);
    836  static DoubleCondition InvertCondition(DoubleCondition cond);
    837 
    838  // As opposed to x86/x64 version, the data relocation has to be executed
    839  // before to recover the pointer, and not after.
    840  void writeDataRelocation(ImmGCPtr ptr) {
    841    // Raw GC pointer relocations and Value relocations both end up in
    842    // TraceOneDataRelocation.
    843    if (ptr.value) {
    844      if (gc::IsInsideNursery(ptr.value)) {
    845        embedsNurseryPointers_ = true;
    846      }
    847      dataRelocations_.writeUnsigned(nextOffset().getOffset());
    848    }
    849  }
    850 
    851  void assertNoGCThings() const {
    852 #ifdef DEBUG
    853    MOZ_ASSERT(dataRelocations_.length() == 0);
    854    for (auto& j : jumps_) {
    855      MOZ_ASSERT(j.kind == RelocationKind::HARDCODED);
    856    }
    857 #endif
    858  }
    859 
    860 public:
    861  void setUnlimitedBuffer() { m_buffer.setUnlimited(); }
    862  bool oom() const;
    863 
    864  void setPrinter(Sprinter* sp) {
    865 #ifdef JS_JITSPEW
    866    printer = sp;
    867 #endif
    868  }
    869 
    870 #ifdef JS_JITSPEW
    871  inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {
    872    if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) {
    873      va_list va;
    874      va_start(va, fmt);
    875      spew(fmt, va);
    876      va_end(va);
    877    }
    878  }
    879 
    880  void decodeBranchInstAndSpew(InstImm branch);
    881 #else
    882  MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {}
    883 #endif
    884 
    885 #ifdef JS_JITSPEW
    886  MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) {
    887    // Buffer to hold the formatted string. Note that this may contain
    888    // '%' characters, so do not pass it directly to printf functions.
    889    char buf[200];
    890 
    891    int i = VsprintfLiteral(buf, fmt, va);
    892    if (i > -1) {
    893      if (printer) {
    894        printer->printf("%s\n", buf);
    895      }
    896      js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf);
    897    }
    898  }
    899 #endif
    900 
    901  Register getStackPointer() const { return StackPointer; }
    902 
    903 protected:
    904  bool isFinished;
    905 
    906 public:
    907  void finish();
    908  bool appendRawCode(const uint8_t* code, size_t numBytes);
    909  bool reserve(size_t size);
    910  bool swapBuffer(wasm::Bytes& bytes);
    911  void executableCopy(void* buffer);
    912  void copyJumpRelocationTable(uint8_t* dest);
    913  void copyDataRelocationTable(uint8_t* dest);
    914 
    915  // Size of the instruction stream, in bytes.
    916  size_t size() const;
    917  // Size of the jump relocation table, in bytes.
    918  size_t jumpRelocationTableBytes() const;
    919  size_t dataRelocationTableBytes() const;
    920 
    921  // Size of the data table, in bytes.
    922  size_t bytesNeeded() const;
    923 
    924  // Write a blob of binary into the instruction stream *OR*
    925  // into a destination address. If dest is nullptr (the default), then the
    926  // instruction gets written into the instruction stream. If dest is not null
    927  // it is interpreted as a pointer to the location that we want the
    928  // instruction to be written.
    929  BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr);
    930  // A static variant for the cases where we don't want to have an assembler
    931  // object at all. Normally, you would use the dummy (nullptr) object.
    932  static void WriteInstStatic(uint32_t x, uint32_t* dest);
    933 
    934 public:
    935  BufferOffset haltingAlign(int alignment);
    936  BufferOffset nopAlign(int alignment);
    937  BufferOffset as_nop();
    938 
    939  // Branch and jump instructions
    940  BufferOffset as_bal(BOffImm16 off);
    941  BufferOffset as_b(BOffImm16 off);
    942 
    943  InstImm getBranchCode(JumpOrCall jumpOrCall);
    944  InstImm getBranchCode(Register s, Register t, Condition c);
    945  InstImm getBranchCode(Register s, Condition c);
    946  InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc);
    947 
    948  BufferOffset as_j(JOffImm26 off);
    949  BufferOffset as_jal(JOffImm26 off);
    950 
    951  BufferOffset as_jr(Register rs);
    952  BufferOffset as_jalr(Register rs);
    953 
    954  // Arithmetic instructions
    955  BufferOffset as_addu(Register rd, Register rs, Register rt);
    956  BufferOffset as_addiu(Register rd, Register rs, int32_t j);
    957  BufferOffset as_daddu(Register rd, Register rs, Register rt);
    958  BufferOffset as_daddiu(Register rd, Register rs, int32_t j);
    959  BufferOffset as_subu(Register rd, Register rs, Register rt);
    960  BufferOffset as_dsubu(Register rd, Register rs, Register rt);
    961  BufferOffset as_mult(Register rs, Register rt);
    962  BufferOffset as_multu(Register rs, Register rt);
    963  BufferOffset as_dmult(Register rs, Register rt);
    964  BufferOffset as_dmultu(Register rs, Register rt);
    965  BufferOffset as_div(Register rs, Register rt);
    966  BufferOffset as_divu(Register rs, Register rt);
    967  BufferOffset as_mul(Register rd, Register rs, Register rt);
    968  BufferOffset as_madd(Register rs, Register rt);
    969  BufferOffset as_maddu(Register rs, Register rt);
    970  BufferOffset as_ddiv(Register rs, Register rt);
    971  BufferOffset as_ddivu(Register rs, Register rt);
    972 
    973  BufferOffset as_muh(Register rd, Register rs, Register rt);
    974  BufferOffset as_muhu(Register rd, Register rs, Register rt);
    975  BufferOffset as_mulu(Register rd, Register rs, Register rt);
    976  BufferOffset as_dmuh(Register rd, Register rs, Register rt);
    977  BufferOffset as_dmuhu(Register rd, Register rs, Register rt);
    978  BufferOffset as_dmul(Register rd, Register rs, Register rt);
    979  BufferOffset as_dmulu(Register rd, Register rs, Register rt);
    980  BufferOffset as_div(Register rd, Register rs, Register rt);
    981  BufferOffset as_divu(Register rd, Register rs, Register rt);
    982  BufferOffset as_mod(Register rd, Register rs, Register rt);
    983  BufferOffset as_modu(Register rd, Register rs, Register rt);
    984  BufferOffset as_ddiv(Register rd, Register rs, Register rt);
    985  BufferOffset as_ddivu(Register rd, Register rs, Register rt);
    986  BufferOffset as_dmod(Register rd, Register rs, Register rt);
    987  BufferOffset as_dmodu(Register rd, Register rs, Register rt);
    988 
    989  // Logical instructions
    990  BufferOffset as_and(Register rd, Register rs, Register rt);
    991  BufferOffset as_or(Register rd, Register rs, Register rt);
    992  BufferOffset as_xor(Register rd, Register rs, Register rt);
    993  BufferOffset as_nor(Register rd, Register rs, Register rt);
    994 
    995  BufferOffset as_andi(Register rd, Register rs, int32_t j);
    996  BufferOffset as_ori(Register rd, Register rs, int32_t j);
    997  BufferOffset as_xori(Register rd, Register rs, int32_t j);
    998  BufferOffset as_lui(Register rd, int32_t j);
    999 
   1000  // Shift instructions
   1001  // as_sll(zero, zero, x) instructions are reserved as nop
   1002  BufferOffset as_sll(Register rd, Register rt, uint16_t sa);
   1003  BufferOffset as_dsll(Register rd, Register rt, uint16_t sa);
   1004  BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa);
   1005  BufferOffset as_sllv(Register rd, Register rt, Register rs);
   1006  BufferOffset as_dsllv(Register rd, Register rt, Register rs);
   1007  BufferOffset as_srl(Register rd, Register rt, uint16_t sa);
   1008  BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa);
   1009  BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa);
   1010  BufferOffset as_srlv(Register rd, Register rt, Register rs);
   1011  BufferOffset as_dsrlv(Register rd, Register rt, Register rs);
   1012  BufferOffset as_sra(Register rd, Register rt, uint16_t sa);
   1013  BufferOffset as_dsra(Register rd, Register rt, uint16_t sa);
   1014  BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa);
   1015  BufferOffset as_srav(Register rd, Register rt, Register rs);
   1016  BufferOffset as_rotr(Register rd, Register rt, uint16_t sa);
   1017  BufferOffset as_rotrv(Register rd, Register rt, Register rs);
   1018  BufferOffset as_dsrav(Register rd, Register rt, Register rs);
   1019  BufferOffset as_drotr(Register rd, Register rt, uint16_t sa);
   1020  BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa);
   1021  BufferOffset as_drotrv(Register rd, Register rt, Register rs);
   1022 
   1023  // Load and store instructions
   1024  BufferOffset as_lb(Register rd, Register rs, int16_t off);
   1025  BufferOffset as_lbu(Register rd, Register rs, int16_t off);
   1026  BufferOffset as_lh(Register rd, Register rs, int16_t off);
   1027  BufferOffset as_lhu(Register rd, Register rs, int16_t off);
   1028  BufferOffset as_lw(Register rd, Register rs, int16_t off);
   1029  BufferOffset as_lwu(Register rd, Register rs, int16_t off);
   1030  BufferOffset as_lwl(Register rd, Register rs, int16_t off);
   1031  BufferOffset as_lwr(Register rd, Register rs, int16_t off);
   1032  BufferOffset as_ll(Register rd, Register rs, int16_t off);
   1033  BufferOffset as_lld(Register rd, Register rs, int16_t off);
   1034  BufferOffset as_ld(Register rd, Register rs, int16_t off);
   1035  BufferOffset as_ldl(Register rd, Register rs, int16_t off);
   1036  BufferOffset as_ldr(Register rd, Register rs, int16_t off);
   1037  BufferOffset as_sb(Register rd, Register rs, int16_t off);
   1038  BufferOffset as_sh(Register rd, Register rs, int16_t off);
   1039  BufferOffset as_sw(Register rd, Register rs, int16_t off);
   1040  BufferOffset as_swl(Register rd, Register rs, int16_t off);
   1041  BufferOffset as_swr(Register rd, Register rs, int16_t off);
   1042  BufferOffset as_sc(Register rd, Register rs, int16_t off);
   1043  BufferOffset as_scd(Register rd, Register rs, int16_t off);
   1044  BufferOffset as_sd(Register rd, Register rs, int16_t off);
   1045  BufferOffset as_sdl(Register rd, Register rs, int16_t off);
   1046  BufferOffset as_sdr(Register rd, Register rs, int16_t off);
   1047 
   1048  // Loongson-specific load and store instructions
   1049  BufferOffset as_gslbx(Register rd, Register rs, Register ri, int16_t off);
   1050  BufferOffset as_gssbx(Register rd, Register rs, Register ri, int16_t off);
   1051  BufferOffset as_gslhx(Register rd, Register rs, Register ri, int16_t off);
   1052  BufferOffset as_gsshx(Register rd, Register rs, Register ri, int16_t off);
   1053  BufferOffset as_gslwx(Register rd, Register rs, Register ri, int16_t off);
   1054  BufferOffset as_gsswx(Register rd, Register rs, Register ri, int16_t off);
   1055  BufferOffset as_gsldx(Register rd, Register rs, Register ri, int16_t off);
   1056  BufferOffset as_gssdx(Register rd, Register rs, Register ri, int16_t off);
   1057  BufferOffset as_gslq(Register rh, Register rl, Register rs, int16_t off);
   1058  BufferOffset as_gssq(Register rh, Register rl, Register rs, int16_t off);
   1059 
   1060  // Move from HI/LO register.
   1061  BufferOffset as_mfhi(Register rd);
   1062  BufferOffset as_mflo(Register rd);
   1063 
   1064  // Set on less than.
   1065  BufferOffset as_slt(Register rd, Register rs, Register rt);
   1066  BufferOffset as_sltu(Register rd, Register rs, Register rt);
   1067  BufferOffset as_slti(Register rd, Register rs, int32_t j);
   1068  BufferOffset as_sltiu(Register rd, Register rs, uint32_t j);
   1069 
   1070  // Conditional move.
   1071  BufferOffset as_movz(Register rd, Register rs, Register rt);
   1072  BufferOffset as_movn(Register rd, Register rs, Register rt);
   1073  BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0);
   1074  BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0);
   1075  BufferOffset as_seleqz(Register rd, Register rs, Register rt);
   1076  BufferOffset as_selnez(Register rd, Register rs, Register rt);
   1077 
   1078  // Bit twiddling.
   1079  BufferOffset as_clz(Register rd, Register rs);
   1080  BufferOffset as_dclz(Register rd, Register rs);
   1081  BufferOffset as_wsbh(Register rd, Register rt);
   1082  BufferOffset as_dsbh(Register rd, Register rt);
   1083  BufferOffset as_dshd(Register rd, Register rt);
   1084  BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size);
   1085  BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size);
   1086  BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size);
   1087  BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size);
   1088  BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size);
   1089  BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size);
   1090  BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size);
   1091  BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size);
   1092 
   1093  // Sign extend
   1094  BufferOffset as_seb(Register rd, Register rt);
   1095  BufferOffset as_seh(Register rd, Register rt);
   1096 
   1097  // FP instructions
   1098 
   1099  BufferOffset as_ldc1(FloatRegister ft, Register base, int32_t off);
   1100  BufferOffset as_sdc1(FloatRegister ft, Register base, int32_t off);
   1101 
   1102  BufferOffset as_lwc1(FloatRegister ft, Register base, int32_t off);
   1103  BufferOffset as_swc1(FloatRegister ft, Register base, int32_t off);
   1104 
   1105  // Loongson-specific FP load and store instructions
   1106  BufferOffset as_gsldl(FloatRegister fd, Register base, int32_t off);
   1107  BufferOffset as_gsldr(FloatRegister fd, Register base, int32_t off);
   1108  BufferOffset as_gssdl(FloatRegister fd, Register base, int32_t off);
   1109  BufferOffset as_gssdr(FloatRegister fd, Register base, int32_t off);
   1110  BufferOffset as_gslsl(FloatRegister fd, Register base, int32_t off);
   1111  BufferOffset as_gslsr(FloatRegister fd, Register base, int32_t off);
   1112  BufferOffset as_gsssl(FloatRegister fd, Register base, int32_t off);
   1113  BufferOffset as_gsssr(FloatRegister fd, Register base, int32_t off);
   1114  BufferOffset as_gslsx(FloatRegister fd, Register rs, Register ri,
   1115                        int16_t off);
   1116  BufferOffset as_gsssx(FloatRegister fd, Register rs, Register ri,
   1117                        int16_t off);
   1118  BufferOffset as_gsldx(FloatRegister fd, Register rs, Register ri,
   1119                        int16_t off);
   1120  BufferOffset as_gssdx(FloatRegister fd, Register rs, Register ri,
   1121                        int16_t off);
   1122  BufferOffset as_gslq(FloatRegister rh, FloatRegister rl, Register rs,
   1123                       int16_t off);
   1124  BufferOffset as_gssq(FloatRegister rh, FloatRegister rl, Register rs,
   1125                       int16_t off);
   1126 
   1127  BufferOffset as_movs(FloatRegister fd, FloatRegister fs);
   1128  BufferOffset as_movd(FloatRegister fd, FloatRegister fs);
   1129 
   1130  BufferOffset as_ctc1(Register rt, FPControl fc);
   1131  BufferOffset as_cfc1(Register rt, FPControl fc);
   1132 
   1133  BufferOffset as_mtc1(Register rt, FloatRegister fs);
   1134  BufferOffset as_mfc1(Register rt, FloatRegister fs);
   1135 
   1136  BufferOffset as_mthc1(Register rt, FloatRegister fs);
   1137  BufferOffset as_mfhc1(Register rt, FloatRegister fs);
   1138  BufferOffset as_dmtc1(Register rt, FloatRegister fs);
   1139  BufferOffset as_dmfc1(Register rt, FloatRegister fs);
   1140 
   1141 public:
   1142  // FP convert instructions
   1143  BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
   1144  BufferOffset as_ceills(FloatRegister fd, FloatRegister fs);
   1145  BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);
   1146  BufferOffset as_floorls(FloatRegister fd, FloatRegister fs);
   1147  BufferOffset as_roundws(FloatRegister fd, FloatRegister fs);
   1148  BufferOffset as_roundls(FloatRegister fd, FloatRegister fs);
   1149  BufferOffset as_truncws(FloatRegister fd, FloatRegister fs);
   1150  BufferOffset as_truncls(FloatRegister fd, FloatRegister fs);
   1151 
   1152  BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs);
   1153  BufferOffset as_ceilld(FloatRegister fd, FloatRegister fs);
   1154  BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs);
   1155  BufferOffset as_floorld(FloatRegister fd, FloatRegister fs);
   1156  BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs);
   1157  BufferOffset as_roundld(FloatRegister fd, FloatRegister fs);
   1158  BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs);
   1159  BufferOffset as_truncld(FloatRegister fd, FloatRegister fs);
   1160 
   1161  BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs);
   1162  BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs);
   1163  BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs);
   1164  BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs);
   1165  BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs);
   1166  BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs);
   1167  BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs);
   1168  BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs);
   1169  BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs);
   1170  BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs);
   1171 
   1172  // FP arithmetic instructions
   1173  BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1174  BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1175  BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1176  BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1177 
   1178  BufferOffset as_abss(FloatRegister fd, FloatRegister fs);
   1179  BufferOffset as_absd(FloatRegister fd, FloatRegister fs);
   1180  BufferOffset as_negs(FloatRegister fd, FloatRegister fs);
   1181  BufferOffset as_negd(FloatRegister fd, FloatRegister fs);
   1182 
   1183  BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1184  BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1185  BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1186  BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
   1187  BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs);
   1188  BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs);
   1189 
   1190  BufferOffset as_max(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1191                      FloatRegister ft);
   1192  BufferOffset as_min(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1193                      FloatRegister ft);
   1194 
   1195  // FP compare instructions
   1196  BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1197                     FPConditionBit fcc = FCC0);
   1198  BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1199                      FPConditionBit fcc = FCC0);
   1200  BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1201                      FPConditionBit fcc = FCC0);
   1202  BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1203                       FPConditionBit fcc = FCC0);
   1204  BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1205                       FPConditionBit fcc = FCC0);
   1206  BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1207                       FPConditionBit fcc = FCC0);
   1208  BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1209                       FPConditionBit fcc = FCC0);
   1210  BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
   1211                       FPConditionBit fcc = FCC0);
   1212 
   1213  // FP conditional move.
   1214  BufferOffset as_movt(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1215                       FPConditionBit fcc = FCC0);
   1216  BufferOffset as_movf(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1217                       FPConditionBit fcc = FCC0);
   1218  BufferOffset as_movz(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1219                       Register rt);
   1220  BufferOffset as_movn(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
   1221                       Register rt);
   1222 
   1223  // Conditional trap operations
   1224  BufferOffset as_tge(Register rs, Register rt, uint32_t code = 0);
   1225  BufferOffset as_tgeu(Register rs, Register rt, uint32_t code = 0);
   1226  BufferOffset as_tlt(Register rs, Register rt, uint32_t code = 0);
   1227  BufferOffset as_tltu(Register rs, Register rt, uint32_t code = 0);
   1228  BufferOffset as_teq(Register rs, Register rt, uint32_t code = 0);
   1229  BufferOffset as_tne(Register rs, Register rt, uint32_t code = 0);
   1230 
   1231  // label operations
   1232  void bind(Label* label, BufferOffset boff = BufferOffset());
   1233  virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
   1234  void bind(CodeLabel* label) { label->target()->bind(currentOffset()); }
   1235  uint32_t currentOffset() { return nextOffset().getOffset(); }
   1236  void retarget(Label* label, Label* target);
   1237 
   1238  void call(Label* label);
   1239  void call(void* target);
   1240 
   1241  void as_break(uint32_t code);
   1242  void as_sync(uint32_t stype = 0);
   1243 
   1244 public:
   1245  static bool SupportsFloatingPoint() {
   1246 #if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \
   1247    defined(JS_SIMULATOR_MIPS64)
   1248    return true;
   1249 #else
   1250    return false;
   1251 #endif
   1252  }
   1253  static bool SupportsUnalignedAccesses() { return true; }
   1254  static bool SupportsFastUnalignedFPAccesses() { return false; }
   1255  static bool SupportsFloat64To16() { return false; }
   1256  static bool SupportsFloat32To16() { return false; }
   1257 
   1258  static bool HasRoundInstruction(RoundingMode mode) { return false; }
   1259 
   1260 protected:
   1261  InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
   1262  void addPendingJump(BufferOffset src, ImmPtr target, RelocationKind kind) {
   1263    enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
   1264    if (kind == RelocationKind::JITCODE) {
   1265      jumpRelocations_.writeUnsigned(src.getOffset());
   1266    }
   1267  }
   1268 
   1269  void addLongJump(BufferOffset src, BufferOffset dst) {
   1270    CodeLabel cl;
   1271    cl.patchAt()->bind(src.getOffset());
   1272    cl.target()->bind(dst.getOffset());
   1273    cl.setLinkMode(CodeLabel::JumpImmediate);
   1274    addCodeLabel(std::move(cl));
   1275  }
   1276 
   1277 public:
   1278  void flushBuffer() {}
   1279 
   1280  void comment(const char* msg) { spew("; %s", msg); }
   1281 
   1282  static uint32_t NopSize() { return 4; }
   1283 
   1284  static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
   1285 
   1286  static uint32_t AlignDoubleArg(uint32_t offset) {
   1287    return (offset + 1U) & ~1U;
   1288  }
   1289 
   1290  static uint8_t* NextInstruction(uint8_t* instruction,
   1291                                  uint32_t* count = nullptr);
   1292 
   1293  static void ToggleToJmp(CodeLocationLabel inst_);
   1294  static void ToggleToCmp(CodeLocationLabel inst_);
   1295 
   1296  static void UpdateLuiOriValue(Instruction* inst0, Instruction* inst1,
   1297                                uint32_t value);
   1298 
   1299  void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
   1300                                   const Disassembler::HeapAccess& heapAccess) {
   1301    // Implement this if we implement a disassembler.
   1302  }
   1303 
   1304 private:
   1305  GeneralRegisterSet scratch_register_list_;
   1306 
   1307 public:
   1308  GeneralRegisterSet* GetScratchRegisterList() {
   1309    return &scratch_register_list_;
   1310  }
   1311 };  // AssemblerMIPSShared
   1312 
   1313 // sll zero, zero, 0
   1314 const uint32_t NopInst = 0x00000000;
   1315 
   1316 // An Instruction is a structure for both encoding and decoding any and all
   1317 // MIPS instructions.
   1318 class Instruction {
   1319 protected:
   1320  uint32_t data;
   1321 
   1322  // Standard constructor
   1323  explicit Instruction(uint32_t data_) : data(data_) {}
   1324 
   1325  // You should never create an instruction directly.  You should create a
   1326  // more specific instruction which will eventually call one of these
   1327  // constructors for you.
   1328 public:
   1329  uint32_t encode() const { return data; }
   1330 
   1331  void makeNop() { data = NopInst; }
   1332 
   1333  void setData(uint32_t data) { this->data = data; }
   1334 
   1335  const Instruction& operator=(const Instruction& src) {
   1336    data = src.data;
   1337    return *this;
   1338  }
   1339 
   1340  // Extract the one particular bit.
   1341  uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; }
   1342  // Extract a bit field out of the instruction
   1343  uint32_t extractBitField(uint32_t hi, uint32_t lo) {
   1344    return (encode() >> lo) & ((2 << (hi - lo)) - 1);
   1345  }
   1346  // Since all MIPS instructions have opcode, the opcode
   1347  // extractor resides in the base class.
   1348  uint32_t extractOpcode() {
   1349    return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
   1350  }
   1351  // Return the fields at their original place in the instruction encoding.
   1352  OpcodeField OpcodeFieldRaw() const {
   1353    return static_cast<OpcodeField>(encode() & OpcodeMask);
   1354  }
   1355 
   1356  // Get the next instruction in the instruction stream.
   1357  // This does neat things like ignoreconstant pools and their guards.
   1358  Instruction* next();
   1359 
   1360  // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
   1361  // an instruction.  raw() just coerces this into a pointer to a uint32_t
   1362  const uint32_t* raw() const { return &data; }
   1363  uint32_t size() const { return 4; }
   1364 };  // Instruction
   1365 
   1366 // make sure that it is the right size
   1367 static_assert(sizeof(Instruction) == 4,
   1368              "Size of Instruction class has to be 4 bytes.");
   1369 
   1370 class InstNOP : public Instruction {
   1371 public:
   1372  InstNOP() : Instruction(NopInst) {}
   1373 };
   1374 
   1375 // Class for register type instructions.
   1376 class InstReg : public Instruction {
   1377 public:
   1378  InstReg(OpcodeField op, Register rd, FunctionField ff)
   1379      : Instruction(static_cast<uint32_t>(op) | RD(rd) |
   1380                    static_cast<uint32_t>(ff)) {}
   1381  InstReg(OpcodeField op, Register rs, Register rt, FunctionField ff)
   1382      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) |
   1383                    static_cast<uint32_t>(ff)) {}
   1384  InstReg(OpcodeField op, Register rs, Register rt, Register rd,
   1385          FunctionField ff)
   1386      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) |
   1387                    static_cast<uint32_t>(ff)) {}
   1388  InstReg(OpcodeField op, Register rs, Register rt, Register rd, uint32_t sa,
   1389          FunctionField ff)
   1390      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) |
   1391                    SA(sa) | static_cast<uint32_t>(ff)) {}
   1392  InstReg(OpcodeField op, RSField rs, Register rt, Register rd, uint32_t sa,
   1393          FunctionField ff)
   1394      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1395                    RT(rt) | RD(rd) | SA(sa) | static_cast<uint32_t>(ff)) {}
   1396  InstReg(OpcodeField op, Register rs, RTField rt, Register rd, uint32_t sa,
   1397          FunctionField ff)
   1398      : Instruction(static_cast<uint32_t>(op) | RS(rs) |
   1399                    static_cast<uint32_t>(rt) | RD(rd) | SA(sa) |
   1400                    static_cast<uint32_t>(ff)) {}
   1401  InstReg(OpcodeField op, Register rs, uint32_t cc, Register rd, uint32_t sa,
   1402          FunctionField ff)
   1403      : Instruction(static_cast<uint32_t>(op) | RS(rs) | cc | RD(rd) | SA(sa) |
   1404                    static_cast<uint32_t>(ff)) {}
   1405  InstReg(OpcodeField op, uint32_t code, FunctionField ff)
   1406      : Instruction(static_cast<uint32_t>(op) | code |
   1407                    static_cast<uint32_t>(ff)) {}
   1408  // for float point
   1409  InstReg(OpcodeField op, RSField rs, Register rt, uint32_t fs)
   1410      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1411                    RT(rt) | FS(fs)) {}
   1412  InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd)
   1413      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1414                    RT(rt) | RD(rd)) {}
   1415  InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd,
   1416          uint32_t sa, FunctionField ff)
   1417      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1418                    RT(rt) | RD(rd) | SA(sa) | static_cast<uint32_t>(ff)) {}
   1419  InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister fs,
   1420          FloatRegister fd, FunctionField ff)
   1421      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1422                    RT(rt) | RD(fs) | SA(fd) | static_cast<uint32_t>(ff)) {}
   1423  InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fs,
   1424          FloatRegister fd, FunctionField ff)
   1425      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1426                    RT(ft) | RD(fs) | SA(fd) | static_cast<uint32_t>(ff)) {}
   1427  InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fd,
   1428          uint32_t sa, FunctionField ff)
   1429      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) |
   1430                    RT(ft) | RD(fd) | SA(sa) | static_cast<uint32_t>(ff)) {}
   1431 
   1432  uint32_t extractRS() {
   1433    return extractBitField(RSShift + RSBits - 1, RSShift);
   1434  }
   1435  uint32_t extractRT() {
   1436    return extractBitField(RTShift + RTBits - 1, RTShift);
   1437  }
   1438  uint32_t extractRD() {
   1439    return extractBitField(RDShift + RDBits - 1, RDShift);
   1440  }
   1441  uint32_t extractSA() {
   1442    return extractBitField(SAShift + SABits - 1, SAShift);
   1443  }
   1444  uint32_t extractFunctionField() {
   1445    return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift);
   1446  }
   1447 };
   1448 
   1449 // Class for branch, load and store instructions with immediate offset.
   1450 class InstImm : public Instruction {
   1451 public:
   1452  void extractImm16(BOffImm16* dest);
   1453 
   1454  InstImm(OpcodeField op, Register rs, Register rt, BOffImm16 off)
   1455      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) |
   1456                    off.encode()) {}
   1457  InstImm(OpcodeField op, Register rs, RTField rt, BOffImm16 off)
   1458      : Instruction(static_cast<uint32_t>(op) | RS(rs) |
   1459                    static_cast<uint32_t>(rt) | off.encode()) {}
   1460  InstImm(OpcodeField op, RSField rs, uint32_t cc, BOffImm16 off)
   1461      : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | cc |
   1462                    off.encode()) {}
   1463  InstImm(OpcodeField op, Register rs, Register rt, Imm16 off)
   1464      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) |
   1465                    off.encode()) {}
   1466  MOZ_IMPLICIT InstImm(uint32_t raw) : Instruction(raw) {}
   1467  // For floating-point loads and stores.
   1468  InstImm(OpcodeField op, Register rs, FloatRegister rt, Imm16 off)
   1469      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) |
   1470                    off.encode()) {}
   1471 
   1472  uint32_t extractOpcode() {
   1473    return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
   1474  }
   1475  void setOpcode(OpcodeField op) { data = (data & ~OpcodeMask) | op; }
   1476  uint32_t extractRS() {
   1477    return extractBitField(RSShift + RSBits - 1, RSShift);
   1478  }
   1479  uint32_t extractRT() {
   1480    return extractBitField(RTShift + RTBits - 1, RTShift);
   1481  }
   1482  void setRT(RTField rt) { data = (data & ~RTMask) | rt; }
   1483  uint32_t extractImm16Value() {
   1484    return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift);
   1485  }
   1486  void setBOffImm16(BOffImm16 off) {
   1487    // Reset immediate field and replace it
   1488    data = (data & ~Imm16Mask) | off.encode();
   1489  }
   1490  void setImm16(Imm16 off) {
   1491    // Reset immediate field and replace it
   1492    data = (data & ~Imm16Mask) | off.encode();
   1493  }
   1494 };
   1495 
   1496 // Class for Jump type instructions.
   1497 class InstJump : public Instruction {
   1498 public:
   1499  InstJump(OpcodeField op, JOffImm26 off)
   1500      : Instruction(static_cast<uint32_t>(op) | off.encode()) {}
   1501 
   1502  uint32_t extractImm26Value() {
   1503    return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift);
   1504  }
   1505 };
   1506 
   1507 // Class for Loongson-specific instructions
   1508 class InstGS : public Instruction {
   1509 public:
   1510  // For indexed loads and stores.
   1511  InstGS(OpcodeField op, Register rs, Register rt, Register rd, Imm8 off,
   1512         FunctionField ff)
   1513      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) |
   1514                    off.encode(3) | static_cast<uint32_t>(ff)) {}
   1515  InstGS(OpcodeField op, Register rs, FloatRegister rt, Register rd, Imm8 off,
   1516         FunctionField ff)
   1517      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) |
   1518                    off.encode(3) | static_cast<uint32_t>(ff)) {}
   1519  // For quad-word loads and stores.
   1520  InstGS(OpcodeField op, Register rs, Register rt, Register rz, GSImm13 off,
   1521         FunctionField ff)
   1522      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RZ(rz) |
   1523                    off.encode(6) | static_cast<uint32_t>(ff)) {}
   1524  InstGS(OpcodeField op, Register rs, FloatRegister rt, FloatRegister rz,
   1525         GSImm13 off, FunctionField ff)
   1526      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RZ(rz) |
   1527                    off.encode(6) | static_cast<uint32_t>(ff)) {}
   1528  explicit InstGS(uint32_t raw) : Instruction(raw) {}
   1529  // For floating-point unaligned loads and stores.
   1530  InstGS(OpcodeField op, Register rs, FloatRegister rt, Imm8 off,
   1531         FunctionField ff)
   1532      : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) |
   1533                    off.encode(6) | ff) {}
   1534 };
   1535 
   1536 inline bool IsUnaligned(const wasm::MemoryAccessDesc& access) {
   1537  if (!access.align()) {
   1538    return false;
   1539  }
   1540 
   1541  return access.align() < access.byteSize();
   1542 }
   1543 
   1544 }  // namespace jit
   1545 }  // namespace js
   1546 
   1547 #endif /* jit_mips_shared_Assembler_mips_shared_h */