Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/jit/mips-shared/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 77 kB image not shown  

Quelle  Assembler-mips-shared.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "jit/mips-shared/Assembler-mips-shared.h"

#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"

#include "gc/Marking.h"
#include "jit/ExecutableAllocator.h"
#include "vm/Realm.h"

using mozilla::DebugOnly;

using namespace js;
using namespace js::jit;

// Encode a standard register when it is being used as rd, the rs, and
// an extra register(rt). These should never be called with an InvalidReg.
uint32_t js::jit::RS(Register r) {
  MOZ_ASSERT((r.code() & ~RegMask) == 0);
  return r.code() << RSShift;
}

uint32_t js::jit::RT(Register r) {
  MOZ_ASSERT((r.code() & ~RegMask) == 0);
  return r.code() << RTShift;
}

uint32_t js::jit::RD(Register r) {
  MOZ_ASSERT((r.code() & ~RegMask) == 0);
  return r.code() << RDShift;
}

uint32_t js::jit::RZ(Register r) {
  MOZ_ASSERT((r.code() & ~RegMask) == 0);
  return r.code() << RZShift;
}

uint32_t js::jit::SA(uint32_t value) {
  MOZ_ASSERT(value < 32);
  return value << SAShift;
}

uint32_t js::jit::FS(uint32_t value) {
  MOZ_ASSERT(value < 32);
  return value << FSShift;
}

Register js::jit::toRS(Instruction& i) {
  return Register::FromCode((i.encode() & RSMask) >> RSShift);
}

Register js::jit::toRT(Instruction& i) {
  return Register::FromCode((i.encode() & RTMask) >> RTShift);
}

Register js::jit::toRD(Instruction& i) {
  return Register::FromCode((i.encode() & RDMask) >> RDShift);
}

Register js::jit::toR(Instruction& i) {
  return Register::FromCode(i.encode() & RegMask);
}

void InstImm::extractImm16(BOffImm16* dest) { *dest = BOffImm16(*this); }

void AssemblerMIPSShared::finish() {
  MOZ_ASSERT(!isFinished);
  isFinished = true;
}

bool AssemblerMIPSShared::appendRawCode(const uint8_t* code, size_t numBytes) {
  return m_buffer.appendRawCode(code, numBytes);
}

bool AssemblerMIPSShared::reserve(size_t size) {
  // This buffer uses fixed-size chunks so there's no point in reserving
  // now vs. on-demand.
  return !oom();
}

bool AssemblerMIPSShared::swapBuffer(wasm::Bytes& bytes) {
  // For now, specialize to the one use case. As long as wasm::Bytes is a
  // Vector, not a linked-list of chunks, there's not much we can do other
  // than copy.
  MOZ_ASSERT(bytes.empty());
  if (!bytes.resize(bytesNeeded())) {
    return false;
  }
  m_buffer.executableCopy(bytes.begin());
  return true;
}

void AssemblerMIPSShared::copyJumpRelocationTable(uint8_t* dest) {
  if (jumpRelocations_.length()) {
    memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
  }
}

void AssemblerMIPSShared::copyDataRelocationTable(uint8_t* dest) {
  if (dataRelocations_.length()) {
    memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
  }
}

AssemblerMIPSShared::Condition AssemblerMIPSShared::InvertCondition(
    Condition cond) {
  switch (cond) {
    case Equal:
      return NotEqual;
    case NotEqual:
      return Equal;
    case Zero:
      return NonZero;
    case NonZero:
      return Zero;
    case LessThan:
      return GreaterThanOrEqual;
    case LessThanOrEqual:
      return GreaterThan;
    case GreaterThan:
      return LessThanOrEqual;
    case GreaterThanOrEqual:
      return LessThan;
    case Above:
      return BelowOrEqual;
    case AboveOrEqual:
      return Below;
    case Below:
      return AboveOrEqual;
    case BelowOrEqual:
      return Above;
    case Signed:
      return NotSigned;
    case NotSigned:
      return Signed;
    default:
      MOZ_CRASH("unexpected condition");
  }
}

AssemblerMIPSShared::DoubleCondition AssemblerMIPSShared::InvertCondition(
    DoubleCondition cond) {
  switch (cond) {
    case DoubleOrdered:
      return DoubleUnordered;
    case DoubleEqual:
      return DoubleNotEqualOrUnordered;
    case DoubleNotEqual:
      return DoubleEqualOrUnordered;
    case DoubleGreaterThan:
      return DoubleLessThanOrEqualOrUnordered;
    case DoubleGreaterThanOrEqual:
      return DoubleLessThanOrUnordered;
    case DoubleLessThan:
      return DoubleGreaterThanOrEqualOrUnordered;
    case DoubleLessThanOrEqual:
      return DoubleGreaterThanOrUnordered;
    case DoubleUnordered:
      return DoubleOrdered;
    case DoubleEqualOrUnordered:
      return DoubleNotEqual;
    case DoubleNotEqualOrUnordered:
      return DoubleEqual;
    case DoubleGreaterThanOrUnordered:
      return DoubleLessThanOrEqual;
    case DoubleGreaterThanOrEqualOrUnordered:
      return DoubleLessThan;
    case DoubleLessThanOrUnordered:
      return DoubleGreaterThanOrEqual;
    case DoubleLessThanOrEqualOrUnordered:
      return DoubleGreaterThan;
    default:
      MOZ_CRASH("unexpected condition");
  }
}

