tor-browser

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

Assembler-mips-shared.cpp (82144B)


      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 #include "jit/mips-shared/Assembler-mips-shared.h"
      8 
      9 #include "mozilla/DebugOnly.h"
     10 
     11 #include "gc/Marking.h"
     12 #include "jit/ExecutableAllocator.h"
     13 #include "vm/Realm.h"
     14 
     15 using mozilla::DebugOnly;
     16 
     17 using namespace js;
     18 using namespace js::jit;
     19 
     20 // Encode a standard register when it is being used as rd, the rs, and
     21 // an extra register(rt). These should never be called with an InvalidReg.
     22 uint32_t js::jit::RS(Register r) {
     23  MOZ_ASSERT((r.code() & ~RegMask) == 0);
     24  return r.code() << RSShift;
     25 }
     26 
     27 uint32_t js::jit::RT(Register r) {
     28  MOZ_ASSERT((r.code() & ~RegMask) == 0);
     29  return r.code() << RTShift;
     30 }
     31 
     32 uint32_t js::jit::RD(Register r) {
     33  MOZ_ASSERT((r.code() & ~RegMask) == 0);
     34  return r.code() << RDShift;
     35 }
     36 
     37 uint32_t js::jit::RZ(Register r) {
     38  MOZ_ASSERT((r.code() & ~RegMask) == 0);
     39  return r.code() << RZShift;
     40 }
     41 
     42 uint32_t js::jit::SA(uint32_t value) {
     43  MOZ_ASSERT(value < 32);
     44  return value << SAShift;
     45 }
     46 
     47 uint32_t js::jit::FS(uint32_t value) {
     48  MOZ_ASSERT(value < 32);
     49  return value << FSShift;
     50 }
     51 
     52 Register js::jit::toRS(Instruction& i) {
     53  return Register::FromCode((i.encode() & RSMask) >> RSShift);
     54 }
     55 
     56 Register js::jit::toRT(Instruction& i) {
     57  return Register::FromCode((i.encode() & RTMask) >> RTShift);
     58 }
     59 
     60 Register js::jit::toRD(Instruction& i) {
     61  return Register::FromCode((i.encode() & RDMask) >> RDShift);
     62 }
     63 
     64 Register js::jit::toR(Instruction& i) {
     65  return Register::FromCode(i.encode() & RegMask);
     66 }
     67 
     68 void InstImm::extractImm16(BOffImm16* dest) { *dest = BOffImm16(*this); }
     69 
     70 void AssemblerMIPSShared::finish() {
     71  MOZ_ASSERT(!isFinished);
     72  isFinished = true;
     73 }
     74 
     75 bool AssemblerMIPSShared::appendRawCode(const uint8_t* code, size_t numBytes) {
     76  return m_buffer.appendRawCode(code, numBytes);
     77 }
     78 
     79 bool AssemblerMIPSShared::reserve(size_t size) {
     80  // This buffer uses fixed-size chunks so there's no point in reserving
     81  // now vs. on-demand.
     82  return !oom();
     83 }
     84 
     85 bool AssemblerMIPSShared::swapBuffer(wasm::Bytes& bytes) {
     86  // For now, specialize to the one use case. As long as wasm::Bytes is a
     87  // Vector, not a linked-list of chunks, there's not much we can do other
     88  // than copy.
     89  MOZ_ASSERT(bytes.empty());
     90  if (!bytes.resize(bytesNeeded())) {
     91    return false;
     92  }
     93  m_buffer.executableCopy(bytes.begin());
     94  return true;
     95 }
     96 
     97 void AssemblerMIPSShared::copyJumpRelocationTable(uint8_t* dest) {
     98  if (jumpRelocations_.length()) {
     99    memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
    100  }
    101 }
    102 
    103 void AssemblerMIPSShared::copyDataRelocationTable(uint8_t* dest) {
    104  if (dataRelocations_.length()) {
    105    memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
    106  }
    107 }
    108 
    109 AssemblerMIPSShared::Condition AssemblerMIPSShared::InvertCondition(
    110    Condition cond) {
    111  switch (cond) {
    112    case Equal:
    113      return NotEqual;
    114    case NotEqual:
    115      return Equal;
    116    case Zero:
    117      return NonZero;
    118    case NonZero:
    119      return Zero;
    120    case LessThan:
    121      return GreaterThanOrEqual;
    122    case LessThanOrEqual:
    123      return GreaterThan;
    124    case GreaterThan:
    125      return LessThanOrEqual;
    126    case GreaterThanOrEqual:
    127      return LessThan;
    128    case Above:
    129      return BelowOrEqual;
    130    case AboveOrEqual:
    131      return Below;
    132    case Below:
    133      return AboveOrEqual;
    134    case BelowOrEqual:
    135      return Above;
    136    case Signed:
    137      return NotSigned;
    138    case NotSigned:
    139      return Signed;
    140    default:
    141      MOZ_CRASH("unexpected condition");
    142  }
    143 }
    144 
    145 AssemblerMIPSShared::DoubleCondition AssemblerMIPSShared::InvertCondition(
    146    DoubleCondition cond) {
    147  switch (cond) {
    148    case DoubleOrdered:
    149      return DoubleUnordered;
    150    case DoubleEqual:
    151      return DoubleNotEqualOrUnordered;
    152    case DoubleNotEqual:
    153      return DoubleEqualOrUnordered;
    154    case DoubleGreaterThan:
    155      return DoubleLessThanOrEqualOrUnordered;
    156    case DoubleGreaterThanOrEqual:
    157      return DoubleLessThanOrUnordered;
    158    case DoubleLessThan:
    159      return DoubleGreaterThanOrEqualOrUnordered;
    160    case DoubleLessThanOrEqual:
    161      return DoubleGreaterThanOrUnordered;
    162    case DoubleUnordered:
    163      return DoubleOrdered;
    164    case DoubleEqualOrUnordered:
    165      return DoubleNotEqual;
    166    case DoubleNotEqualOrUnordered:
    167      return DoubleEqual;
    168    case DoubleGreaterThanOrUnordered:
    169      return DoubleLessThanOrEqual;
    170    case DoubleGreaterThanOrEqualOrUnordered:
    171      return DoubleLessThan;
    172    case DoubleLessThanOrUnordered:
    173      return DoubleGreaterThanOrEqual;
    174    case DoubleLessThanOrEqualOrUnordered:
    175      return DoubleGreaterThan;
    176    default:
    177      MOZ_CRASH("unexpected condition");
    178  }
    179 }
    180 
    181 BOffImm16::BOffImm16(InstImm inst) : data(inst.encode() & Imm16Mask) {}
    182 
    183 Instruction* BOffImm16::getDest(Instruction* src) const {
    184  return &src[(((int32_t)data << 16) >> 16) + 1];
    185 }
    186 
    187 bool AssemblerMIPSShared::oom() const {
    188  return AssemblerShared::oom() || m_buffer.oom() || jumpRelocations_.oom() ||
    189         dataRelocations_.oom();
    190 }
    191 
    192 // Size of the instruction stream, in bytes.
    193 size_t AssemblerMIPSShared::size() const { return m_buffer.size(); }
    194 
    195 // Size of the relocation table, in bytes.
    196 size_t AssemblerMIPSShared::jumpRelocationTableBytes() const {
    197  return jumpRelocations_.length();
    198 }
    199 
    200 size_t AssemblerMIPSShared::dataRelocationTableBytes() const {
    201  return dataRelocations_.length();
    202 }
    203 
    204 // Size of the data table, in bytes.
    205 size_t AssemblerMIPSShared::bytesNeeded() const {
    206  return size() + jumpRelocationTableBytes() + dataRelocationTableBytes();
    207 }
    208 
    209 // write a blob of binary into the instruction stream
    210 BufferOffset AssemblerMIPSShared::writeInst(uint32_t x, uint32_t* dest) {
    211  MOZ_ASSERT(hasCreator());
    212  if (dest == nullptr) {
    213    return m_buffer.putInt(x);
    214  }
    215 
    216  WriteInstStatic(x, dest);
    217  return BufferOffset();
    218 }
    219 
    220 void AssemblerMIPSShared::WriteInstStatic(uint32_t x, uint32_t* dest) {
    221  MOZ_ASSERT(dest != nullptr);
    222  *dest = x;
    223 }
    224 
    225 BufferOffset AssemblerMIPSShared::haltingAlign(int alignment) {
    226  // TODO: Implement a proper halting align.
    227  return nopAlign(alignment);
    228 }
    229 
    230 BufferOffset AssemblerMIPSShared::nopAlign(int alignment) {
    231  BufferOffset ret;
    232  MOZ_ASSERT(m_buffer.isAligned(4));
    233  if (alignment == 8) {
    234    if (!m_buffer.isAligned(alignment)) {
    235      BufferOffset tmp = as_nop();
    236      if (!ret.assigned()) {
    237        ret = tmp;
    238      }
    239    }
    240  } else {
    241    MOZ_ASSERT((alignment & (alignment - 1)) == 0);
    242    while (size() & (alignment - 1)) {
    243      BufferOffset tmp = as_nop();
    244      if (!ret.assigned()) {
    245        ret = tmp;
    246      }
    247    }
    248  }
    249  return ret;
    250 }
    251 
    252 BufferOffset AssemblerMIPSShared::as_nop() {
    253  spew("nop");
    254  return writeInst(static_cast<uint32_t>(op_special) | ff_sll);
    255 }
    256 
    257 // Logical operations.
    258 BufferOffset AssemblerMIPSShared::as_and(Register rd, Register rs,
    259                                         Register rt) {
    260  spew("and    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    261  return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode());
    262 }
    263 
    264 BufferOffset AssemblerMIPSShared::as_or(Register rd, Register rs, Register rt) {
    265  spew("or     %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    266  return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode());
    267 }
    268 
    269 BufferOffset AssemblerMIPSShared::as_xor(Register rd, Register rs,
    270                                         Register rt) {
    271  spew("xor    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    272  return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode());
    273 }
    274 
    275 BufferOffset AssemblerMIPSShared::as_nor(Register rd, Register rs,
    276                                         Register rt) {
    277  spew("nor    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    278  return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode());
    279 }
    280 
    281 BufferOffset AssemblerMIPSShared::as_andi(Register rd, Register rs, int32_t j) {
    282  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
    283  spew("andi   %3s,%3s,0x%x", rd.name(), rs.name(), j);
    284  return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode());
    285 }
    286 
    287 BufferOffset AssemblerMIPSShared::as_ori(Register rd, Register rs, int32_t j) {
    288  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
    289  spew("ori    %3s,%3s,0x%x", rd.name(), rs.name(), j);
    290  return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode());
    291 }
    292 
    293 BufferOffset AssemblerMIPSShared::as_xori(Register rd, Register rs, int32_t j) {
    294  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
    295  spew("xori   %3s,%3s,0x%x", rd.name(), rs.name(), j);
    296  return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode());
    297 }
    298 
    299 BufferOffset AssemblerMIPSShared::as_lui(Register rd, int32_t j) {
    300  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
    301  spew("lui    %3s,0x%x", rd.name(), j);
    302  return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode());
    303 }
    304 
    305 // Branch and jump instructions
    306 BufferOffset AssemblerMIPSShared::as_bal(BOffImm16 off) {
    307  spew("bal    %d", off.decode());
    308  BufferOffset bo =
    309      writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode());
    310  return bo;
    311 }
    312 
    313 BufferOffset AssemblerMIPSShared::as_b(BOffImm16 off) {
    314  spew("b      %d", off.decode());
    315  BufferOffset bo = writeInst(InstImm(op_beq, zero, zero, off).encode());
    316  return bo;
    317 }
    318 
    319 InstImm AssemblerMIPSShared::getBranchCode(JumpOrCall jumpOrCall) {
    320  if (jumpOrCall == BranchIsCall) {
    321    return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
    322  }
    323 
    324  return InstImm(op_beq, zero, zero, BOffImm16(0));
    325 }
    326 
    327 InstImm AssemblerMIPSShared::getBranchCode(Register s, Register t,
    328                                           Condition c) {
    329  MOZ_ASSERT(c == AssemblerMIPSShared::Equal ||
    330             c == AssemblerMIPSShared::NotEqual);
    331  return InstImm(c == AssemblerMIPSShared::Equal ? op_beq : op_bne, s, t,
    332                 BOffImm16(0));
    333 }
    334 
    335 InstImm AssemblerMIPSShared::getBranchCode(Register s, Condition c) {
    336  switch (c) {
    337    case AssemblerMIPSShared::Equal:
    338    case AssemblerMIPSShared::Zero:
    339    case AssemblerMIPSShared::BelowOrEqual:
    340      return InstImm(op_beq, s, zero, BOffImm16(0));
    341    case AssemblerMIPSShared::NotEqual:
    342    case AssemblerMIPSShared::NonZero:
    343    case AssemblerMIPSShared::Above:
    344      return InstImm(op_bne, s, zero, BOffImm16(0));
    345    case AssemblerMIPSShared::GreaterThan:
    346      return InstImm(op_bgtz, s, zero, BOffImm16(0));
    347    case AssemblerMIPSShared::GreaterThanOrEqual:
    348    case AssemblerMIPSShared::NotSigned:
    349      return InstImm(op_regimm, s, rt_bgez, BOffImm16(0));
    350    case AssemblerMIPSShared::LessThan:
    351    case AssemblerMIPSShared::Signed:
    352      return InstImm(op_regimm, s, rt_bltz, BOffImm16(0));
    353    case AssemblerMIPSShared::LessThanOrEqual:
    354      return InstImm(op_blez, s, zero, BOffImm16(0));
    355    default:
    356      MOZ_CRASH("Condition not supported.");
    357  }
    358 }
    359 
    360 InstImm AssemblerMIPSShared::getBranchCode(FloatTestKind testKind,
    361                                           FPConditionBit fcc) {
    362  MOZ_ASSERT(!(fcc && FccMask));
    363 #ifdef MIPSR6
    364  RSField rsField = ((testKind == TestForTrue ? rs_t : rs_f));
    365 
    366  return InstImm(op_cop1, rsField, FloatRegisters::f24 << 16, BOffImm16(0));
    367 #else
    368  uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift))
    369                     << RTShift;
    370 
    371  return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0));
    372 #endif
    373 }
    374 
    375 BufferOffset AssemblerMIPSShared::as_j(JOffImm26 off) {
    376  spew("j      0x%x", off.decode());
    377  BufferOffset bo = writeInst(InstJump(op_j, off).encode());
    378  return bo;
    379 }
    380 BufferOffset AssemblerMIPSShared::as_jal(JOffImm26 off) {
    381  spew("jal    0x%x", off.decode());
    382  BufferOffset bo = writeInst(InstJump(op_jal, off).encode());
    383  return bo;
    384 }
    385 
    386 BufferOffset AssemblerMIPSShared::as_jr(Register rs) {
    387  spew("jr     %3s", rs.name());
    388 #ifdef MIPSR6
    389  BufferOffset bo =
    390      writeInst(InstReg(op_special, rs, zero, zero, ff_jalr).encode());
    391 #else
    392  BufferOffset bo =
    393      writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode());
    394 #endif
    395  return bo;
    396 }
    397 BufferOffset AssemblerMIPSShared::as_jalr(Register rs) {
    398  spew("jalr   %3s", rs.name());
    399  BufferOffset bo =
    400      writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode());
    401  return bo;
    402 }
    403 
    404 // Arithmetic instructions
    405 BufferOffset AssemblerMIPSShared::as_addu(Register rd, Register rs,
    406                                          Register rt) {
    407  spew("addu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    408  return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode());
    409 }
    410 
    411 BufferOffset AssemblerMIPSShared::as_addiu(Register rd, Register rs,
    412                                           int32_t j) {
    413  MOZ_ASSERT(Imm16::IsInSignedRange(j));
    414  spew("addiu  %3s,%3s,0x%x", rd.name(), rs.name(), j);
    415  return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
    416 }
    417 
    418 BufferOffset AssemblerMIPSShared::as_daddu(Register rd, Register rs,
    419                                           Register rt) {
    420  spew("daddu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    421  return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode());
    422 }
    423 
    424 BufferOffset AssemblerMIPSShared::as_daddiu(Register rd, Register rs,
    425                                            int32_t j) {
    426  MOZ_ASSERT(Imm16::IsInSignedRange(j));
    427  spew("daddiu %3s,%3s,0x%x", rd.name(), rs.name(), j);
    428  return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode());
    429 }
    430 
    431 BufferOffset AssemblerMIPSShared::as_subu(Register rd, Register rs,
    432                                          Register rt) {
    433  spew("subu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    434  return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
    435 }
    436 
    437 BufferOffset AssemblerMIPSShared::as_dsubu(Register rd, Register rs,
    438                                           Register rt) {
    439  spew("dsubu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    440  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode());
    441 }
    442 
    443 BufferOffset AssemblerMIPSShared::as_mult(Register rs, Register rt) {
    444  spew("mult   %3s,%3s", rs.name(), rt.name());
    445  return writeInst(InstReg(op_special, rs, rt, ff_mult).encode());
    446 }
    447 
    448 BufferOffset AssemblerMIPSShared::as_multu(Register rs, Register rt) {
    449  spew("multu  %3s,%3s", rs.name(), rt.name());
    450  return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
    451 }
    452 
    453 BufferOffset AssemblerMIPSShared::as_dmult(Register rs, Register rt) {
    454  spew("dmult  %3s,%3s", rs.name(), rt.name());
    455  return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode());
    456 }
    457 
    458 BufferOffset AssemblerMIPSShared::as_dmultu(Register rs, Register rt) {
    459  spew("dmultu %3s,%3s", rs.name(), rt.name());
    460  return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode());
    461 }
    462 
    463 BufferOffset AssemblerMIPSShared::as_div(Register rs, Register rt) {
    464  spew("div    %3s,%3s", rs.name(), rt.name());
    465  return writeInst(InstReg(op_special, rs, rt, ff_div).encode());
    466 }
    467 
    468 BufferOffset AssemblerMIPSShared::as_div(Register rd, Register rs,
    469                                         Register rt) {
    470  spew("div    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    471  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_div).encode());
    472 }
    473 
    474 BufferOffset AssemblerMIPSShared::as_divu(Register rs, Register rt) {
    475  spew("divu   %3s,%3s", rs.name(), rt.name());
    476  return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
    477 }
    478 
    479 BufferOffset AssemblerMIPSShared::as_divu(Register rd, Register rs,
    480                                          Register rt) {
    481  spew("divu    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    482  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_divu).encode());
    483 }
    484 
    485 BufferOffset AssemblerMIPSShared::as_mod(Register rd, Register rs,
    486                                         Register rt) {
    487  spew("mod    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    488  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_mod).encode());
    489 }
    490 
    491 BufferOffset AssemblerMIPSShared::as_modu(Register rd, Register rs,
    492                                          Register rt) {
    493  spew("modu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    494  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_modu).encode());
    495 }
    496 
    497 BufferOffset AssemblerMIPSShared::as_ddiv(Register rs, Register rt) {
    498  spew("ddiv   %3s,%3s", rs.name(), rt.name());
    499  return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode());
    500 }
    501 
    502 BufferOffset AssemblerMIPSShared::as_ddiv(Register rd, Register rs,
    503                                          Register rt) {
    504  spew("ddiv   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    505  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddiv).encode());
    506 }
    507 
    508 BufferOffset AssemblerMIPSShared::as_ddivu(Register rs, Register rt) {
    509  spew("ddivu  %3s,%3s", rs.name(), rt.name());
    510  return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode());
    511 }
    512 
    513 BufferOffset AssemblerMIPSShared::as_ddivu(Register rd, Register rs,
    514                                           Register rt) {
    515  spew("ddivu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    516  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddivu).encode());
    517 }
    518 
    519 BufferOffset AssemblerMIPSShared::as_mul(Register rd, Register rs,
    520                                         Register rt) {
    521  spew("mul    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    522 #ifdef MIPSR6
    523  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mul).encode());
    524 #else
    525  return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode());
    526 #endif
    527 }
    528 
    529 BufferOffset AssemblerMIPSShared::as_muh(Register rd, Register rs,
    530                                         Register rt) {
    531  spew("muh  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    532  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muh).encode());
    533 }
    534 
    535 BufferOffset AssemblerMIPSShared::as_mulu(Register rd, Register rs,
    536                                          Register rt) {
    537  spew("mulu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    538  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mulu).encode());
    539 }
    540 
    541 BufferOffset AssemblerMIPSShared::as_muhu(Register rd, Register rs,
    542                                          Register rt) {
    543  spew("muhu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    544  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muhu).encode());
    545 }
    546 
    547 BufferOffset AssemblerMIPSShared::as_dmul(Register rd, Register rs,
    548                                          Register rt) {
    549  spew("dmul   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    550  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmul).encode());
    551 }
    552 
    553 BufferOffset AssemblerMIPSShared::as_dmuh(Register rd, Register rs,
    554                                          Register rt) {
    555  spew("dmuh   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    556  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuh).encode());
    557 }
    558 
    559 BufferOffset AssemblerMIPSShared::as_dmulu(Register rd, Register rt,
    560                                           Register rs) {
    561  spew("dmulu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    562  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmulu).encode());
    563 }
    564 
    565 BufferOffset AssemblerMIPSShared::as_dmuhu(Register rd, Register rt,
    566                                           Register rs) {
    567  spew("dmuhu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    568  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuhu).encode());
    569 }
    570 
    571 BufferOffset AssemblerMIPSShared::as_dmod(Register rd, Register rs,
    572                                          Register rt) {
    573  spew("dmod    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    574  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmod).encode());
    575 }
    576 
    577 BufferOffset AssemblerMIPSShared::as_dmodu(Register rd, Register rs,
    578                                           Register rt) {
    579  spew("dmodu    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    580  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmodu).encode());
    581 }
    582 
    583 BufferOffset AssemblerMIPSShared::as_madd(Register rs, Register rt) {
    584  spew("madd %3s,%3s", rs.name(), rt.name());
    585  return writeInst(InstReg(op_special2, rs, rt, ff_madd).encode());
    586 }
    587 
    588 BufferOffset AssemblerMIPSShared::as_maddu(Register rs, Register rt) {
    589  spew("maddu %3s,%3s", rs.name(), rt.name());
    590  return writeInst(InstReg(op_special2, rs, rt, ff_maddu).encode());
    591 }
    592 
    593 // Shift instructions
    594 BufferOffset AssemblerMIPSShared::as_sll(Register rd, Register rt,
    595                                         uint16_t sa) {
    596  MOZ_ASSERT(sa < 32);
    597  spew("sll    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    598  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
    599 }
    600 
    601 BufferOffset AssemblerMIPSShared::as_dsll(Register rd, Register rt,
    602                                          uint16_t sa) {
    603  MOZ_ASSERT(sa < 32);
    604  spew("dsll   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    605  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode());
    606 }
    607 
    608 BufferOffset AssemblerMIPSShared::as_dsll32(Register rd, Register rt,
    609                                            uint16_t sa) {
    610  MOZ_ASSERT(31 < sa && sa < 64);
    611  spew("dsll32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
    612  return writeInst(
    613      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode());
    614 }
    615 
    616 BufferOffset AssemblerMIPSShared::as_sllv(Register rd, Register rt,
    617                                          Register rs) {
    618  spew("sllv   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    619  return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
    620 }
    621 
    622 BufferOffset AssemblerMIPSShared::as_dsllv(Register rd, Register rt,
    623                                           Register rs) {
    624  spew("dsllv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    625  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode());
    626 }
    627 
    628 BufferOffset AssemblerMIPSShared::as_srl(Register rd, Register rt,
    629                                         uint16_t sa) {
    630  MOZ_ASSERT(sa < 32);
    631  spew("srl    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    632  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
    633 }
    634 
    635 BufferOffset AssemblerMIPSShared::as_dsrl(Register rd, Register rt,
    636                                          uint16_t sa) {
    637  MOZ_ASSERT(sa < 32);
    638  spew("dsrl   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    639  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode());
    640 }
    641 
    642 BufferOffset AssemblerMIPSShared::as_dsrl32(Register rd, Register rt,
    643                                            uint16_t sa) {
    644  MOZ_ASSERT(31 < sa && sa < 64);
    645  spew("dsrl32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
    646  return writeInst(
    647      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode());
    648 }
    649 
    650 BufferOffset AssemblerMIPSShared::as_srlv(Register rd, Register rt,
    651                                          Register rs) {
    652  spew("srlv   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    653  return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
    654 }
    655 
    656 BufferOffset AssemblerMIPSShared::as_dsrlv(Register rd, Register rt,
    657                                           Register rs) {
    658  spew("dsrlv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    659  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode());
    660 }
    661 
    662 BufferOffset AssemblerMIPSShared::as_sra(Register rd, Register rt,
    663                                         uint16_t sa) {
    664  MOZ_ASSERT(sa < 32);
    665  spew("sra    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    666  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
    667 }
    668 
    669 BufferOffset AssemblerMIPSShared::as_dsra(Register rd, Register rt,
    670                                          uint16_t sa) {
    671  MOZ_ASSERT(sa < 32);
    672  spew("dsra   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    673  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode());
    674 }
    675 
    676 BufferOffset AssemblerMIPSShared::as_dsra32(Register rd, Register rt,
    677                                            uint16_t sa) {
    678  MOZ_ASSERT(31 < sa && sa < 64);
    679  spew("dsra32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
    680  return writeInst(
    681      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode());
    682 }
    683 
    684 BufferOffset AssemblerMIPSShared::as_srav(Register rd, Register rt,
    685                                          Register rs) {
    686  spew("srav   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    687  return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
    688 }
    689 
    690 BufferOffset AssemblerMIPSShared::as_dsrav(Register rd, Register rt,
    691                                           Register rs) {
    692  spew("dsrav  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    693  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode());
    694 }
    695 
    696 BufferOffset AssemblerMIPSShared::as_rotr(Register rd, Register rt,
    697                                          uint16_t sa) {
    698  MOZ_ASSERT(sa < 32);
    699  spew("rotr   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    700  MOZ_ASSERT(hasR2());
    701  return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
    702 }
    703 
    704 BufferOffset AssemblerMIPSShared::as_drotr(Register rd, Register rt,
    705                                           uint16_t sa) {
    706  MOZ_ASSERT(sa < 32);
    707  spew("drotr  %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
    708  MOZ_ASSERT(hasR2());
    709  return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode());
    710 }
    711 
    712 BufferOffset AssemblerMIPSShared::as_drotr32(Register rd, Register rt,
    713                                             uint16_t sa) {
    714  MOZ_ASSERT(31 < sa && sa < 64);
    715  spew("drotr32%3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
    716  MOZ_ASSERT(hasR2());
    717  return writeInst(
    718      InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode());
    719 }
    720 
    721 BufferOffset AssemblerMIPSShared::as_rotrv(Register rd, Register rt,
    722                                           Register rs) {
    723  spew("rotrv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    724  MOZ_ASSERT(hasR2());
    725  return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
    726 }
    727 
    728 BufferOffset AssemblerMIPSShared::as_drotrv(Register rd, Register rt,
    729                                            Register rs) {
    730  spew("drotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
    731  MOZ_ASSERT(hasR2());
    732  return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode());
    733 }
    734 
    735 // Load and store instructions
    736 BufferOffset AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off) {
    737  spew("lb     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    738  return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode());
    739 }
    740 
    741 BufferOffset AssemblerMIPSShared::as_lbu(Register rd, Register rs,
    742                                         int16_t off) {
    743  spew("lbu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    744  return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode());
    745 }
    746 
    747 BufferOffset AssemblerMIPSShared::as_lh(Register rd, Register rs, int16_t off) {
    748  spew("lh     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    749  return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode());
    750 }
    751 
    752 BufferOffset AssemblerMIPSShared::as_lhu(Register rd, Register rs,
    753                                         int16_t off) {
    754  spew("lhu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    755  return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode());
    756 }
    757 
    758 BufferOffset AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off) {
    759  spew("lw     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    760  return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
    761 }
    762 
    763 BufferOffset AssemblerMIPSShared::as_lwu(Register rd, Register rs,
    764                                         int16_t off) {
    765  spew("lwu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    766  return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode());
    767 }
    768 
    769 BufferOffset AssemblerMIPSShared::as_lwl(Register rd, Register rs,
    770                                         int16_t off) {
    771  spew("lwl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    772  return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode());
    773 }
    774 
    775 BufferOffset AssemblerMIPSShared::as_lwr(Register rd, Register rs,
    776                                         int16_t off) {
    777  spew("lwr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    778  return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
    779 }
    780 
    781 BufferOffset AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off) {
    782  spew("ll     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    783 #ifdef MIPSR6
    784  return writeInst(InstReg(op_special3, rs, rd, ff_ll).encode());
    785 #else
    786  return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode());
    787 #endif
    788 }
    789 
    790 BufferOffset AssemblerMIPSShared::as_lld(Register rd, Register rs,
    791                                         int16_t off) {
    792  spew("lld     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    793 #ifdef MIPSR6
    794  return writeInst(InstReg(op_special3, rs, rd, ff_lld).encode());
    795 #else
    796  return writeInst(InstImm(op_lld, rs, rd, Imm16(off)).encode());
    797 #endif
    798 }
    799 
    800 BufferOffset AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off) {
    801  spew("ld     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    802  return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode());
    803 }
    804 
    805 BufferOffset AssemblerMIPSShared::as_ldl(Register rd, Register rs,
    806                                         int16_t off) {
    807  spew("ldl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    808  return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode());
    809 }
    810 
    811 BufferOffset AssemblerMIPSShared::as_ldr(Register rd, Register rs,
    812                                         int16_t off) {
    813  spew("ldr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    814  return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode());
    815 }
    816 
    817 BufferOffset AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off) {
    818  spew("sb     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    819  return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode());
    820 }
    821 
    822 BufferOffset AssemblerMIPSShared::as_sh(Register rd, Register rs, int16_t off) {
    823  spew("sh     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    824  return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode());
    825 }
    826 
    827 BufferOffset AssemblerMIPSShared::as_sw(Register rd, Register rs, int16_t off) {
    828  spew("sw     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    829  return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode());
    830 }
    831 
    832 BufferOffset AssemblerMIPSShared::as_swl(Register rd, Register rs,
    833                                         int16_t off) {
    834  spew("swl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    835  return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode());
    836 }
    837 
    838 BufferOffset AssemblerMIPSShared::as_swr(Register rd, Register rs,
    839                                         int16_t off) {
    840  spew("swr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    841  return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
    842 }
    843 
    844 BufferOffset AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off) {
    845  spew("sc     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    846 #ifdef MIPSR6
    847  return writeInst(InstReg(op_special3, rs, rd, ff_sc).encode());
    848 #else
    849  return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode());
    850 #endif
    851 }
    852 
    853 BufferOffset AssemblerMIPSShared::as_scd(Register rd, Register rs,
    854                                         int16_t off) {
    855 #ifdef MIPSR6
    856  return writeInst(InstReg(op_special3, rs, rd, ff_scd).encode());
    857 #else
    858  spew("scd     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    859  return writeInst(InstImm(op_scd, rs, rd, Imm16(off)).encode());
    860 #endif
    861 }
    862 
    863 BufferOffset AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off) {
    864  spew("sd     %3s, (0x%x)%2s", rd.name(), off, rs.name());
    865  return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode());
    866 }
    867 
    868 BufferOffset AssemblerMIPSShared::as_sdl(Register rd, Register rs,
    869                                         int16_t off) {
    870  spew("sdl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    871  return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode());
    872 }
    873 
    874 BufferOffset AssemblerMIPSShared::as_sdr(Register rd, Register rs,
    875                                         int16_t off) {
    876  spew("sdr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
    877  return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode());
    878 }
    879 
    880 BufferOffset AssemblerMIPSShared::as_seleqz(Register rd, Register rs,
    881                                            Register rt) {
    882  spew("seleqz    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    883  return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_seleqz).encode());
    884 }
    885 
    886 BufferOffset AssemblerMIPSShared::as_selnez(Register rd, Register rs,
    887                                            Register rt) {
    888  spew("selnez    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    889  return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_selnez).encode());
    890 }
    891 
    892 BufferOffset AssemblerMIPSShared::as_gslbx(Register rd, Register rs,
    893                                           Register ri, int16_t off) {
    894  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    895  spew("gslbx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    896  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
    897 }
    898 
    899 BufferOffset AssemblerMIPSShared::as_gssbx(Register rd, Register rs,
    900                                           Register ri, int16_t off) {
    901  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    902  spew("gssbx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    903  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
    904 }
    905 
    906 BufferOffset AssemblerMIPSShared::as_gslhx(Register rd, Register rs,
    907                                           Register ri, int16_t off) {
    908  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    909  spew("gslhx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    910  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
    911 }
    912 
    913 BufferOffset AssemblerMIPSShared::as_gsshx(Register rd, Register rs,
    914                                           Register ri, int16_t off) {
    915  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    916  spew("gsshx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    917  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
    918 }
    919 
    920 BufferOffset AssemblerMIPSShared::as_gslwx(Register rd, Register rs,
    921                                           Register ri, int16_t off) {
    922  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    923  spew("gslwx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    924  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
    925 }
    926 
    927 BufferOffset AssemblerMIPSShared::as_gsswx(Register rd, Register rs,
    928                                           Register ri, int16_t off) {
    929  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    930  spew("gsswx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    931  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
    932 }
    933 
    934 BufferOffset AssemblerMIPSShared::as_gsldx(Register rd, Register rs,
    935                                           Register ri, int16_t off) {
    936  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    937  spew("gsldx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    938  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
    939 }
    940 
    941 BufferOffset AssemblerMIPSShared::as_gssdx(Register rd, Register rs,
    942                                           Register ri, int16_t off) {
    943  MOZ_ASSERT(Imm8::IsInSignedRange(off));
    944  spew("gssdx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
    945  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
    946 }
    947 
    948 BufferOffset AssemblerMIPSShared::as_gslq(Register rh, Register rl, Register rs,
    949                                          int16_t off) {
    950  MOZ_ASSERT(GSImm13::IsInRange(off));
    951  spew("gslq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
    952  return writeInst(InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
    953 }
    954 
    955 BufferOffset AssemblerMIPSShared::as_gssq(Register rh, Register rl, Register rs,
    956                                          int16_t off) {
    957  MOZ_ASSERT(GSImm13::IsInRange(off));
    958  spew("gssq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
    959  return writeInst(InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
    960 }
    961 
    962 // Move from HI/LO register.
    963 BufferOffset AssemblerMIPSShared::as_mfhi(Register rd) {
    964  spew("mfhi   %3s", rd.name());
    965  return writeInst(InstReg(op_special, rd, ff_mfhi).encode());
    966 }
    967 
    968 BufferOffset AssemblerMIPSShared::as_mflo(Register rd) {
    969  spew("mflo   %3s", rd.name());
    970  return writeInst(InstReg(op_special, rd, ff_mflo).encode());
    971 }
    972 
    973 // Set on less than.
    974 BufferOffset AssemblerMIPSShared::as_slt(Register rd, Register rs,
    975                                         Register rt) {
    976  spew("slt    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    977  return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode());
    978 }
    979 
    980 BufferOffset AssemblerMIPSShared::as_sltu(Register rd, Register rs,
    981                                          Register rt) {
    982  spew("sltu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
    983  return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode());
    984 }
    985 
    986 BufferOffset AssemblerMIPSShared::as_slti(Register rd, Register rs, int32_t j) {
    987  MOZ_ASSERT(Imm16::IsInSignedRange(j));
    988  spew("slti   %3s,%3s, 0x%x", rd.name(), rs.name(), j);
    989  return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode());
    990 }
    991 
    992 BufferOffset AssemblerMIPSShared::as_sltiu(Register rd, Register rs,
    993                                           uint32_t j) {
    994  MOZ_ASSERT(Imm16::IsInSignedRange(int32_t(j)));
    995  spew("sltiu  %3s,%3s, 0x%x", rd.name(), rs.name(), j);
    996  return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode());
    997 }
    998 
    999 // Conditional move.
   1000 BufferOffset AssemblerMIPSShared::as_movz(Register rd, Register rs,
   1001                                          Register rt) {
   1002  spew("movz   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
   1003  return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode());
   1004 }
   1005 
   1006 BufferOffset AssemblerMIPSShared::as_movn(Register rd, Register rs,
   1007                                          Register rt) {
   1008  spew("movn   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
   1009  return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode());
   1010 }
   1011 
   1012 BufferOffset AssemblerMIPSShared::as_movt(Register rd, Register rs,
   1013                                          uint16_t cc) {
   1014  Register rt;
   1015  rt = Register::FromCode((cc & 0x7) << 2 | 1);
   1016  spew("movt   %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
   1017  return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
   1018 }
   1019 
   1020 BufferOffset AssemblerMIPSShared::as_movf(Register rd, Register rs,
   1021                                          uint16_t cc) {
   1022  Register rt;
   1023  rt = Register::FromCode((cc & 0x7) << 2 | 0);
   1024  spew("movf   %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
   1025  return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
   1026 }
   1027 
   1028 // Bit twiddling.
   1029 BufferOffset AssemblerMIPSShared::as_clz(Register rd, Register rs) {
   1030  spew("clz    %3s,%3s", rd.name(), rs.name());
   1031 #ifdef MIPSR6
   1032  return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_clz).encode());
   1033 #else
   1034  return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
   1035 #endif
   1036 }
   1037 
   1038 BufferOffset AssemblerMIPSShared::as_dclz(Register rd, Register rs) {
   1039  spew("dclz   %3s,%3s", rd.name(), rs.name());
   1040 #ifdef MIPSR6
   1041  return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_dclz).encode());
   1042 #else
   1043  return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode());
   1044 #endif
   1045 }
   1046 
   1047 BufferOffset AssemblerMIPSShared::as_wsbh(Register rd, Register rt) {
   1048  spew("wsbh   %3s,%3s", rd.name(), rt.name());
   1049  return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_bshfl).encode());
   1050 }
   1051 
   1052 BufferOffset AssemblerMIPSShared::as_dsbh(Register rd, Register rt) {
   1053  spew("dsbh   %3s,%3s", rd.name(), rt.name());
   1054  return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_dbshfl).encode());
   1055 }
   1056 
   1057 BufferOffset AssemblerMIPSShared::as_dshd(Register rd, Register rt) {
   1058  spew("dshd   %3s,%3s", rd.name(), rt.name());
   1059  return writeInst(InstReg(op_special3, zero, rt, rd, 0x5, ff_dbshfl).encode());
   1060 }
   1061 
   1062 BufferOffset AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos,
   1063                                         uint16_t size) {
   1064  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
   1065             pos + size <= 32);
   1066  Register rd;
   1067  rd = Register::FromCode(pos + size - 1);
   1068  spew("ins    %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1069  MOZ_ASSERT(hasR2());
   1070  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
   1071 }
   1072 
   1073 BufferOffset AssemblerMIPSShared::as_dins(Register rt, Register rs,
   1074                                          uint16_t pos, uint16_t size) {
   1075  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
   1076             pos + size <= 32);
   1077  Register rd;
   1078  rd = Register::FromCode(pos + size - 1);
   1079  spew("dins   %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1080  MOZ_ASSERT(hasR2());
   1081  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode());
   1082 }
   1083 
   1084 BufferOffset AssemblerMIPSShared::as_dinsm(Register rt, Register rs,
   1085                                           uint16_t pos, uint16_t size) {
   1086  MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 &&
   1087             pos + size <= 64);
   1088  Register rd;
   1089  rd = Register::FromCode(pos + size - 1 - 32);
   1090  spew("dinsm  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1091  MOZ_ASSERT(hasR2());
   1092  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode());
   1093 }
   1094 
   1095 BufferOffset AssemblerMIPSShared::as_dinsu(Register rt, Register rs,
   1096                                           uint16_t pos, uint16_t size) {
   1097  MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 &&
   1098             pos + size > 32 && pos + size <= 64);
   1099  Register rd;
   1100  rd = Register::FromCode(pos + size - 1 - 32);
   1101  spew("dinsu  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1102  MOZ_ASSERT(hasR2());
   1103  return writeInst(
   1104      InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode());
   1105 }
   1106 
   1107 BufferOffset AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos,
   1108                                         uint16_t size) {
   1109  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
   1110             pos + size <= 32);
   1111  Register rd;
   1112  rd = Register::FromCode(size - 1);
   1113  spew("ext    %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1114  MOZ_ASSERT(hasR2());
   1115  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
   1116 }
   1117 
   1118 // Sign extend
   1119 BufferOffset AssemblerMIPSShared::as_seb(Register rd, Register rt) {
   1120  spew("seb    %3s,%3s", rd.name(), rt.name());
   1121  MOZ_ASSERT(hasR2());
   1122  return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode());
   1123 }
   1124 
   1125 BufferOffset AssemblerMIPSShared::as_seh(Register rd, Register rt) {
   1126  spew("seh    %3s,%3s", rd.name(), rt.name());
   1127  MOZ_ASSERT(hasR2());
   1128  return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode());
   1129 }
   1130 
   1131 BufferOffset AssemblerMIPSShared::as_dext(Register rt, Register rs,
   1132                                          uint16_t pos, uint16_t size) {
   1133  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
   1134             pos + size <= 63);
   1135  Register rd;
   1136  rd = Register::FromCode(size - 1);
   1137  spew("dext   %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1138  MOZ_ASSERT(hasR2());
   1139  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode());
   1140 }
   1141 
   1142 BufferOffset AssemblerMIPSShared::as_dextm(Register rt, Register rs,
   1143                                           uint16_t pos, uint16_t size) {
   1144  MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 &&
   1145             pos + size <= 64);
   1146  Register rd;
   1147  rd = Register::FromCode(size - 1 - 32);
   1148  spew("dextm  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1149  MOZ_ASSERT(hasR2());
   1150  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode());
   1151 }
   1152 
   1153 BufferOffset AssemblerMIPSShared::as_dextu(Register rt, Register rs,
   1154                                           uint16_t pos, uint16_t size) {
   1155  MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 &&
   1156             pos + size > 32 && pos + size <= 64);
   1157  Register rd;
   1158  rd = Register::FromCode(size - 1);
   1159  spew("dextu  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
   1160  MOZ_ASSERT(hasR2());
   1161  return writeInst(
   1162      InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode());
   1163 }
   1164 
   1165 // FP instructions
   1166 BufferOffset AssemblerMIPSShared::as_ldc1(FloatRegister ft, Register base,
   1167                                          int32_t off) {
   1168  MOZ_ASSERT(Imm16::IsInSignedRange(off));
   1169  spew("ldc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
   1170  return writeInst(InstImm(op_ldc1, base, ft, Imm16(off)).encode());
   1171 }
   1172 
   1173 BufferOffset AssemblerMIPSShared::as_sdc1(FloatRegister ft, Register base,
   1174                                          int32_t off) {
   1175  MOZ_ASSERT(Imm16::IsInSignedRange(off));
   1176  spew("sdc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
   1177  return writeInst(InstImm(op_sdc1, base, ft, Imm16(off)).encode());
   1178 }
   1179 
   1180 BufferOffset AssemblerMIPSShared::as_lwc1(FloatRegister ft, Register base,
   1181                                          int32_t off) {
   1182  MOZ_ASSERT(Imm16::IsInSignedRange(off));
   1183  spew("lwc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
   1184  return writeInst(InstImm(op_lwc1, base, ft, Imm16(off)).encode());
   1185 }
   1186 
   1187 BufferOffset AssemblerMIPSShared::as_swc1(FloatRegister ft, Register base,
   1188                                          int32_t off) {
   1189  MOZ_ASSERT(Imm16::IsInSignedRange(off));
   1190  spew("swc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
   1191  return writeInst(InstImm(op_swc1, base, ft, Imm16(off)).encode());
   1192 }
   1193 
   1194 BufferOffset AssemblerMIPSShared::as_gsldl(FloatRegister fd, Register base,
   1195                                           int32_t off) {
   1196  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1197  spew("gsldl  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1198  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
   1199 }
   1200 
   1201 BufferOffset AssemblerMIPSShared::as_gsldr(FloatRegister fd, Register base,
   1202                                           int32_t off) {
   1203  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1204  spew("gsldr  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1205  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
   1206 }
   1207 
   1208 BufferOffset AssemblerMIPSShared::as_gssdl(FloatRegister fd, Register base,
   1209                                           int32_t off) {
   1210  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1211  spew("gssdl  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1212  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
   1213 }
   1214 
   1215 BufferOffset AssemblerMIPSShared::as_gssdr(FloatRegister fd, Register base,
   1216                                           int32_t off) {
   1217  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1218  spew("gssdr  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1219  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
   1220 }
   1221 
   1222 BufferOffset AssemblerMIPSShared::as_gslsl(FloatRegister fd, Register base,
   1223                                           int32_t off) {
   1224  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1225  spew("gslsl  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1226  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
   1227 }
   1228 
   1229 BufferOffset AssemblerMIPSShared::as_gslsr(FloatRegister fd, Register base,
   1230                                           int32_t off) {
   1231  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1232  spew("gslsr  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1233  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
   1234 }
   1235 
   1236 BufferOffset AssemblerMIPSShared::as_gsssl(FloatRegister fd, Register base,
   1237                                           int32_t off) {
   1238  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1239  spew("gsssl  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1240  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
   1241 }
   1242 
   1243 BufferOffset AssemblerMIPSShared::as_gsssr(FloatRegister fd, Register base,
   1244                                           int32_t off) {
   1245  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1246  spew("gsssr  %3s, (0x%x)%2s", fd.name(), off, base.name());
   1247  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
   1248 }
   1249 
   1250 BufferOffset AssemblerMIPSShared::as_gslsx(FloatRegister fd, Register rs,
   1251                                           Register ri, int16_t off) {
   1252  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1253  spew("gslsx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
   1254  return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
   1255 }
   1256 
   1257 BufferOffset AssemblerMIPSShared::as_gsssx(FloatRegister fd, Register rs,
   1258                                           Register ri, int16_t off) {
   1259  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1260  spew("gsssx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
   1261  return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
   1262 }
   1263 
   1264 BufferOffset AssemblerMIPSShared::as_gsldx(FloatRegister fd, Register rs,
   1265                                           Register ri, int16_t off) {
   1266  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1267  spew("gsldx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
   1268  return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
   1269 }
   1270 
   1271 BufferOffset AssemblerMIPSShared::as_gssdx(FloatRegister fd, Register rs,
   1272                                           Register ri, int16_t off) {
   1273  MOZ_ASSERT(Imm8::IsInSignedRange(off));
   1274  spew("gssdx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
   1275  return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
   1276 }
   1277 
   1278 BufferOffset AssemblerMIPSShared::as_gslq(FloatRegister rh, FloatRegister rl,
   1279                                          Register rs, int16_t off) {
   1280  MOZ_ASSERT(GSImm13::IsInRange(off));
   1281  spew("gslq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
   1282  return writeInst(
   1283      InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
   1284 }
   1285 
   1286 BufferOffset AssemblerMIPSShared::as_gssq(FloatRegister rh, FloatRegister rl,
   1287                                          Register rs, int16_t off) {
   1288  MOZ_ASSERT(GSImm13::IsInRange(off));
   1289  spew("gssq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
   1290  return writeInst(
   1291      InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
   1292 }
   1293 
   1294 BufferOffset AssemblerMIPSShared::as_movs(FloatRegister fd, FloatRegister fs) {
   1295  spew("mov.s  %3s,%3s", fd.name(), fs.name());
   1296  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode());
   1297 }
   1298 
   1299 BufferOffset AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs) {
   1300  spew("mov.d  %3s,%3s", fd.name(), fs.name());
   1301  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode());
   1302 }
   1303 
   1304 BufferOffset AssemblerMIPSShared::as_ctc1(Register rt, FPControl fc) {
   1305  spew("ctc1   %3s,%d", rt.name(), fc);
   1306  return writeInst(InstReg(op_cop1, rs_ctc1, rt, (uint32_t)fc).encode());
   1307 }
   1308 
   1309 BufferOffset AssemblerMIPSShared::as_cfc1(Register rt, FPControl fc) {
   1310  spew("cfc1   %3s,%d", rt.name(), fc);
   1311  return writeInst(InstReg(op_cop1, rs_cfc1, rt, (uint32_t)fc).encode());
   1312 }
   1313 
   1314 BufferOffset AssemblerMIPSShared::as_mtc1(Register rt, FloatRegister fs) {
   1315  spew("mtc1   %3s,%3s", rt.name(), fs.name());
   1316  return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode());
   1317 }
   1318 
   1319 BufferOffset AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs) {
   1320  spew("mfc1   %3s,%3s", rt.name(), fs.name());
   1321  return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
   1322 }
   1323 
   1324 BufferOffset AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs) {
   1325  spew("mthc1  %3s,%3s", rt.name(), fs.name());
   1326  return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode());
   1327 }
   1328 
   1329 BufferOffset AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs) {
   1330  spew("mfhc1  %3s,%3s", rt.name(), fs.name());
   1331  return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode());
   1332 }
   1333 
   1334 BufferOffset AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs) {
   1335  spew("dmtc1  %3s,%3s", rt.name(), fs.name());
   1336  return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode());
   1337 }
   1338 
   1339 BufferOffset AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs) {
   1340  spew("dmfc1  %3s,%3s", rt.name(), fs.name());
   1341  return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode());
   1342 }
   1343 
   1344 // FP convert instructions
   1345 BufferOffset AssemblerMIPSShared::as_ceilws(FloatRegister fd,
   1346                                            FloatRegister fs) {
   1347  spew("ceil.w.s%3s,%3s", fd.name(), fs.name());
   1348  return writeInst(
   1349      InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode());
   1350 }
   1351 
   1352 BufferOffset AssemblerMIPSShared::as_ceills(FloatRegister fd,
   1353                                            FloatRegister fs) {
   1354  spew("ceil.l.s%3s,%3s", fd.name(), fs.name());
   1355  return writeInst(
   1356      InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_l_fmt).encode());
   1357 }
   1358 
   1359 BufferOffset AssemblerMIPSShared::as_floorws(FloatRegister fd,
   1360                                             FloatRegister fs) {
   1361  spew("floor.w.s%3s,%3s", fd.name(), fs.name());
   1362  return writeInst(
   1363      InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode());
   1364 }
   1365 
   1366 BufferOffset AssemblerMIPSShared::as_floorls(FloatRegister fd,
   1367                                             FloatRegister fs) {
   1368  spew("floor.l.s%3s,%3s", fd.name(), fs.name());
   1369  return writeInst(
   1370      InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_l_fmt).encode());
   1371 }
   1372 
   1373 BufferOffset AssemblerMIPSShared::as_roundws(FloatRegister fd,
   1374                                             FloatRegister fs) {
   1375  spew("round.w.s%3s,%3s", fd.name(), fs.name());
   1376  return writeInst(
   1377      InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode());
   1378 }
   1379 
   1380 BufferOffset AssemblerMIPSShared::as_roundls(FloatRegister fd,
   1381                                             FloatRegister fs) {
   1382  spew("round.l.s%3s,%3s", fd.name(), fs.name());
   1383  return writeInst(
   1384      InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_l_fmt).encode());
   1385 }
   1386 
   1387 BufferOffset AssemblerMIPSShared::as_truncws(FloatRegister fd,
   1388                                             FloatRegister fs) {
   1389  spew("trunc.w.s%3s,%3s", fd.name(), fs.name());
   1390  return writeInst(
   1391      InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode());
   1392 }
   1393 
   1394 BufferOffset AssemblerMIPSShared::as_truncls(FloatRegister fd,
   1395                                             FloatRegister fs) {
   1396  spew("trunc.l.s%3s,%3s", fd.name(), fs.name());
   1397  return writeInst(
   1398      InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_l_fmt).encode());
   1399 }
   1400 
   1401 BufferOffset AssemblerMIPSShared::as_ceilwd(FloatRegister fd,
   1402                                            FloatRegister fs) {
   1403  spew("ceil.w.d%3s,%3s", fd.name(), fs.name());
   1404  return writeInst(
   1405      InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode());
   1406 }
   1407 
   1408 BufferOffset AssemblerMIPSShared::as_ceilld(FloatRegister fd,
   1409                                            FloatRegister fs) {
   1410  spew("ceil.l.d%3s,%3s", fd.name(), fs.name());
   1411  return writeInst(
   1412      InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_l_fmt).encode());
   1413 }
   1414 
   1415 BufferOffset AssemblerMIPSShared::as_floorwd(FloatRegister fd,
   1416                                             FloatRegister fs) {
   1417  spew("floor.w.d%3s,%3s", fd.name(), fs.name());
   1418  return writeInst(
   1419      InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode());
   1420 }
   1421 
   1422 BufferOffset AssemblerMIPSShared::as_floorld(FloatRegister fd,
   1423                                             FloatRegister fs) {
   1424  spew("floor.l.d%3s,%3s", fd.name(), fs.name());
   1425  return writeInst(
   1426      InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_l_fmt).encode());
   1427 }
   1428 
   1429 BufferOffset AssemblerMIPSShared::as_roundwd(FloatRegister fd,
   1430                                             FloatRegister fs) {
   1431  spew("round.w.d%3s,%3s", fd.name(), fs.name());
   1432  return writeInst(
   1433      InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode());
   1434 }
   1435 
   1436 BufferOffset AssemblerMIPSShared::as_roundld(FloatRegister fd,
   1437                                             FloatRegister fs) {
   1438  spew("round.l.d%3s,%3s", fd.name(), fs.name());
   1439  return writeInst(
   1440      InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_l_fmt).encode());
   1441 }
   1442 
   1443 BufferOffset AssemblerMIPSShared::as_truncwd(FloatRegister fd,
   1444                                             FloatRegister fs) {
   1445  spew("trunc.w.d%3s,%3s", fd.name(), fs.name());
   1446  return writeInst(
   1447      InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
   1448 }
   1449 
   1450 BufferOffset AssemblerMIPSShared::as_truncld(FloatRegister fd,
   1451                                             FloatRegister fs) {
   1452  spew("trunc.l.d%3s,%3s", fd.name(), fs.name());
   1453  return writeInst(
   1454      InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_l_fmt).encode());
   1455 }
   1456 
   1457 BufferOffset AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs) {
   1458  spew("cvt.d.l%3s,%3s", fd.name(), fs.name());
   1459  return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode());
   1460 }
   1461 
   1462 BufferOffset AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs) {
   1463  spew("cvt.d.s%3s,%3s", fd.name(), fs.name());
   1464  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode());
   1465 }
   1466 
   1467 BufferOffset AssemblerMIPSShared::as_cvtdw(FloatRegister fd, FloatRegister fs) {
   1468  spew("cvt.d.w%3s,%3s", fd.name(), fs.name());
   1469  return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode());
   1470 }
   1471 
   1472 BufferOffset AssemblerMIPSShared::as_cvtsd(FloatRegister fd, FloatRegister fs) {
   1473  spew("cvt.s.d%3s,%3s", fd.name(), fs.name());
   1474  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode());
   1475 }
   1476 
   1477 BufferOffset AssemblerMIPSShared::as_cvtsl(FloatRegister fd, FloatRegister fs) {
   1478  spew("cvt.s.l%3s,%3s", fd.name(), fs.name());
   1479  return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_s_fmt).encode());
   1480 }
   1481 
   1482 BufferOffset AssemblerMIPSShared::as_cvtsw(FloatRegister fd, FloatRegister fs) {
   1483  spew("cvt.s.w%3s,%3s", fd.name(), fs.name());
   1484  return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode());
   1485 }
   1486 
   1487 BufferOffset AssemblerMIPSShared::as_cvtwd(FloatRegister fd, FloatRegister fs) {
   1488  spew("cvt.w.d%3s,%3s", fd.name(), fs.name());
   1489  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode());
   1490 }
   1491 
   1492 BufferOffset AssemblerMIPSShared::as_cvtws(FloatRegister fd, FloatRegister fs) {
   1493  spew("cvt.w.s%3s,%3s", fd.name(), fs.name());
   1494  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode());
   1495 }
   1496 
   1497 // FP arithmetic instructions
   1498 BufferOffset AssemblerMIPSShared::as_adds(FloatRegister fd, FloatRegister fs,
   1499                                          FloatRegister ft) {
   1500  spew("add.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1501  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode());
   1502 }
   1503 
   1504 BufferOffset AssemblerMIPSShared::as_addd(FloatRegister fd, FloatRegister fs,
   1505                                          FloatRegister ft) {
   1506  spew("add.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1507  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode());
   1508 }
   1509 
   1510 BufferOffset AssemblerMIPSShared::as_subs(FloatRegister fd, FloatRegister fs,
   1511                                          FloatRegister ft) {
   1512  spew("sub.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1513  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode());
   1514 }
   1515 
   1516 BufferOffset AssemblerMIPSShared::as_subd(FloatRegister fd, FloatRegister fs,
   1517                                          FloatRegister ft) {
   1518  spew("sub.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1519  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode());
   1520 }
   1521 
   1522 BufferOffset AssemblerMIPSShared::as_abss(FloatRegister fd, FloatRegister fs) {
   1523  spew("abs.s  %3s,%3s", fd.name(), fs.name());
   1524  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode());
   1525 }
   1526 
   1527 BufferOffset AssemblerMIPSShared::as_absd(FloatRegister fd, FloatRegister fs) {
   1528  spew("abs.d  %3s,%3s", fd.name(), fs.name());
   1529  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
   1530 }
   1531 
   1532 BufferOffset AssemblerMIPSShared::as_negs(FloatRegister fd, FloatRegister fs) {
   1533  spew("neg.s  %3s,%3s", fd.name(), fs.name());
   1534  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode());
   1535 }
   1536 
   1537 BufferOffset AssemblerMIPSShared::as_negd(FloatRegister fd, FloatRegister fs) {
   1538  spew("neg.d  %3s,%3s", fd.name(), fs.name());
   1539  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
   1540 }
   1541 
   1542 BufferOffset AssemblerMIPSShared::as_muls(FloatRegister fd, FloatRegister fs,
   1543                                          FloatRegister ft) {
   1544  spew("mul.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1545  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode());
   1546 }
   1547 
   1548 BufferOffset AssemblerMIPSShared::as_muld(FloatRegister fd, FloatRegister fs,
   1549                                          FloatRegister ft) {
   1550  spew("mul.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1551  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode());
   1552 }
   1553 
   1554 BufferOffset AssemblerMIPSShared::as_divs(FloatRegister fd, FloatRegister fs,
   1555                                          FloatRegister ft) {
   1556  spew("div.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1557  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode());
   1558 }
   1559 
   1560 BufferOffset AssemblerMIPSShared::as_divd(FloatRegister fd, FloatRegister fs,
   1561                                          FloatRegister ft) {
   1562  spew("divd.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1563  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode());
   1564 }
   1565 
   1566 BufferOffset AssemblerMIPSShared::as_sqrts(FloatRegister fd, FloatRegister fs) {
   1567  spew("sqrts  %3s,%3s", fd.name(), fs.name());
   1568  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode());
   1569 }
   1570 
   1571 BufferOffset AssemblerMIPSShared::as_sqrtd(FloatRegister fd, FloatRegister fs) {
   1572  spew("sqrtd  %3s,%3s", fd.name(), fs.name());
   1573  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode());
   1574 }
   1575 
   1576 // FP compare instructions
   1577 BufferOffset AssemblerMIPSShared::as_cf(FloatFormat fmt, FloatRegister fs,
   1578                                        FloatRegister ft, FPConditionBit fcc) {
   1579  if (fmt == DoubleFloat) {
   1580    spew("c.f.d  FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1581 #ifdef MIPSR6
   1582    return writeInst(
   1583        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
   1584            .encode());
   1585 #else
   1586    return writeInst(
   1587        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
   1588 #endif
   1589  } else {
   1590    spew("c.f.s  FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1591 #ifdef MIPSR6
   1592    return writeInst(
   1593        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
   1594            .encode());
   1595 #else
   1596    return writeInst(
   1597        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
   1598 #endif
   1599  }
   1600 }
   1601 
   1602 BufferOffset AssemblerMIPSShared::as_cun(FloatFormat fmt, FloatRegister fs,
   1603                                         FloatRegister ft, FPConditionBit fcc) {
   1604  if (fmt == DoubleFloat) {
   1605    spew("c.un.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1606 #ifdef MIPSR6
   1607    return writeInst(
   1608        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
   1609            .encode());
   1610 #else
   1611    return writeInst(
   1612        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
   1613 #endif
   1614  } else {
   1615    spew("c.un.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1616 #ifdef MIPSR6
   1617    return writeInst(
   1618        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
   1619            .encode());
   1620 #else
   1621    return writeInst(
   1622        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
   1623 #endif
   1624  }
   1625 }
   1626 
   1627 BufferOffset AssemblerMIPSShared::as_ceq(FloatFormat fmt, FloatRegister fs,
   1628                                         FloatRegister ft, FPConditionBit fcc) {
   1629  if (fmt == DoubleFloat) {
   1630    spew("c.eq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1631 #ifdef MIPSR6
   1632    return writeInst(
   1633        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
   1634            .encode());
   1635 #else
   1636    return writeInst(
   1637        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
   1638 #endif
   1639  } else {
   1640    spew("c.eq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1641 #ifdef MIPSR6
   1642    return writeInst(
   1643        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
   1644            .encode());
   1645 #else
   1646    return writeInst(
   1647        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
   1648 #endif
   1649  }
   1650 }
   1651 
   1652 BufferOffset AssemblerMIPSShared::as_cueq(FloatFormat fmt, FloatRegister fs,
   1653                                          FloatRegister ft,
   1654                                          FPConditionBit fcc) {
   1655  if (fmt == DoubleFloat) {
   1656    spew("c.ueq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1657 #ifdef MIPSR6
   1658    return writeInst(
   1659        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
   1660            .encode());
   1661 #else
   1662    return writeInst(
   1663        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
   1664 #endif
   1665  } else {
   1666    spew("c.ueq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1667 #ifdef MIPSR6
   1668    return writeInst(
   1669        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
   1670            .encode());
   1671 #else
   1672    return writeInst(
   1673        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
   1674 #endif
   1675  }
   1676 }
   1677 
   1678 BufferOffset AssemblerMIPSShared::as_colt(FloatFormat fmt, FloatRegister fs,
   1679                                          FloatRegister ft,
   1680                                          FPConditionBit fcc) {
   1681  if (fmt == DoubleFloat) {
   1682    spew("c.olt.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1683 #ifdef MIPSR6
   1684    return writeInst(
   1685        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
   1686            .encode());
   1687 #else
   1688    return writeInst(
   1689        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
   1690 #endif
   1691  } else {
   1692    spew("c.olt.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1693 #ifdef MIPSR6
   1694    return writeInst(
   1695        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
   1696            .encode());
   1697 #else
   1698    return writeInst(
   1699        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
   1700 #endif
   1701  }
   1702 }
   1703 
   1704 BufferOffset AssemblerMIPSShared::as_cult(FloatFormat fmt, FloatRegister fs,
   1705                                          FloatRegister ft,
   1706                                          FPConditionBit fcc) {
   1707  if (fmt == DoubleFloat) {
   1708    spew("c.ult.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1709 #ifdef MIPSR6
   1710    return writeInst(
   1711        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
   1712            .encode());
   1713 #else
   1714    return writeInst(
   1715        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
   1716 #endif
   1717  } else {
   1718    spew("c.ult.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1719 #ifdef MIPSR6
   1720    return writeInst(
   1721        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
   1722            .encode());
   1723 #else
   1724    return writeInst(
   1725        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
   1726 #endif
   1727  }
   1728 }
   1729 
   1730 BufferOffset AssemblerMIPSShared::as_cole(FloatFormat fmt, FloatRegister fs,
   1731                                          FloatRegister ft,
   1732                                          FPConditionBit fcc) {
   1733  if (fmt == DoubleFloat) {
   1734    spew("c.ole.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1735 #ifdef MIPSR6
   1736    return writeInst(
   1737        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ole_fmt)
   1738            .encode());
   1739 #else
   1740    return writeInst(
   1741        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
   1742 #endif
   1743  } else {
   1744    spew("c.ole.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1745 #ifdef MIPSR6
   1746    return writeInst(
   1747        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ole_fmt)
   1748            .encode());
   1749 #else
   1750    return writeInst(
   1751        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
   1752 #endif
   1753  }
   1754 }
   1755 
   1756 BufferOffset AssemblerMIPSShared::as_cule(FloatFormat fmt, FloatRegister fs,
   1757                                          FloatRegister ft,
   1758                                          FPConditionBit fcc) {
   1759  if (fmt == DoubleFloat) {
   1760    spew("c.ule.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1761 #ifdef MIPSR6
   1762    return writeInst(
   1763        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ule_fmt)
   1764            .encode());
   1765 #else
   1766    return writeInst(
   1767        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
   1768 #endif
   1769  } else {
   1770    spew("c.ule.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
   1771 #ifdef MIPSR6
   1772    return writeInst(
   1773        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ule_fmt)
   1774            .encode());
   1775 #else
   1776    return writeInst(
   1777        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
   1778 #endif
   1779  }
   1780 }
   1781 
   1782 // FP conditional move.
   1783 BufferOffset AssemblerMIPSShared::as_movt(FloatFormat fmt, FloatRegister fd,
   1784                                          FloatRegister fs,
   1785                                          FPConditionBit fcc) {
   1786  Register rt = Register::FromCode(fcc << 2 | 1);
   1787  if (fmt == DoubleFloat) {
   1788    spew("movt.d FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
   1789    return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movf_fmt).encode());
   1790  } else {
   1791    spew("movt.s FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
   1792    return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movf_fmt).encode());
   1793  }
   1794 }
   1795 
   1796 BufferOffset AssemblerMIPSShared::as_movf(FloatFormat fmt, FloatRegister fd,
   1797                                          FloatRegister fs,
   1798                                          FPConditionBit fcc) {
   1799  Register rt = Register::FromCode(fcc << 2 | 0);
   1800  if (fmt == DoubleFloat) {
   1801    spew("movf.d FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
   1802    return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movf_fmt).encode());
   1803  } else {
   1804    spew("movf.s FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
   1805    return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movf_fmt).encode());
   1806  }
   1807 }
   1808 
   1809 BufferOffset AssemblerMIPSShared::as_movz(FloatFormat fmt, FloatRegister fd,
   1810                                          FloatRegister fs, Register rt) {
   1811  if (fmt == DoubleFloat) {
   1812    spew("movz.d %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
   1813    return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movz_fmt).encode());
   1814  } else {
   1815    spew("movz.s %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
   1816    return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movz_fmt).encode());
   1817  }
   1818 }
   1819 
   1820 BufferOffset AssemblerMIPSShared::as_movn(FloatFormat fmt, FloatRegister fd,
   1821                                          FloatRegister fs, Register rt) {
   1822  if (fmt == DoubleFloat) {
   1823    spew("movn.d %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
   1824    return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movn_fmt).encode());
   1825  } else {
   1826    spew("movn.s %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
   1827    return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movn_fmt).encode());
   1828  }
   1829 }
   1830 
   1831 BufferOffset AssemblerMIPSShared::as_max(FloatFormat fmt, FloatRegister fd,
   1832                                         FloatRegister fs, FloatRegister ft) {
   1833  if (fmt == DoubleFloat) {
   1834    spew("max  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1835    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_max).encode());
   1836  } else {
   1837    spew("max  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1838    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_max).encode());
   1839  }
   1840 }
   1841 
   1842 BufferOffset AssemblerMIPSShared::as_min(FloatFormat fmt, FloatRegister fd,
   1843                                         FloatRegister fs, FloatRegister ft) {
   1844  if (fmt == DoubleFloat) {
   1845    spew("min  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1846    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_min).encode());
   1847  } else {
   1848    spew("min  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
   1849    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_min).encode());
   1850  }
   1851 }
   1852 
   1853 BufferOffset AssemblerMIPSShared::as_tge(Register rs, Register rt,
   1854                                         uint32_t code) {
   1855  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1856  spew("tge %3s,%3s,%d", rs.name(), rt.name(), code);
   1857  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tge).encode());
   1858 }
   1859 
   1860 BufferOffset AssemblerMIPSShared::as_tgeu(Register rs, Register rt,
   1861                                          uint32_t code) {
   1862  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1863  spew("tgeu %3s,%3s,%d", rs.name(), rt.name(), code);
   1864  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tgeu).encode());
   1865 }
   1866 
   1867 BufferOffset AssemblerMIPSShared::as_tlt(Register rs, Register rt,
   1868                                         uint32_t code) {
   1869  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1870  spew("tlt %3s,%3s,%d", rs.name(), rt.name(), code);
   1871  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tlt).encode());
   1872 }
   1873 
   1874 BufferOffset AssemblerMIPSShared::as_tltu(Register rs, Register rt,
   1875                                          uint32_t code) {
   1876  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1877  spew("tltu %3s,%3s,%d", rs.name(), rt.name(), code);
   1878  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tltu).encode());
   1879 }
   1880 
   1881 BufferOffset AssemblerMIPSShared::as_teq(Register rs, Register rt,
   1882                                         uint32_t code) {
   1883  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1884  spew("teq %3s,%3s,%d", rs.name(), rt.name(), code);
   1885  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_teq).encode());
   1886 }
   1887 
   1888 BufferOffset AssemblerMIPSShared::as_tne(Register rs, Register rt,
   1889                                         uint32_t code) {
   1890  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1891  spew("tne %3s,%3s,%d", rs.name(), rt.name(), code);
   1892  return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tne).encode());
   1893 }
   1894 
   1895 void AssemblerMIPSShared::bind(Label* label, BufferOffset boff) {
   1896  spew(".set Llabel %p", label);
   1897  // If our caller didn't give us an explicit target to bind to
   1898  // then we want to bind to the location of the next instruction
   1899  BufferOffset dest = boff.assigned() ? boff : nextOffset();
   1900  if (label->used()) {
   1901    int32_t next;
   1902 
   1903    // A used label holds a link to branch that uses it.
   1904    BufferOffset b(label);
   1905    do {
   1906      // Even a 0 offset may be invalid if we're out of memory.
   1907      if (oom()) {
   1908        return;
   1909      }
   1910 
   1911      Instruction* inst = editSrc(b);
   1912 
   1913      // Second word holds a pointer to the next branch in label's chain.
   1914      next = inst[1].encode();
   1915      bind(reinterpret_cast<InstImm*>(inst), b.getOffset(), dest.getOffset());
   1916 
   1917      b = BufferOffset(next);
   1918    } while (next != LabelBase::INVALID_OFFSET);
   1919  }
   1920  label->bind(dest.getOffset());
   1921 }
   1922 
   1923 void AssemblerMIPSShared::retarget(Label* label, Label* target) {
   1924  spew("retarget %p -> %p", label, target);
   1925  if (label->used() && !oom()) {
   1926    if (target->bound()) {
   1927      bind(label, BufferOffset(target));
   1928    } else if (target->used()) {
   1929      // The target is not bound but used. Prepend label's branch list
   1930      // onto target's.
   1931      int32_t next;
   1932      BufferOffset labelBranchOffset(label);
   1933 
   1934      // Find the head of the use chain for label.
   1935      do {
   1936        Instruction* inst = editSrc(labelBranchOffset);
   1937 
   1938        // Second word holds a pointer to the next branch in chain.
   1939        next = inst[1].encode();
   1940        labelBranchOffset = BufferOffset(next);
   1941      } while (next != LabelBase::INVALID_OFFSET);
   1942 
   1943      // Then patch the head of label's use chain to the tail of
   1944      // target's use chain, prepending the entire use chain of target.
   1945      Instruction* inst = editSrc(labelBranchOffset);
   1946      int32_t prev = target->offset();
   1947      target->use(label->offset());
   1948      inst[1].setData(prev);
   1949    } else {
   1950      // The target is unbound and unused.  We can just take the head of
   1951      // the list hanging off of label, and dump that into target.
   1952      target->use(label->offset());
   1953    }
   1954  }
   1955  label->reset();
   1956 }
   1957 
   1958 void dbg_break() {}
   1959 void AssemblerMIPSShared::as_break(uint32_t code) {
   1960  MOZ_ASSERT(code <= MAX_BREAK_CODE);
   1961  spew("break %d", code);
   1962  writeInst(op_special | code << FunctionBits | ff_break);
   1963 }
   1964 
   1965 void AssemblerMIPSShared::as_sync(uint32_t stype) {
   1966  MOZ_ASSERT(stype <= 31);
   1967  spew("sync %d", stype);
   1968  writeInst(InstReg(op_special, zero, zero, zero, stype, ff_sync).encode());
   1969 }
   1970 
   1971 // This just stomps over memory with 32 bits of raw data. Its purpose is to
   1972 // overwrite the call of JITed code with 32 bits worth of an offset. This will
   1973 // is only meant to function on code that has been invalidated, so it should
   1974 // be totally safe. Since that instruction will never be executed again, a
   1975 // ICache flush should not be necessary
   1976 void AssemblerMIPSShared::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) {
   1977  // Raw is going to be the return address.
   1978  uint32_t* raw = (uint32_t*)label.raw();
   1979  // Overwrite the 4 bytes before the return address, which will
   1980  // end up being the call instruction.
   1981  *(raw - 1) = imm.value;
   1982 }
   1983 
   1984 uint8_t* AssemblerMIPSShared::NextInstruction(uint8_t* inst_, uint32_t* count) {
   1985  Instruction* inst = reinterpret_cast<Instruction*>(inst_);
   1986  if (count != nullptr) {
   1987    *count += sizeof(Instruction);
   1988  }
   1989  return reinterpret_cast<uint8_t*>(inst->next());
   1990 }
   1991 
   1992 // Since there are no pools in MIPS implementation, this should be simple.
   1993 Instruction* Instruction::next() { return this + 1; }
   1994 
   1995 InstImm AssemblerMIPSShared::invertBranch(InstImm branch,
   1996                                          BOffImm16 skipOffset) {
   1997  uint32_t rt = 0;
   1998  OpcodeField op = (OpcodeField)(branch.extractOpcode() << OpcodeShift);
   1999  switch (op) {
   2000    case op_beq:
   2001      branch.setBOffImm16(skipOffset);
   2002      branch.setOpcode(op_bne);
   2003      return branch;
   2004    case op_bne:
   2005      branch.setBOffImm16(skipOffset);
   2006      branch.setOpcode(op_beq);
   2007      return branch;
   2008    case op_bgtz:
   2009      branch.setBOffImm16(skipOffset);
   2010      branch.setOpcode(op_blez);
   2011      return branch;
   2012    case op_blez:
   2013      branch.setBOffImm16(skipOffset);
   2014      branch.setOpcode(op_bgtz);
   2015      return branch;
   2016    case op_regimm:
   2017      branch.setBOffImm16(skipOffset);
   2018      rt = branch.extractRT();
   2019      if (rt == (rt_bltz >> RTShift)) {
   2020        branch.setRT(rt_bgez);
   2021        return branch;
   2022      }
   2023      if (rt == (rt_bgez >> RTShift)) {
   2024        branch.setRT(rt_bltz);
   2025        return branch;
   2026      }
   2027 
   2028      MOZ_CRASH("Error creating long branch.");
   2029 
   2030    case op_cop1:
   2031      MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
   2032 
   2033      branch.setBOffImm16(skipOffset);
   2034      rt = branch.extractRT();
   2035      if (rt & 0x1) {
   2036        branch.setRT((RTField)((rt & ~0x1) << RTShift));
   2037      } else {
   2038        branch.setRT((RTField)((rt | 0x1) << RTShift));
   2039      }
   2040      return branch;
   2041    default:
   2042      MOZ_CRASH("Error creating long branch.");
   2043  }
   2044 }
   2045 
   2046 void AssemblerMIPSShared::ToggleToJmp(CodeLocationLabel inst_) {
   2047  InstImm* inst = (InstImm*)inst_.raw();
   2048 
   2049  MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift));
   2050  // We converted beq to andi, so now we restore it.
   2051  inst->setOpcode(op_beq);
   2052 }
   2053 
   2054 void AssemblerMIPSShared::ToggleToCmp(CodeLocationLabel inst_) {
   2055  InstImm* inst = (InstImm*)inst_.raw();
   2056 
   2057  // toggledJump is allways used for short jumps.
   2058  MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift));
   2059  // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset"
   2060  inst->setOpcode(op_andi);
   2061 }
   2062 
   2063 void AssemblerMIPSShared::UpdateLuiOriValue(Instruction* inst0,
   2064                                            Instruction* inst1,
   2065                                            uint32_t value) {
   2066  MOZ_ASSERT(inst0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
   2067  MOZ_ASSERT(inst1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
   2068 
   2069  ((InstImm*)inst0)->setImm16(Imm16::Upper(Imm32(value)));
   2070  ((InstImm*)inst1)->setImm16(Imm16::Lower(Imm32(value)));
   2071 }
   2072 
   2073 #ifdef JS_JITSPEW
   2074 void AssemblerMIPSShared::decodeBranchInstAndSpew(InstImm branch) {
   2075  OpcodeField op = (OpcodeField)(branch.extractOpcode() << OpcodeShift);
   2076  uint32_t rt_id;
   2077  uint32_t rs_id;
   2078  uint32_t immi = branch.extractImm16Value();
   2079  uint32_t fcc;
   2080  switch (op) {
   2081    case op_beq:
   2082      rt_id = branch.extractRT();
   2083      rs_id = branch.extractRS();
   2084      spew("beq    %3s,%3s,0x%x", Registers::GetName(rs_id),
   2085           Registers::GetName(rt_id), (int32_t(immi << 18) >> 16) + 4);
   2086      break;
   2087    case op_bne:
   2088      rt_id = branch.extractRT();
   2089      rs_id = branch.extractRS();
   2090      spew("bne    %3s,%3s,0x%x", Registers::GetName(rs_id),
   2091           Registers::GetName(rt_id), (int32_t(immi << 18) >> 16) + 4);
   2092      break;
   2093    case op_bgtz:
   2094      rs_id = branch.extractRS();
   2095      spew("bgt    %3s,  0,0x%x", Registers::GetName(rs_id),
   2096           (int32_t(immi << 18) >> 16) + 4);
   2097      break;
   2098    case op_blez:
   2099      rs_id = branch.extractRS();
   2100      spew("ble    %3s,  0,0x%x", Registers::GetName(rs_id),
   2101           (int32_t(immi << 18) >> 16) + 4);
   2102      break;
   2103    case op_regimm:
   2104      rt_id = branch.extractRT();
   2105      if (rt_id == (rt_bltz >> RTShift)) {
   2106        rs_id = branch.extractRS();
   2107        spew("blt   %3s,  0,0x%x", Registers::GetName(rs_id),
   2108             (int32_t(immi << 18) >> 16) + 4);
   2109      } else if (rt_id == (rt_bgez >> RTShift)) {
   2110        rs_id = branch.extractRS();
   2111        spew("bge   %3s,  0,0x%x", Registers::GetName(rs_id),
   2112             (int32_t(immi << 18) >> 16) + 4);
   2113      } else {
   2114        MOZ_CRASH("Error disassemble branch.");
   2115      }
   2116      break;
   2117    case op_cop1:
   2118      MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
   2119      rt_id = branch.extractRT();
   2120      fcc = branch.extractBitField(FCccShift + FCccBits - 1, FCccShift);
   2121      if (rt_id & 0x1) {
   2122        spew("bc1t  FCC%d, 0x%x", fcc, (int32_t(immi << 18) >> 16) + 4);
   2123      } else {
   2124        spew("bc1f  FCC%d, 0x%x", fcc, (int32_t(immi << 18) >> 16) + 4);
   2125      }
   2126      break;
   2127    default:
   2128      MOZ_CRASH("Error disassemble branch.");
   2129  }
   2130 }
   2131 #endif
   2132 
   2133 UseScratchRegisterScope::UseScratchRegisterScope(AssemblerMIPSShared& assembler)
   2134    : available_(assembler.GetScratchRegisterList()),
   2135      old_available_(*available_) {}
   2136 
   2137 UseScratchRegisterScope::UseScratchRegisterScope(AssemblerMIPSShared* assembler)
   2138    : available_(assembler->GetScratchRegisterList()),
   2139      old_available_(*available_) {}
   2140 
   2141 UseScratchRegisterScope::~UseScratchRegisterScope() {
   2142  *available_ = old_available_;
   2143 }
   2144 
   2145 Register UseScratchRegisterScope::Acquire() {
   2146  MOZ_ASSERT(available_ != nullptr);
   2147  MOZ_ASSERT(!available_->empty());
   2148  Register index = GeneralRegisterSet::FirstRegister(available_->bits());
   2149  available_->takeRegisterIndex(index);
   2150  return index;
   2151 }
   2152 
   2153 void UseScratchRegisterScope::Release(const Register& reg) {
   2154  MOZ_ASSERT(available_ != nullptr);
   2155  MOZ_ASSERT(old_available_.hasRegisterIndex(reg));
   2156  MOZ_ASSERT(!available_->hasRegisterIndex(reg));
   2157  Include(GeneralRegisterSet(1 << reg.code()));
   2158 }
   2159 
   2160 bool UseScratchRegisterScope::hasAvailable() const {
   2161  return (available_->size()) != 0;
   2162 }