BOffImm16::BOffImm16(InstImm inst) : data(inst.encode() & Imm16Mask) {}

Instruction* BOffImm16::getDest(Instruction* src) const {
  return &src[(((int32_t)data << 16) >> 16) + 1];
}

bool AssemblerMIPSShared::oom() const {
  return AssemblerShared::oom() || m_buffer.oom() || jumpRelocations_.oom() ||
         dataRelocations_.oom();
}

// Size of the instruction stream, in bytes.
size_t AssemblerMIPSShared::size() const { return m_buffer.size(); }

// Size of the relocation table, in bytes.
size_t AssemblerMIPSShared::jumpRelocationTableBytes() const {
  return jumpRelocations_.length();
}

size_t AssemblerMIPSShared::dataRelocationTableBytes() const {
  return dataRelocations_.length();
}

// Size of the data table, in bytes.
size_t AssemblerMIPSShared::bytesNeeded() const {
  return size() + jumpRelocationTableBytes() + dataRelocationTableBytes();
}

// write a blob of binary into the instruction stream
BufferOffset AssemblerMIPSShared::writeInst(uint32_t x, uint32_t* dest) {
  MOZ_ASSERT(hasCreator());
  if (dest == nullptr) {
    return m_buffer.putInt(x);
  }

  WriteInstStatic(x, dest);
  return BufferOffset();
}

void AssemblerMIPSShared::WriteInstStatic(uint32_t x, uint32_t* dest) {
  MOZ_ASSERT(dest != nullptr);
  *dest = x;
}

BufferOffset AssemblerMIPSShared::haltingAlign(int alignment) {
  // TODO: Implement a proper halting align.
  return nopAlign(alignment);
}

BufferOffset AssemblerMIPSShared::nopAlign(int alignment) {
  BufferOffset ret;
  MOZ_ASSERT(m_buffer.isAligned(4));
  if (alignment == 8) {
    if (!m_buffer.isAligned(alignment)) {
      BufferOffset tmp = as_nop();
      if (!ret.assigned()) {
        ret = tmp;
      }
    }
  } else {
    MOZ_ASSERT((alignment & (alignment - 1)) == 0);
    while (size() & (alignment - 1)) {
      BufferOffset tmp = as_nop();
      if (!ret.assigned()) {
        ret = tmp;
      }
    }
  }
  return ret;
}

BufferOffset AssemblerMIPSShared::as_nop() {
  spew("nop");
  return writeInst(op_special | ff_sll);
}

// Logical operations.
BufferOffset AssemblerMIPSShared::as_and(Register rd, Register rs,
                                         Register rt) {
  spew("and %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode());
}

BufferOffset AssemblerMIPSShared::as_or(Register rd, Register rs, Register rt) {
  spew("or %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode());
}

BufferOffset AssemblerMIPSShared::as_xor(Register rd, Register rs,
                                         Register rt) {
  spew("xor %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode());
}

BufferOffset AssemblerMIPSShared::as_nor(Register rd, Register rs,
                                         Register rt) {
  spew("nor %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode());
}

BufferOffset AssemblerMIPSShared::as_andi(Register rd, Register rs, int32_t j) {
  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
  spew("andi %3s,%3s,0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_ori(Register rd, Register rs, int32_t j) {
  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
  spew("ori %3s,%3s,0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_xori(Register rd, Register rs, int32_t j) {
  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
  spew("xori %3s,%3s,0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_lui(Register rd, int32_t j) {
  MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
  spew("lui %3s,0x%x", rd.name(), j);
  return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode());
}

// Branch and jump instructions
BufferOffset AssemblerMIPSShared::as_bal(BOffImm16 off) {
  spew("bal %d", off.decode());
  BufferOffset bo =
      writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode());
  return bo;
}

BufferOffset AssemblerMIPSShared::as_b(BOffImm16 off) {
  spew("b %d", off.decode());
  BufferOffset bo = writeInst(InstImm(op_beq, zero, zero, off).encode());
  return bo;
}

InstImm AssemblerMIPSShared::getBranchCode(JumpOrCall jumpOrCall) {
  if (jumpOrCall == BranchIsCall) {
    return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
  }

  return InstImm(op_beq, zero, zero, BOffImm16(0));
}

InstImm AssemblerMIPSShared::getBranchCode(Register s, Register t,
                                           Condition c) {
  MOZ_ASSERT(c == AssemblerMIPSShared::Equal ||
             c == AssemblerMIPSShared::NotEqual);
  return InstImm(c == AssemblerMIPSShared::Equal ? op_beq : op_bne, s, t,
                 BOffImm16(0));
}

InstImm AssemblerMIPSShared::getBranchCode(Register s, Condition c) {
  switch (c) {
    case AssemblerMIPSShared::Equal:
    case AssemblerMIPSShared::Zero:
    case AssemblerMIPSShared::BelowOrEqual:
      return InstImm(op_beq, s, zero, BOffImm16(0));
    case AssemblerMIPSShared::NotEqual:
    case AssemblerMIPSShared::NonZero:
    case AssemblerMIPSShared::Above:
      return InstImm(op_bne, s, zero, BOffImm16(0));
    case AssemblerMIPSShared::GreaterThan:
      return InstImm(op_bgtz, s, zero, BOffImm16(0));
    case AssemblerMIPSShared::GreaterThanOrEqual:
    case AssemblerMIPSShared::NotSigned:
      return InstImm(op_regimm, s, rt_bgez, BOffImm16(0));
    case AssemblerMIPSShared::LessThan:
    case AssemblerMIPSShared::Signed:
      return InstImm(op_regimm, s, rt_bltz, BOffImm16(0));
    case AssemblerMIPSShared::LessThanOrEqual:
      return InstImm(op_blez, s, zero, BOffImm16(0));
    default:
      MOZ_CRASH("Condition not supported.");
  }
}

InstImm AssemblerMIPSShared::getBranchCode(FloatTestKind testKind,
                                           FPConditionBit fcc) {
  MOZ_ASSERT(!(fcc && FccMask));
#ifdef MIPSR6
  RSField rsField = ((testKind == TestForTrue ? rs_t : rs_f));

  return InstImm(op_cop1, rsField, FloatRegisters::f24 << 16, BOffImm16(0));
#else
  uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift))
                     << RTShift;

  return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0));
#endif
}

BufferOffset AssemblerMIPSShared::as_j(JOffImm26 off) {
  spew("j 0x%x", off.decode());
  BufferOffset bo = writeInst(InstJump(op_j, off).encode());
  return bo;
}
BufferOffset AssemblerMIPSShared::as_jal(JOffImm26 off) {
  spew("jal 0x%x", off.decode());
  BufferOffset bo = writeInst(InstJump(op_jal, off).encode());
  return bo;
}

BufferOffset AssemblerMIPSShared::as_jr(Register rs) {
  spew("jr %3s", rs.name());
#ifdef MIPSR6
  BufferOffset bo =
      writeInst(InstReg(op_special, rs, zero, zero, ff_jalr).encode());
#else
  BufferOffset bo =
      writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode());
#endif
  return bo;
}
BufferOffset AssemblerMIPSShared::as_jalr(Register rs) {
  spew("jalr %3s", rs.name());
  BufferOffset bo =
      writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode());
  return bo;
}

// Arithmetic instructions
BufferOffset AssemblerMIPSShared::as_addu(Register rd, Register rs,
                                          Register rt) {
  spew("addu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode());
}

BufferOffset AssemblerMIPSShared::as_addiu(Register rd, Register rs,
                                           int32_t j) {
  MOZ_ASSERT(Imm16::IsInSignedRange(j));
  spew("addiu %3s,%3s,0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_daddu(Register rd, Register rs,
                                           Register rt) {
  spew("daddu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode());
}

BufferOffset AssemblerMIPSShared::as_daddiu(Register rd, Register rs,
                                            int32_t j) {
  MOZ_ASSERT(Imm16::IsInSignedRange(j));
  spew("daddiu %3s,%3s,0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_subu(Register rd, Register rs,
                                          Register rt) {
  spew("subu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
}

BufferOffset AssemblerMIPSShared::as_dsubu(Register rd, Register rs,
                                           Register rt) {
  spew("dsubu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode());
}

BufferOffset AssemblerMIPSShared::as_mult(Register rs, Register rt) {
  spew("mult %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_mult).encode());
}

BufferOffset AssemblerMIPSShared::as_multu(Register rs, Register rt) {
  spew("multu %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
}

BufferOffset AssemblerMIPSShared::as_dmult(Register rs, Register rt) {
  spew("dmult %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode());
}

BufferOffset AssemblerMIPSShared::as_dmultu(Register rs, Register rt) {
  spew("dmultu %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode());
}

BufferOffset AssemblerMIPSShared::as_div(Register rs, Register rt) {
  spew("div %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_div).encode());
}

BufferOffset AssemblerMIPSShared::as_div(Register rd, Register rs,
                                         Register rt) {
  spew("div %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_div).encode());
}

BufferOffset AssemblerMIPSShared::as_divu(Register rs, Register rt) {
  spew("divu %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
}

BufferOffset AssemblerMIPSShared::as_divu(Register rd, Register rs,
                                          Register rt) {
  spew("divu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_divu).encode());
}

BufferOffset AssemblerMIPSShared::as_mod(Register rd, Register rs,
                                         Register rt) {
  spew("mod %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_mod).encode());
}

BufferOffset AssemblerMIPSShared::as_modu(Register rd, Register rs,
                                          Register rt) {
  spew("modu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_modu).encode());
}

BufferOffset AssemblerMIPSShared::as_ddiv(Register rs, Register rt) {
  spew("ddiv %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode());
}

BufferOffset AssemblerMIPSShared::as_ddiv(Register rd, Register rs,
                                          Register rt) {
  spew("ddiv %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddiv).encode());
}

BufferOffset AssemblerMIPSShared::as_ddivu(Register rs, Register rt) {
  spew("ddivu %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode());
}

BufferOffset AssemblerMIPSShared::as_ddivu(Register rd, Register rs,
                                           Register rt) {
  spew("ddivu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddivu).encode());
}

BufferOffset AssemblerMIPSShared::as_mul(Register rd, Register rs,
                                         Register rt) {
  spew("mul %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mul).encode());
#else
  return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_muh(Register rd, Register rs,
                                         Register rt) {
  spew("muh %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muh).encode());
}

BufferOffset AssemblerMIPSShared::as_mulu(Register rd, Register rs,
                                          Register rt) {
  spew("mulu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mulu).encode());
}

BufferOffset AssemblerMIPSShared::as_muhu(Register rd, Register rs,
                                          Register rt) {
  spew("muhu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muhu).encode());
}

BufferOffset AssemblerMIPSShared::as_dmul(Register rd, Register rs,
                                          Register rt) {
  spew("dmul %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmul).encode());
}

BufferOffset AssemblerMIPSShared::as_dmuh(Register rd, Register rs,
                                          Register rt) {
  spew("dmuh %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuh).encode());
}

BufferOffset AssemblerMIPSShared::as_dmulu(Register rd, Register rt,
                                           Register rs) {
  spew("dmulu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmulu).encode());
}

BufferOffset AssemblerMIPSShared::as_dmuhu(Register rd, Register rt,
                                           Register rs) {
  spew("dmuhu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuhu).encode());
}

BufferOffset AssemblerMIPSShared::as_dmod(Register rd, Register rs,
                                          Register rt) {
  spew("dmod %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmod).encode());
}

BufferOffset AssemblerMIPSShared::as_dmodu(Register rd, Register rs,
                                           Register rt) {
  spew("dmodu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmodu).encode());
}

BufferOffset AssemblerMIPSShared::as_madd(Register rs, Register rt) {
  spew("madd %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special2, rs, rt, ff_madd).encode());
}

BufferOffset AssemblerMIPSShared::as_maddu(Register rs, Register rt) {
  spew("maddu %3s,%3s", rs.name(), rt.name());
  return writeInst(InstReg(op_special2, rs, rt, ff_maddu).encode());
}

// Shift instructions
BufferOffset AssemblerMIPSShared::as_sll(Register rd, Register rt,
                                         uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("sll %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
}

BufferOffset AssemblerMIPSShared::as_dsll(Register rd, Register rt,
                                          uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("dsll %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode());
}

BufferOffset AssemblerMIPSShared::as_dsll32(Register rd, Register rt,
                                            uint16_t sa) {
  MOZ_ASSERT(31 < sa && sa < 64);
  spew("dsll32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
  return writeInst(
      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode());
}

BufferOffset AssemblerMIPSShared::as_sllv(Register rd, Register rt,
                                          Register rs) {
  spew("sllv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
}

BufferOffset AssemblerMIPSShared::as_dsllv(Register rd, Register rt,
                                           Register rs) {
  spew("dsllv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode());
}

BufferOffset AssemblerMIPSShared::as_srl(Register rd, Register rt,
                                         uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("srl %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
}

BufferOffset AssemblerMIPSShared::as_dsrl(Register rd, Register rt,
                                          uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("dsrl %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode());
}

BufferOffset AssemblerMIPSShared::as_dsrl32(Register rd, Register rt,
                                            uint16_t sa) {
  MOZ_ASSERT(31 < sa && sa < 64);
  spew("dsrl32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
  return writeInst(
      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode());
}

BufferOffset AssemblerMIPSShared::as_srlv(Register rd, Register rt,
                                          Register rs) {
  spew("srlv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
}

BufferOffset AssemblerMIPSShared::as_dsrlv(Register rd, Register rt,
                                           Register rs) {
  spew("dsrlv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode());
}

BufferOffset AssemblerMIPSShared::as_sra(Register rd, Register rt,
                                         uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("sra %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
}

BufferOffset AssemblerMIPSShared::as_dsra(Register rd, Register rt,
                                          uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("dsra %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode());
}

BufferOffset AssemblerMIPSShared::as_dsra32(Register rd, Register rt,
                                            uint16_t sa) {
  MOZ_ASSERT(31 < sa && sa < 64);
  spew("dsra32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
  return writeInst(
      InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode());
}

BufferOffset AssemblerMIPSShared::as_srav(Register rd, Register rt,
                                          Register rs) {
  spew("srav %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
}

BufferOffset AssemblerMIPSShared::as_dsrav(Register rd, Register rt,
                                           Register rs) {
  spew("dsrav %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode());
}

BufferOffset AssemblerMIPSShared::as_rotr(Register rd, Register rt,
                                          uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("rotr %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
}

BufferOffset AssemblerMIPSShared::as_drotr(Register rd, Register rt,
                                           uint16_t sa) {
  MOZ_ASSERT(sa < 32);
  spew("drotr %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode());
}

BufferOffset AssemblerMIPSShared::as_drotr32(Register rd, Register rt,
                                             uint16_t sa) {
  MOZ_ASSERT(31 < sa && sa < 64);
  spew("drotr32%3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
  MOZ_ASSERT(hasR2());
  return writeInst(
      InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode());
}

BufferOffset AssemblerMIPSShared::as_rotrv(Register rd, Register rt,
                                           Register rs) {
  spew("rotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
}

BufferOffset AssemblerMIPSShared::as_drotrv(Register rd, Register rt,
                                            Register rs) {
  spew("drotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode());
}

// Load and store instructions
BufferOffset AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off) {
  spew("lb %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lbu(Register rd, Register rs,
                                         int16_t off) {
  spew("lbu %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lh(Register rd, Register rs, int16_t off) {
  spew("lh %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lhu(Register rd, Register rs,
                                         int16_t off) {
  spew("lhu %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off) {
  spew("lw %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lwu(Register rd, Register rs,
                                         int16_t off) {
  spew("lwu %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lwl(Register rd, Register rs,
                                         int16_t off) {
  spew("lwl %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lwr(Register rd, Register rs,
                                         int16_t off) {
  spew("lwr %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off) {
  spew("ll %3s, (0x%x)%2s", rd.name(), off, rs.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special3, rs, rd, ff_ll).encode());
#else
  return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_lld(Register rd, Register rs,
                                         int16_t off) {
  spew("lld %3s, (0x%x)%2s", rd.name(), off, rs.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special3, rs, rd, ff_lld).encode());
#else
  return writeInst(InstImm(op_lld, rs, rd, Imm16(off)).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off) {
  spew("ld %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_ldl(Register rd, Register rs,
                                         int16_t off) {
  spew("ldl %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_ldr(Register rd, Register rs,
                                         int16_t off) {
  spew("ldr %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off) {
  spew("sb %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sh(Register rd, Register rs, int16_t off) {
  spew("sh %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sw(Register rd, Register rs, int16_t off) {
  spew("sw %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_swl(Register rd, Register rs,
                                         int16_t off) {
  spew("swl %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_swr(Register rd, Register rs,
                                         int16_t off) {
  spew("swr %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off) {
  spew("sc %3s, (0x%x)%2s", rd.name(), off, rs.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special3, rs, rd, ff_sc).encode());
#else
  return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_scd(Register rd, Register rs,
                                         int16_t off) {
#ifdef MIPSR6
  return writeInst(InstReg(op_special3, rs, rd, ff_scd).encode());
#else
  spew("scd %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_scd, rs, rd, Imm16(off)).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off) {
  spew("sd %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sdl(Register rd, Register rs,
                                         int16_t off) {
  spew("sdl %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sdr(Register rd, Register rs,
                                         int16_t off) {
  spew("sdr %3s, (0x%x)%2s", rd.name(), off, rs.name());
  return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_seleqz(Register rd, Register rs,
                                            Register rt) {
  spew("seleqz %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_seleqz).encode());
}

BufferOffset AssemblerMIPSShared::as_selnez(Register rd, Register rs,
                                            Register rt) {
  spew("selnez %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_selnez).encode());
}

BufferOffset AssemblerMIPSShared::as_gslbx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslbx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
}

BufferOffset AssemblerMIPSShared::as_gssbx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gssbx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
}

BufferOffset AssemblerMIPSShared::as_gslhx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslhx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
}

BufferOffset AssemblerMIPSShared::as_gsshx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsshx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
}

BufferOffset AssemblerMIPSShared::as_gslwx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslwx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
}

BufferOffset AssemblerMIPSShared::as_gsswx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsswx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
}

BufferOffset AssemblerMIPSShared::as_gsldx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsldx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
}

BufferOffset AssemblerMIPSShared::as_gssdx(Register rd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gssdx %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
  return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
}

BufferOffset AssemblerMIPSShared::as_gslq(Register rh, Register rl, Register rs,
                                          int16_t off) {
  MOZ_ASSERT(GSImm13::IsInRange(off));
  spew("gslq %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
  return writeInst(InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
}

BufferOffset AssemblerMIPSShared::as_gssq(Register rh, Register rl, Register rs,
                                          int16_t off) {
  MOZ_ASSERT(GSImm13::IsInRange(off));
  spew("gssq %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
  return writeInst(InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
}

// Move from HI/LO register.
BufferOffset AssemblerMIPSShared::as_mfhi(Register rd) {
  spew("mfhi %3s", rd.name());
  return writeInst(InstReg(op_special, rd, ff_mfhi).encode());
}

BufferOffset AssemblerMIPSShared::as_mflo(Register rd) {
  spew("mflo %3s", rd.name());
  return writeInst(InstReg(op_special, rd, ff_mflo).encode());
}

// Set on less than.
BufferOffset AssemblerMIPSShared::as_slt(Register rd, Register rs,
                                         Register rt) {
  spew("slt %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode());
}

BufferOffset AssemblerMIPSShared::as_sltu(Register rd, Register rs,
                                          Register rt) {
  spew("sltu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode());
}

BufferOffset AssemblerMIPSShared::as_slti(Register rd, Register rs, int32_t j) {
  MOZ_ASSERT(Imm16::IsInSignedRange(j));
  spew("slti %3s,%3s, 0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode());
}

BufferOffset AssemblerMIPSShared::as_sltiu(Register rd, Register rs,
                                           uint32_t j) {
  MOZ_ASSERT(Imm16::IsInSignedRange(int32_t(j)));
  spew("sltiu %3s,%3s, 0x%x", rd.name(), rs.name(), j);
  return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode());
}

// Conditional move.
BufferOffset AssemblerMIPSShared::as_movz(Register rd, Register rs,
                                          Register rt) {
  spew("movz %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode());
}

BufferOffset AssemblerMIPSShared::as_movn(Register rd, Register rs,
                                          Register rt) {
  spew("movn %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
  return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode());
}

BufferOffset AssemblerMIPSShared::as_movt(Register rd, Register rs,
                                          uint16_t cc) {
  Register rt;
  rt = Register::FromCode((cc & 0x7) << 2 | 1);
  spew("movt %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
  return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
}

BufferOffset AssemblerMIPSShared::as_movf(Register rd, Register rs,
                                          uint16_t cc) {
  Register rt;
  rt = Register::FromCode((cc & 0x7) << 2 | 0);
  spew("movf %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
  return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
}

// Bit twiddling.
BufferOffset AssemblerMIPSShared::as_clz(Register rd, Register rs) {
  spew("clz %3s,%3s", rd.name(), rs.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_clz).encode());
#else
  return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_dclz(Register rd, Register rs) {
  spew("dclz %3s,%3s", rd.name(), rs.name());
#ifdef MIPSR6
  return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_dclz).encode());
#else
  return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode());
#endif
}

BufferOffset AssemblerMIPSShared::as_wsbh(Register rd, Register rt) {
  spew("wsbh %3s,%3s", rd.name(), rt.name());
  return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_bshfl).encode());
}

BufferOffset AssemblerMIPSShared::as_dsbh(Register rd, Register rt) {
  spew("dsbh %3s,%3s", rd.name(), rt.name());
  return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_dbshfl).encode());
}

BufferOffset AssemblerMIPSShared::as_dshd(Register rd, Register rt) {
  spew("dshd %3s,%3s", rd.name(), rt.name());
  return writeInst(InstReg(op_special3, zero, rt, rd, 0x5, ff_dbshfl).encode());
}

BufferOffset AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos,
                                         uint16_t size) {
  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
             pos + size <= 32);
  Register rd;
  rd = Register::FromCode(pos + size - 1);
  spew("ins %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
}

BufferOffset AssemblerMIPSShared::as_dins(Register rt, Register rs,
                                          uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
             pos + size <= 32);
  Register rd;
  rd = Register::FromCode(pos + size - 1);
  spew("dins %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode());
}

BufferOffset AssemblerMIPSShared::as_dinsm(Register rt, Register rs,
                                           uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 &&
             pos + size <= 64);
  Register rd;
  rd = Register::FromCode(pos + size - 1 - 32);
  spew("dinsm %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode());
}

BufferOffset AssemblerMIPSShared::as_dinsu(Register rt, Register rs,
                                           uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 &&
             pos + size > 32 && pos + size <= 64);
  Register rd;
  rd = Register::FromCode(pos + size - 1 - 32);
  spew("dinsu %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(
      InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode());
}

BufferOffset AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos,
                                         uint16_t size) {
  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
             pos + size <= 32);
  Register rd;
  rd = Register::FromCode(size - 1);
  spew("ext %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
}

// Sign extend
BufferOffset AssemblerMIPSShared::as_seb(Register rd, Register rt) {
  spew("seb %3s,%3s", rd.name(), rt.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode());
}

BufferOffset AssemblerMIPSShared::as_seh(Register rd, Register rt) {
  spew("seh %3s,%3s", rd.name(), rt.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode());
}

BufferOffset AssemblerMIPSShared::as_dext(Register rt, Register rs,
                                          uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
             pos + size <= 63);
  Register rd;
  rd = Register::FromCode(size - 1);
  spew("dext %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode());
}

BufferOffset AssemblerMIPSShared::as_dextm(Register rt, Register rs,
                                           uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 &&
             pos + size <= 64);
  Register rd;
  rd = Register::FromCode(size - 1 - 32);
  spew("dextm %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode());
}

BufferOffset AssemblerMIPSShared::as_dextu(Register rt, Register rs,
                                           uint16_t pos, uint16_t size) {
  MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 &&
             pos + size > 32 && pos + size <= 64);
  Register rd;
  rd = Register::FromCode(size - 1);
  spew("dextu %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
  MOZ_ASSERT(hasR2());
  return writeInst(
      InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode());
}

// FP instructions
BufferOffset AssemblerMIPSShared::as_ldc1(FloatRegister ft, Register base,
                                          int32_t off) {
  MOZ_ASSERT(Imm16::IsInSignedRange(off));
  spew("ldc1 %3s, (0x%x)%2s", ft.name(), off, base.name());
  return writeInst(InstImm(op_ldc1, base, ft, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_sdc1(FloatRegister ft, Register base,
                                          int32_t off) {
  MOZ_ASSERT(Imm16::IsInSignedRange(off));
  spew("sdc1 %3s, (0x%x)%2s", ft.name(), off, base.name());
  return writeInst(InstImm(op_sdc1, base, ft, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_lwc1(FloatRegister ft, Register base,
                                          int32_t off) {
  MOZ_ASSERT(Imm16::IsInSignedRange(off));
  spew("lwc1 %3s, (0x%x)%2s", ft.name(), off, base.name());
  return writeInst(InstImm(op_lwc1, base, ft, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_swc1(FloatRegister ft, Register base,
                                          int32_t off) {
  MOZ_ASSERT(Imm16::IsInSignedRange(off));
  spew("swc1 %3s, (0x%x)%2s", ft.name(), off, base.name());
  return writeInst(InstImm(op_swc1, base, ft, Imm16(off)).encode());
}

BufferOffset AssemblerMIPSShared::as_gsldl(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsldl %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gsldr(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsldr %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gssdl(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gssdl %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gssdr(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gssdr %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gslsl(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslsl %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gslsr(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslsr %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gsssl(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsssl %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gsssr(FloatRegister fd, Register base,
                                           int32_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsssr %3s, (0x%x)%2s", fd.name(), off, base.name());
  return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gslsx(FloatRegister fd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gslsx %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
  return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gsssx(FloatRegister fd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsssx %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
  return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gsldx(FloatRegister fd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gsldx %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
  return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gssdx(FloatRegister fd, Register rs,
                                           Register ri, int16_t off) {
  MOZ_ASSERT(Imm8::IsInSignedRange(off));
  spew("gssdx %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
  return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gslq(FloatRegister rh, FloatRegister rl,
                                          Register rs, int16_t off) {
  MOZ_ASSERT(GSImm13::IsInRange(off));
  spew("gslq %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
  return writeInst(
      InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
}

BufferOffset AssemblerMIPSShared::as_gssq(FloatRegister rh, FloatRegister rl,
                                          Register rs, int16_t off) {
  MOZ_ASSERT(GSImm13::IsInRange(off));
  spew("gssq %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
  return writeInst(
      InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
}

BufferOffset AssemblerMIPSShared::as_movs(FloatRegister fd, FloatRegister fs) {
  spew("mov.s %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs) {
  spew("mov.d %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_ctc1(Register rt, FPControl fc) {
  spew("ctc1 %3s,%d", rt.name(), fc);
  return writeInst(InstReg(op_cop1, rs_ctc1, rt, (uint32_t)fc).encode());
}

BufferOffset AssemblerMIPSShared::as_cfc1(Register rt, FPControl fc) {
  spew("cfc1 %3s,%d", rt.name(), fc);
  return writeInst(InstReg(op_cop1, rs_cfc1, rt, (uint32_t)fc).encode());
}

BufferOffset AssemblerMIPSShared::as_mtc1(Register rt, FloatRegister fs) {
  spew("mtc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode());
}

BufferOffset AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs) {
  spew("mfc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
}

BufferOffset AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs) {
  spew("mthc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode());
}

BufferOffset AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs) {
  spew("mfhc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode());
}

BufferOffset AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs) {
  spew("dmtc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode());
}

BufferOffset AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs) {
  spew("dmfc1 %3s,%3s", rt.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode());
}

// FP convert instructions
BufferOffset AssemblerMIPSShared::as_ceilws(FloatRegister fd,
                                            FloatRegister fs) {
  spew("ceil.w.s%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_floorws(FloatRegister fd,
                                             FloatRegister fs) {
  spew("floor.w.s%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_roundws(FloatRegister fd,
                                             FloatRegister fs) {
  spew("round.w.s%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_truncws(FloatRegister fd,
                                             FloatRegister fs) {
  spew("trunc.w.s%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_truncls(FloatRegister fd,
                                             FloatRegister fs) {
  spew("trunc.l.s%3s,%3s", fd.name(), fs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(
      InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_l_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_ceilwd(FloatRegister fd,
                                            FloatRegister fs) {
  spew("ceil.w.d%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_floorwd(FloatRegister fd,
                                             FloatRegister fs) {
  spew("floor.w.d%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_roundwd(FloatRegister fd,
                                             FloatRegister fs) {
  spew("round.w.d%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_truncwd(FloatRegister fd,
                                             FloatRegister fs) {
  spew("trunc.w.d%3s,%3s", fd.name(), fs.name());
  return writeInst(
      InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_truncld(FloatRegister fd,
                                             FloatRegister fs) {
  spew("trunc.l.d%3s,%3s", fd.name(), fs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(
      InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_l_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs) {
  spew("cvt.d.l%3s,%3s", fd.name(), fs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs) {
  spew("cvt.d.s%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtdw(FloatRegister fd, FloatRegister fs) {
  spew("cvt.d.w%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtsd(FloatRegister fd, FloatRegister fs) {
  spew("cvt.s.d%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtsl(FloatRegister fd, FloatRegister fs) {
  spew("cvt.s.l%3s,%3s", fd.name(), fs.name());
  MOZ_ASSERT(hasR2());
  return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_s_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtsw(FloatRegister fd, FloatRegister fs) {
  spew("cvt.s.w%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtwd(FloatRegister fd, FloatRegister fs) {
  spew("cvt.w.d%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_cvtws(FloatRegister fd, FloatRegister fs) {
  spew("cvt.w.s%3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode());
}

// FP arithmetic instructions
BufferOffset AssemblerMIPSShared::as_adds(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("add.s %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_addd(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("add.d %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_subs(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("sub.s %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_subd(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("sub.d %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_abss(FloatRegister fd, FloatRegister fs) {
  spew("abs.s %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_absd(FloatRegister fd, FloatRegister fs) {
  spew("abs.d %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_negs(FloatRegister fd, FloatRegister fs) {
  spew("neg.s %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_negd(FloatRegister fd, FloatRegister fs) {
  spew("neg.d %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_muls(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("mul.s %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_muld(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("mul.d %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_divs(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("div.s %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_divd(FloatRegister fd, FloatRegister fs,
                                          FloatRegister ft) {
  spew("divd.d %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
  return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_sqrts(FloatRegister fd, FloatRegister fs) {
  spew("sqrts %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode());
}

BufferOffset AssemblerMIPSShared::as_sqrtd(FloatRegister fd, FloatRegister fs) {
  spew("sqrtd %3s,%3s", fd.name(), fs.name());
  return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode());
}

// FP compare instructions
BufferOffset AssemblerMIPSShared::as_cf(FloatFormat fmt, FloatRegister fs,
                                        FloatRegister ft, FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.f.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
#endif
  } else {
    spew("c.f.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_cun(FloatFormat fmt, FloatRegister fs,
                                         FloatRegister ft, FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.un.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
#endif
  } else {
    spew("c.un.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_ceq(FloatFormat fmt, FloatRegister fs,
                                         FloatRegister ft, FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.eq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
#endif
  } else {
    spew("c.eq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_cueq(FloatFormat fmt, FloatRegister fs,
                                          FloatRegister ft,
                                          FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.ueq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
#endif
  } else {
    spew("c.ueq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_colt(FloatFormat fmt, FloatRegister fs,
                                          FloatRegister ft,
                                          FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.olt.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
#endif
  } else {
    spew("c.olt.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_cult(FloatFormat fmt, FloatRegister fs,
                                          FloatRegister ft,
                                          FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.ult.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
#endif
  } else {
    spew("c.ult.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
#endif
  }
}

BufferOffset AssemblerMIPSShared::as_cole(FloatFormat fmt, FloatRegister fs,
                                          FloatRegister ft,
                                          FPConditionBit fcc) {
  if (fmt == DoubleFloat) {
    spew("c.ole.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
        InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ole_fmt)
            .encode());
#else
    return writeInst(
        InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
#endif
  } else {
    spew("c.ole.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
#ifdef MIPSR6
    return writeInst(
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=98 G=94

¤ Dauer der Verarbeitung: 0.41 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.