js/src/jit/mips/Assembler-mips.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/mips/Assembler-mips.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1529 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/mips/Assembler-mips.h"
    1.11 +
    1.12 +#include "mozilla/DebugOnly.h"
    1.13 +#include "mozilla/MathAlgorithms.h"
    1.14 +
    1.15 +#include "jscompartment.h"
    1.16 +#include "jsutil.h"
    1.17 +
    1.18 +#include "assembler/jit/ExecutableAllocator.h"
    1.19 +#include "gc/Marking.h"
    1.20 +#include "jit/JitCompartment.h"
    1.21 +
    1.22 +using mozilla::DebugOnly;
    1.23 +
    1.24 +using namespace js;
    1.25 +using namespace js::jit;
    1.26 +
    1.27 +ABIArgGenerator::ABIArgGenerator()
    1.28 +  : usedArgSlots_(0),
    1.29 +    firstArgFloat(false),
    1.30 +    current_()
    1.31 +{}
    1.32 +
    1.33 +ABIArg
    1.34 +ABIArgGenerator::next(MIRType type)
    1.35 +{
    1.36 +    MOZ_ASSUME_UNREACHABLE("NYI");
    1.37 +    return ABIArg();
    1.38 +}
    1.39 +const Register ABIArgGenerator::NonArgReturnVolatileReg0 = t0;
    1.40 +const Register ABIArgGenerator::NonArgReturnVolatileReg1 = t1;
    1.41 +
    1.42 +// Encode a standard register when it is being used as rd, the rs, and
    1.43 +// an extra register(rt). These should never be called with an InvalidReg.
    1.44 +uint32_t
    1.45 +js::jit::RS(Register r)
    1.46 +{
    1.47 +    JS_ASSERT((r.code() & ~RegMask) == 0);
    1.48 +    return r.code() << RSShift;
    1.49 +}
    1.50 +
    1.51 +uint32_t
    1.52 +js::jit::RT(Register r)
    1.53 +{
    1.54 +    JS_ASSERT((r.code() & ~RegMask) == 0);
    1.55 +    return r.code() << RTShift;
    1.56 +}
    1.57 +
    1.58 +uint32_t
    1.59 +js::jit::RT(FloatRegister r)
    1.60 +{
    1.61 +    JS_ASSERT(r.code() < FloatRegisters::Total);
    1.62 +    return r.code() << RTShift;
    1.63 +}
    1.64 +
    1.65 +uint32_t
    1.66 +js::jit::RD(Register r)
    1.67 +{
    1.68 +    JS_ASSERT((r.code() & ~RegMask) == 0);
    1.69 +    return r.code() << RDShift;
    1.70 +}
    1.71 +
    1.72 +uint32_t
    1.73 +js::jit::RD(FloatRegister r)
    1.74 +{
    1.75 +    JS_ASSERT(r.code() < FloatRegisters::Total);
    1.76 +    return r.code() << RDShift;
    1.77 +}
    1.78 +
    1.79 +uint32_t
    1.80 +js::jit::SA(uint32_t value)
    1.81 +{
    1.82 +    JS_ASSERT(value < 32);
    1.83 +    return value << SAShift;
    1.84 +}
    1.85 +
    1.86 +uint32_t
    1.87 +js::jit::SA(FloatRegister r)
    1.88 +{
    1.89 +    JS_ASSERT(r.code() < FloatRegisters::Total);
    1.90 +    return r.code() << SAShift;
    1.91 +}
    1.92 +
    1.93 +Register
    1.94 +js::jit::toRS(Instruction &i)
    1.95 +{
    1.96 +    return Register::FromCode((i.encode() & RSMask ) >> RSShift);
    1.97 +}
    1.98 +
    1.99 +Register
   1.100 +js::jit::toRT(Instruction &i)
   1.101 +{
   1.102 +    return Register::FromCode((i.encode() & RTMask ) >> RTShift);
   1.103 +}
   1.104 +
   1.105 +Register
   1.106 +js::jit::toRD(Instruction &i)
   1.107 +{
   1.108 +    return Register::FromCode((i.encode() & RDMask ) >> RDShift);
   1.109 +}
   1.110 +
   1.111 +Register
   1.112 +js::jit::toR(Instruction &i)
   1.113 +{
   1.114 +    return Register::FromCode(i.encode() & RegMask);
   1.115 +}
   1.116 +
   1.117 +void
   1.118 +InstImm::extractImm16(BOffImm16 *dest)
   1.119 +{
   1.120 +    *dest = BOffImm16(*this);
   1.121 +}
   1.122 +
   1.123 +// Used to patch jumps created by MacroAssemblerMIPSCompat::jumpWithPatch.
   1.124 +void
   1.125 +jit::PatchJump(CodeLocationJump &jump_, CodeLocationLabel label)
   1.126 +{
   1.127 +    Instruction *inst1 = (Instruction *)jump_.raw();
   1.128 +    Instruction *inst2 = inst1->next();
   1.129 +
   1.130 +    Assembler::updateLuiOriValue(inst1, inst2, (uint32_t)label.raw());
   1.131 +
   1.132 +    AutoFlushICache::flush(uintptr_t(inst1), 8);
   1.133 +}
   1.134 +
   1.135 +void
   1.136 +Assembler::finish()
   1.137 +{
   1.138 +    JS_ASSERT(!isFinished);
   1.139 +    isFinished = true;
   1.140 +}
   1.141 +
   1.142 +void
   1.143 +Assembler::executableCopy(uint8_t *buffer)
   1.144 +{
   1.145 +    JS_ASSERT(isFinished);
   1.146 +    m_buffer.executableCopy(buffer);
   1.147 +
   1.148 +    // Patch all long jumps during code copy.
   1.149 +    for (size_t i = 0; i < longJumps_.length(); i++) {
   1.150 +        Instruction *inst1 = (Instruction *) ((uint32_t)buffer + longJumps_[i]);
   1.151 +
   1.152 +        uint32_t value = extractLuiOriValue(inst1, inst1->next());
   1.153 +        updateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value);
   1.154 +    }
   1.155 +
   1.156 +    AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
   1.157 +}
   1.158 +
   1.159 +uint32_t
   1.160 +Assembler::actualOffset(uint32_t off_) const
   1.161 +{
   1.162 +    return off_;
   1.163 +}
   1.164 +
   1.165 +uint32_t
   1.166 +Assembler::actualIndex(uint32_t idx_) const
   1.167 +{
   1.168 +    return idx_;
   1.169 +}
   1.170 +
   1.171 +uint8_t *
   1.172 +Assembler::PatchableJumpAddress(JitCode *code, uint32_t pe_)
   1.173 +{
   1.174 +    return code->raw() + pe_;
   1.175 +}
   1.176 +
   1.177 +class RelocationIterator
   1.178 +{
   1.179 +    CompactBufferReader reader_;
   1.180 +    // offset in bytes
   1.181 +    uint32_t offset_;
   1.182 +
   1.183 +  public:
   1.184 +    RelocationIterator(CompactBufferReader &reader)
   1.185 +      : reader_(reader)
   1.186 +    { }
   1.187 +
   1.188 +    bool read() {
   1.189 +        if (!reader_.more())
   1.190 +            return false;
   1.191 +        offset_ = reader_.readUnsigned();
   1.192 +        return true;
   1.193 +    }
   1.194 +
   1.195 +    uint32_t offset() const {
   1.196 +        return offset_;
   1.197 +    }
   1.198 +};
   1.199 +
   1.200 +uintptr_t
   1.201 +Assembler::getPointer(uint8_t *instPtr)
   1.202 +{
   1.203 +    Instruction *inst = (Instruction*)instPtr;
   1.204 +    return Assembler::extractLuiOriValue(inst, inst->next());
   1.205 +}
   1.206 +
   1.207 +static JitCode *
   1.208 +CodeFromJump(Instruction *jump)
   1.209 +{
   1.210 +    uint8_t *target = (uint8_t *)Assembler::extractLuiOriValue(jump, jump->next());
   1.211 +    return JitCode::FromExecutable(target);
   1.212 +}
   1.213 +
   1.214 +void
   1.215 +Assembler::TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
   1.216 +{
   1.217 +    RelocationIterator iter(reader);
   1.218 +    while (iter.read()) {
   1.219 +        JitCode *child = CodeFromJump((Instruction *)(code->raw() + iter.offset()));
   1.220 +        MarkJitCodeUnbarriered(trc, &child, "rel32");
   1.221 +    }
   1.222 +}
   1.223 +
   1.224 +static void
   1.225 +TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
   1.226 +{
   1.227 +    while (reader.more()) {
   1.228 +        size_t offset = reader.readUnsigned();
   1.229 +        Instruction *inst = (Instruction*)(buffer + offset);
   1.230 +        void *ptr = (void *)Assembler::extractLuiOriValue(inst, inst->next());
   1.231 +
   1.232 +        // No barrier needed since these are constants.
   1.233 +        gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
   1.234 +    }
   1.235 +}
   1.236 +
   1.237 +static void
   1.238 +TraceDataRelocations(JSTracer *trc, MIPSBuffer *buffer, CompactBufferReader &reader)
   1.239 +{
   1.240 +    while (reader.more()) {
   1.241 +        BufferOffset bo (reader.readUnsigned());
   1.242 +        MIPSBuffer::AssemblerBufferInstIterator iter(bo, buffer);
   1.243 +
   1.244 +        void *ptr = (void *)Assembler::extractLuiOriValue(iter.cur(), iter.next());
   1.245 +
   1.246 +        // No barrier needed since these are constants.
   1.247 +        gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
   1.248 +    }
   1.249 +}
   1.250 +
   1.251 +void
   1.252 +Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
   1.253 +{
   1.254 +    ::TraceDataRelocations(trc, code->raw(), reader);
   1.255 +}
   1.256 +
   1.257 +void
   1.258 +Assembler::copyJumpRelocationTable(uint8_t *dest)
   1.259 +{
   1.260 +    if (jumpRelocations_.length())
   1.261 +        memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
   1.262 +}
   1.263 +
   1.264 +void
   1.265 +Assembler::copyDataRelocationTable(uint8_t *dest)
   1.266 +{
   1.267 +    if (dataRelocations_.length())
   1.268 +        memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
   1.269 +}
   1.270 +
   1.271 +void
   1.272 +Assembler::copyPreBarrierTable(uint8_t *dest)
   1.273 +{
   1.274 +    if (preBarriers_.length())
   1.275 +        memcpy(dest, preBarriers_.buffer(), preBarriers_.length());
   1.276 +}
   1.277 +
   1.278 +void
   1.279 +Assembler::trace(JSTracer *trc)
   1.280 +{
   1.281 +    for (size_t i = 0; i < jumps_.length(); i++) {
   1.282 +        RelativePatch &rp = jumps_[i];
   1.283 +        if (rp.kind == Relocation::JITCODE) {
   1.284 +            JitCode *code = JitCode::FromExecutable((uint8_t *)rp.target);
   1.285 +            MarkJitCodeUnbarriered(trc, &code, "masmrel32");
   1.286 +            JS_ASSERT(code == JitCode::FromExecutable((uint8_t *)rp.target));
   1.287 +        }
   1.288 +    }
   1.289 +    if (dataRelocations_.length()) {
   1.290 +        CompactBufferReader reader(dataRelocations_);
   1.291 +        ::TraceDataRelocations(trc, &m_buffer, reader);
   1.292 +    }
   1.293 +}
   1.294 +
   1.295 +void
   1.296 +Assembler::processCodeLabels(uint8_t *rawCode)
   1.297 +{
   1.298 +    for (size_t i = 0; i < codeLabels_.length(); i++) {
   1.299 +        CodeLabel label = codeLabels_[i];
   1.300 +        Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset()));
   1.301 +    }
   1.302 +}
   1.303 +
   1.304 +void
   1.305 +Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
   1.306 +{
   1.307 +    if (label->used()) {
   1.308 +        int32_t src = label->offset();
   1.309 +        do {
   1.310 +            Instruction *inst = (Instruction *) (rawCode + src);
   1.311 +            uint32_t next = Assembler::extractLuiOriValue(inst, inst->next());
   1.312 +            Assembler::updateLuiOriValue(inst, inst->next(), (uint32_t)address);
   1.313 +            src = next;
   1.314 +        } while (src != AbsoluteLabel::INVALID_OFFSET);
   1.315 +    }
   1.316 +    label->bind();
   1.317 +}
   1.318 +
   1.319 +Assembler::Condition
   1.320 +Assembler::InvertCondition(Condition cond)
   1.321 +{
   1.322 +    switch (cond) {
   1.323 +      case Equal:
   1.324 +        return NotEqual;
   1.325 +      case NotEqual:
   1.326 +        return Equal;
   1.327 +      case Zero:
   1.328 +        return NonZero;
   1.329 +      case NonZero:
   1.330 +        return Zero;
   1.331 +      case LessThan:
   1.332 +        return GreaterThanOrEqual;
   1.333 +      case LessThanOrEqual:
   1.334 +        return GreaterThan;
   1.335 +      case GreaterThan:
   1.336 +        return LessThanOrEqual;
   1.337 +      case GreaterThanOrEqual:
   1.338 +        return LessThan;
   1.339 +      case Above:
   1.340 +        return BelowOrEqual;
   1.341 +      case AboveOrEqual:
   1.342 +        return Below;
   1.343 +      case Below:
   1.344 +        return AboveOrEqual;
   1.345 +      case BelowOrEqual:
   1.346 +        return Above;
   1.347 +      case Signed:
   1.348 +        return NotSigned;
   1.349 +      case NotSigned:
   1.350 +        return Signed;
   1.351 +      default:
   1.352 +        MOZ_ASSUME_UNREACHABLE("unexpected condition");
   1.353 +        return Equal;
   1.354 +    }
   1.355 +}
   1.356 +
   1.357 +Assembler::DoubleCondition
   1.358 +Assembler::InvertCondition(DoubleCondition cond)
   1.359 +{
   1.360 +    switch (cond) {
   1.361 +      case DoubleOrdered:
   1.362 +        return DoubleUnordered;
   1.363 +      case DoubleEqual:
   1.364 +        return DoubleNotEqualOrUnordered;
   1.365 +      case DoubleNotEqual:
   1.366 +        return DoubleEqualOrUnordered;
   1.367 +      case DoubleGreaterThan:
   1.368 +        return DoubleLessThanOrEqualOrUnordered;
   1.369 +      case DoubleGreaterThanOrEqual:
   1.370 +        return DoubleLessThanOrUnordered;
   1.371 +      case DoubleLessThan:
   1.372 +        return DoubleGreaterThanOrEqualOrUnordered;
   1.373 +      case DoubleLessThanOrEqual:
   1.374 +        return DoubleGreaterThanOrUnordered;
   1.375 +      case DoubleUnordered:
   1.376 +        return DoubleOrdered;
   1.377 +      case DoubleEqualOrUnordered:
   1.378 +        return DoubleNotEqual;
   1.379 +      case DoubleNotEqualOrUnordered:
   1.380 +        return DoubleEqual;
   1.381 +      case DoubleGreaterThanOrUnordered:
   1.382 +        return DoubleLessThanOrEqual;
   1.383 +      case DoubleGreaterThanOrEqualOrUnordered:
   1.384 +        return DoubleLessThan;
   1.385 +      case DoubleLessThanOrUnordered:
   1.386 +        return DoubleGreaterThanOrEqual;
   1.387 +      case DoubleLessThanOrEqualOrUnordered:
   1.388 +        return DoubleGreaterThan;
   1.389 +      default:
   1.390 +        MOZ_ASSUME_UNREACHABLE("unexpected condition");
   1.391 +        return DoubleEqual;
   1.392 +    }
   1.393 +}
   1.394 +
   1.395 +BOffImm16::BOffImm16(InstImm inst)
   1.396 +  : data(inst.encode() & Imm16Mask)
   1.397 +{
   1.398 +}
   1.399 +
   1.400 +bool
   1.401 +Assembler::oom() const
   1.402 +{
   1.403 +    return m_buffer.oom() ||
   1.404 +           !enoughMemory_ ||
   1.405 +           jumpRelocations_.oom() ||
   1.406 +           dataRelocations_.oom() ||
   1.407 +           preBarriers_.oom();
   1.408 +}
   1.409 +
   1.410 +bool
   1.411 +Assembler::addCodeLabel(CodeLabel label)
   1.412 +{
   1.413 +    return codeLabels_.append(label);
   1.414 +}
   1.415 +
   1.416 +// Size of the instruction stream, in bytes.
   1.417 +size_t
   1.418 +Assembler::size() const
   1.419 +{
   1.420 +    return m_buffer.size();
   1.421 +}
   1.422 +
   1.423 +// Size of the relocation table, in bytes.
   1.424 +size_t
   1.425 +Assembler::jumpRelocationTableBytes() const
   1.426 +{
   1.427 +    return jumpRelocations_.length();
   1.428 +}
   1.429 +
   1.430 +size_t
   1.431 +Assembler::dataRelocationTableBytes() const
   1.432 +{
   1.433 +    return dataRelocations_.length();
   1.434 +}
   1.435 +
   1.436 +size_t
   1.437 +Assembler::preBarrierTableBytes() const
   1.438 +{
   1.439 +    return preBarriers_.length();
   1.440 +}
   1.441 +
   1.442 +// Size of the data table, in bytes.
   1.443 +size_t
   1.444 +Assembler::bytesNeeded() const
   1.445 +{
   1.446 +    return size() +
   1.447 +           jumpRelocationTableBytes() +
   1.448 +           dataRelocationTableBytes() +
   1.449 +           preBarrierTableBytes();
   1.450 +}
   1.451 +
   1.452 +// write a blob of binary into the instruction stream
   1.453 +BufferOffset
   1.454 +Assembler::writeInst(uint32_t x, uint32_t *dest)
   1.455 +{
   1.456 +    if (dest == nullptr)
   1.457 +        return m_buffer.putInt(x);
   1.458 +
   1.459 +    writeInstStatic(x, dest);
   1.460 +    return BufferOffset();
   1.461 +}
   1.462 +
   1.463 +void
   1.464 +Assembler::writeInstStatic(uint32_t x, uint32_t *dest)
   1.465 +{
   1.466 +    JS_ASSERT(dest != nullptr);
   1.467 +    *dest = x;
   1.468 +}
   1.469 +
   1.470 +BufferOffset
   1.471 +Assembler::align(int alignment)
   1.472 +{
   1.473 +    BufferOffset ret;
   1.474 +    JS_ASSERT(m_buffer.isAligned(4));
   1.475 +    if (alignment == 8) {
   1.476 +        if (!m_buffer.isAligned(alignment)) {
   1.477 +            BufferOffset tmp = as_nop();
   1.478 +            if (!ret.assigned())
   1.479 +                ret = tmp;
   1.480 +        }
   1.481 +    } else {
   1.482 +        JS_ASSERT((alignment & (alignment - 1)) == 0);
   1.483 +        while (size() & (alignment - 1)) {
   1.484 +            BufferOffset tmp = as_nop();
   1.485 +            if (!ret.assigned())
   1.486 +                ret = tmp;
   1.487 +        }
   1.488 +    }
   1.489 +    return ret;
   1.490 +}
   1.491 +
   1.492 +BufferOffset
   1.493 +Assembler::as_nop()
   1.494 +{
   1.495 +    return writeInst(op_special | ff_sll);
   1.496 +}
   1.497 +
   1.498 +// Logical operations.
   1.499 +BufferOffset
   1.500 +Assembler::as_and(Register rd, Register rs, Register rt)
   1.501 +{
   1.502 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode());
   1.503 +}
   1.504 +
   1.505 +BufferOffset
   1.506 +Assembler::as_or(Register rd, Register rs, Register rt)
   1.507 +{
   1.508 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode());
   1.509 +}
   1.510 +
   1.511 +BufferOffset
   1.512 +Assembler::as_xor(Register rd, Register rs, Register rt)
   1.513 +{
   1.514 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode());
   1.515 +}
   1.516 +
   1.517 +BufferOffset
   1.518 +Assembler::as_nor(Register rd, Register rs, Register rt)
   1.519 +{
   1.520 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode());
   1.521 +}
   1.522 +
   1.523 +BufferOffset
   1.524 +Assembler::as_andi(Register rd, Register rs, int32_t j)
   1.525 +{
   1.526 +    JS_ASSERT(Imm16::isInUnsignedRange(j));
   1.527 +    return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode());
   1.528 +}
   1.529 +
   1.530 +BufferOffset
   1.531 +Assembler::as_ori(Register rd, Register rs, int32_t j)
   1.532 +{
   1.533 +    JS_ASSERT(Imm16::isInUnsignedRange(j));
   1.534 +    return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode());
   1.535 +}
   1.536 +
   1.537 +BufferOffset
   1.538 +Assembler::as_xori(Register rd, Register rs, int32_t j)
   1.539 +{
   1.540 +    JS_ASSERT(Imm16::isInUnsignedRange(j));
   1.541 +    return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode());
   1.542 +}
   1.543 +
   1.544 +// Branch and jump instructions
   1.545 +BufferOffset
   1.546 +Assembler::as_bal(BOffImm16 off)
   1.547 +{
   1.548 +    BufferOffset bo = writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode());
   1.549 +    return bo;
   1.550 +}
   1.551 +
   1.552 +InstImm
   1.553 +Assembler::getBranchCode(JumpOrCall jumpOrCall)
   1.554 +{
   1.555 +    if (jumpOrCall == BranchIsCall)
   1.556 +        return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
   1.557 +
   1.558 +    return InstImm(op_beq, zero, zero, BOffImm16(0));
   1.559 +}
   1.560 +
   1.561 +InstImm
   1.562 +Assembler::getBranchCode(Register s, Register t, Condition c)
   1.563 +{
   1.564 +    JS_ASSERT(c == Assembler::Equal || c == Assembler::NotEqual);
   1.565 +    return InstImm(c == Assembler::Equal ? op_beq : op_bne, s, t, BOffImm16(0));
   1.566 +}
   1.567 +
   1.568 +InstImm
   1.569 +Assembler::getBranchCode(Register s, Condition c)
   1.570 +{
   1.571 +    switch (c) {
   1.572 +      case Assembler::Equal:
   1.573 +      case Assembler::Zero:
   1.574 +      case Assembler::BelowOrEqual:
   1.575 +        return InstImm(op_beq, s, zero, BOffImm16(0));
   1.576 +      case Assembler::NotEqual:
   1.577 +      case Assembler::NonZero:
   1.578 +      case Assembler::Above:
   1.579 +        return InstImm(op_bne, s, zero, BOffImm16(0));
   1.580 +      case Assembler::GreaterThan:
   1.581 +        return InstImm(op_bgtz, s, zero, BOffImm16(0));
   1.582 +      case Assembler::GreaterThanOrEqual:
   1.583 +      case Assembler::NotSigned:
   1.584 +        return InstImm(op_regimm, s, rt_bgez, BOffImm16(0));
   1.585 +      case Assembler::LessThan:
   1.586 +      case Assembler::Signed:
   1.587 +        return InstImm(op_regimm, s, rt_bltz, BOffImm16(0));
   1.588 +      case Assembler::LessThanOrEqual:
   1.589 +        return InstImm(op_blez, s, zero, BOffImm16(0));
   1.590 +      default:
   1.591 +        MOZ_ASSUME_UNREACHABLE("Condition not supported.");
   1.592 +    }
   1.593 +}
   1.594 +
   1.595 +InstImm
   1.596 +Assembler::getBranchCode(FloatTestKind testKind, FPConditionBit fcc)
   1.597 +{
   1.598 +    JS_ASSERT(!(fcc && FccMask));
   1.599 +    uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift)) << RTShift;
   1.600 +
   1.601 +    return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0));
   1.602 +}
   1.603 +
   1.604 +BufferOffset
   1.605 +Assembler::as_j(JOffImm26 off)
   1.606 +{
   1.607 +    BufferOffset bo = writeInst(InstJump(op_j, off).encode());
   1.608 +    return bo;
   1.609 +}
   1.610 +BufferOffset
   1.611 +Assembler::as_jal(JOffImm26 off)
   1.612 +{
   1.613 +    BufferOffset bo = writeInst(InstJump(op_jal, off).encode());
   1.614 +    return bo;
   1.615 +}
   1.616 +
   1.617 +BufferOffset
   1.618 +Assembler::as_jr(Register rs)
   1.619 +{
   1.620 +    BufferOffset bo = writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode());
   1.621 +    return bo;
   1.622 +}
   1.623 +BufferOffset
   1.624 +Assembler::as_jalr(Register rs)
   1.625 +{
   1.626 +    BufferOffset bo = writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode());
   1.627 +    return bo;
   1.628 +}
   1.629 +
   1.630 +
   1.631 +// Arithmetic instructions
   1.632 +BufferOffset
   1.633 +Assembler::as_addu(Register rd, Register rs, Register rt)
   1.634 +{
   1.635 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode());
   1.636 +}
   1.637 +
   1.638 +BufferOffset
   1.639 +Assembler::as_addiu(Register rd, Register rs, int32_t j)
   1.640 +{
   1.641 +    JS_ASSERT(Imm16::isInSignedRange(j));
   1.642 +    return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
   1.643 +}
   1.644 +
   1.645 +BufferOffset
   1.646 +Assembler::as_subu(Register rd, Register rs, Register rt)
   1.647 +{
   1.648 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
   1.649 +}
   1.650 +
   1.651 +BufferOffset
   1.652 +Assembler::as_mult(Register rs, Register rt)
   1.653 +{
   1.654 +    return writeInst(InstReg(op_special, rs, rt, ff_mult).encode());
   1.655 +}
   1.656 +
   1.657 +BufferOffset
   1.658 +Assembler::as_multu(Register rs, Register rt)
   1.659 +{
   1.660 +    return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
   1.661 +}
   1.662 +
   1.663 +BufferOffset
   1.664 +Assembler::as_div(Register rs, Register rt)
   1.665 +{
   1.666 +    return writeInst(InstReg(op_special, rs, rt, ff_div).encode());
   1.667 +}
   1.668 +
   1.669 +BufferOffset
   1.670 +Assembler::as_divu(Register rs, Register rt)
   1.671 +{
   1.672 +    return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
   1.673 +}
   1.674 +
   1.675 +BufferOffset
   1.676 +Assembler::as_mul(Register rd, Register rs, Register rt)
   1.677 +{
   1.678 +    return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode());
   1.679 +}
   1.680 +
   1.681 +BufferOffset
   1.682 +Assembler::as_lui(Register rd, int32_t j)
   1.683 +{
   1.684 +    JS_ASSERT(Imm16::isInUnsignedRange(j));
   1.685 +    return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode());
   1.686 +}
   1.687 +
   1.688 +// Shift instructions
   1.689 +BufferOffset
   1.690 +Assembler::as_sll(Register rd, Register rt, uint16_t sa)
   1.691 +{
   1.692 +    JS_ASSERT(sa < 32);
   1.693 +    return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
   1.694 +}
   1.695 +
   1.696 +BufferOffset
   1.697 +Assembler::as_sllv(Register rd, Register rt, Register rs)
   1.698 +{
   1.699 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
   1.700 +}
   1.701 +
   1.702 +BufferOffset
   1.703 +Assembler::as_srl(Register rd, Register rt, uint16_t sa)
   1.704 +{
   1.705 +    JS_ASSERT(sa < 32);
   1.706 +    return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
   1.707 +}
   1.708 +
   1.709 +BufferOffset
   1.710 +Assembler::as_srlv(Register rd, Register rt, Register rs)
   1.711 +{
   1.712 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
   1.713 +}
   1.714 +
   1.715 +BufferOffset
   1.716 +Assembler::as_sra(Register rd, Register rt, uint16_t sa)
   1.717 +{
   1.718 +    JS_ASSERT(sa < 32);
   1.719 +    return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
   1.720 +}
   1.721 +
   1.722 +BufferOffset
   1.723 +Assembler::as_srav(Register rd, Register rt, Register rs)
   1.724 +{
   1.725 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
   1.726 +}
   1.727 +
   1.728 +BufferOffset
   1.729 +Assembler::as_rotr(Register rd, Register rt, uint16_t sa)
   1.730 +{
   1.731 +    JS_ASSERT(sa < 32);
   1.732 +    return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
   1.733 +}
   1.734 +
   1.735 +BufferOffset
   1.736 +Assembler::as_rotrv(Register rd, Register rt, Register rs)
   1.737 +{
   1.738 +    return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
   1.739 +}
   1.740 +
   1.741 +// Load and store instructions
   1.742 +BufferOffset
   1.743 +Assembler::as_lb(Register rd, Register rs, int16_t off)
   1.744 +{
   1.745 +    return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode());
   1.746 +}
   1.747 +
   1.748 +BufferOffset
   1.749 +Assembler::as_lbu(Register rd, Register rs, int16_t off)
   1.750 +{
   1.751 +    return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode());
   1.752 +}
   1.753 +
   1.754 +BufferOffset
   1.755 +Assembler::as_lh(Register rd, Register rs, int16_t off)
   1.756 +{
   1.757 +    return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode());
   1.758 +}
   1.759 +
   1.760 +BufferOffset
   1.761 +Assembler::as_lhu(Register rd, Register rs, int16_t off)
   1.762 +{
   1.763 +    return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode());
   1.764 +}
   1.765 +
   1.766 +BufferOffset
   1.767 +Assembler::as_lw(Register rd, Register rs, int16_t off)
   1.768 +{
   1.769 +    return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
   1.770 +}
   1.771 +
   1.772 +BufferOffset
   1.773 +Assembler::as_lwl(Register rd, Register rs, int16_t off)
   1.774 +{
   1.775 +    return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode());
   1.776 +}
   1.777 +
   1.778 +BufferOffset
   1.779 +Assembler::as_lwr(Register rd, Register rs, int16_t off)
   1.780 +{
   1.781 +    return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
   1.782 +}
   1.783 +
   1.784 +BufferOffset
   1.785 +Assembler::as_sb(Register rd, Register rs, int16_t off)
   1.786 +{
   1.787 +    return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode());
   1.788 +}
   1.789 +
   1.790 +BufferOffset
   1.791 +Assembler::as_sh(Register rd, Register rs, int16_t off)
   1.792 +{
   1.793 +    return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode());
   1.794 +}
   1.795 +
   1.796 +BufferOffset
   1.797 +Assembler::as_sw(Register rd, Register rs, int16_t off)
   1.798 +{
   1.799 +    return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode());
   1.800 +}
   1.801 +
   1.802 +BufferOffset
   1.803 +Assembler::as_swl(Register rd, Register rs, int16_t off)
   1.804 +{
   1.805 +    return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode());
   1.806 +}
   1.807 +
   1.808 +BufferOffset
   1.809 +Assembler::as_swr(Register rd, Register rs, int16_t off)
   1.810 +{
   1.811 +    return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
   1.812 +}
   1.813 +
   1.814 +// Move from HI/LO register.
   1.815 +BufferOffset
   1.816 +Assembler::as_mfhi(Register rd)
   1.817 +{
   1.818 +    return writeInst(InstReg(op_special, rd, ff_mfhi).encode());
   1.819 +}
   1.820 +
   1.821 +BufferOffset
   1.822 +Assembler::as_mflo(Register rd)
   1.823 +{
   1.824 +    return writeInst(InstReg(op_special, rd, ff_mflo).encode());
   1.825 +}
   1.826 +
   1.827 +// Set on less than.
   1.828 +BufferOffset
   1.829 +Assembler::as_slt(Register rd, Register rs, Register rt)
   1.830 +{
   1.831 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode());
   1.832 +}
   1.833 +
   1.834 +BufferOffset
   1.835 +Assembler::as_sltu(Register rd, Register rs, Register rt)
   1.836 +{
   1.837 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode());
   1.838 +}
   1.839 +
   1.840 +BufferOffset
   1.841 +Assembler::as_slti(Register rd, Register rs, int32_t j)
   1.842 +{
   1.843 +    JS_ASSERT(Imm16::isInSignedRange(j));
   1.844 +    return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode());
   1.845 +}
   1.846 +
   1.847 +BufferOffset
   1.848 +Assembler::as_sltiu(Register rd, Register rs, uint32_t j)
   1.849 +{
   1.850 +    JS_ASSERT(Imm16::isInUnsignedRange(j));
   1.851 +    return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode());
   1.852 +}
   1.853 +
   1.854 +// Conditional move.
   1.855 +BufferOffset
   1.856 +Assembler::as_movz(Register rd, Register rs, Register rt)
   1.857 +{
   1.858 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode());
   1.859 +}
   1.860 +
   1.861 +BufferOffset
   1.862 +Assembler::as_movn(Register rd, Register rs, Register rt)
   1.863 +{
   1.864 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode());
   1.865 +}
   1.866 +
   1.867 +BufferOffset
   1.868 +Assembler::as_movt(Register rd, Register rs, uint16_t cc)
   1.869 +{
   1.870 +    Register rt;
   1.871 +    rt = Register::FromCode((cc & 0x7) << 2 | 1);
   1.872 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
   1.873 +}
   1.874 +
   1.875 +BufferOffset
   1.876 +Assembler::as_movf(Register rd, Register rs, uint16_t cc)
   1.877 +{
   1.878 +    Register rt;
   1.879 +    rt = Register::FromCode((cc & 0x7) << 2 | 0);
   1.880 +    return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
   1.881 +}
   1.882 +
   1.883 +// Bit twiddling.
   1.884 +BufferOffset
   1.885 +Assembler::as_clz(Register rd, Register rs, Register rt)
   1.886 +{
   1.887 +    return writeInst(InstReg(op_special2, rs, rt, rd, ff_clz).encode());
   1.888 +}
   1.889 +
   1.890 +BufferOffset
   1.891 +Assembler::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
   1.892 +{
   1.893 +    JS_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
   1.894 +    Register rd;
   1.895 +    rd = Register::FromCode(pos + size - 1);
   1.896 +    return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
   1.897 +}
   1.898 +
   1.899 +BufferOffset
   1.900 +Assembler::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
   1.901 +{
   1.902 +    JS_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
   1.903 +    Register rd;
   1.904 +    rd = Register::FromCode(size - 1);
   1.905 +    return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
   1.906 +}
   1.907 +
   1.908 +// FP instructions
   1.909 +BufferOffset
   1.910 +Assembler::as_ld(FloatRegister fd, Register base, int32_t off)
   1.911 +{
   1.912 +    JS_ASSERT(Imm16::isInSignedRange(off));
   1.913 +    return writeInst(InstImm(op_ldc1, base, fd, Imm16(off)).encode());
   1.914 +}
   1.915 +
   1.916 +BufferOffset
   1.917 +Assembler::as_sd(FloatRegister fd, Register base, int32_t off)
   1.918 +{
   1.919 +    JS_ASSERT(Imm16::isInSignedRange(off));
   1.920 +    return writeInst(InstImm(op_sdc1, base, fd, Imm16(off)).encode());
   1.921 +}
   1.922 +
   1.923 +BufferOffset
   1.924 +Assembler::as_ls(FloatRegister fd, Register base, int32_t off)
   1.925 +{
   1.926 +    JS_ASSERT(Imm16::isInSignedRange(off));
   1.927 +    return writeInst(InstImm(op_lwc1, base, fd, Imm16(off)).encode());
   1.928 +}
   1.929 +
   1.930 +BufferOffset
   1.931 +Assembler::as_ss(FloatRegister fd, Register base, int32_t off)
   1.932 +{
   1.933 +    JS_ASSERT(Imm16::isInSignedRange(off));
   1.934 +    return writeInst(InstImm(op_swc1, base, fd, Imm16(off)).encode());
   1.935 +}
   1.936 +
   1.937 +BufferOffset
   1.938 +Assembler::as_movs(FloatRegister fd, FloatRegister fs)
   1.939 +{
   1.940 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode());
   1.941 +}
   1.942 +
   1.943 +BufferOffset
   1.944 +Assembler::as_movd(FloatRegister fd, FloatRegister fs)
   1.945 +{
   1.946 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode());
   1.947 +}
   1.948 +
   1.949 +BufferOffset
   1.950 +Assembler::as_mtc1(Register rt, FloatRegister fs)
   1.951 +{
   1.952 +    return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode());
   1.953 +}
   1.954 +
   1.955 +BufferOffset
   1.956 +Assembler::as_mfc1(Register rt, FloatRegister fs)
   1.957 +{
   1.958 +    return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
   1.959 +}
   1.960 +
   1.961 +// FP convert instructions
   1.962 +BufferOffset
   1.963 +Assembler::as_ceilws(FloatRegister fd, FloatRegister fs)
   1.964 +{
   1.965 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode());
   1.966 +}
   1.967 +
   1.968 +BufferOffset
   1.969 +Assembler::as_floorws(FloatRegister fd, FloatRegister fs)
   1.970 +{
   1.971 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode());
   1.972 +}
   1.973 +
   1.974 +BufferOffset
   1.975 +Assembler::as_roundws(FloatRegister fd, FloatRegister fs)
   1.976 +{
   1.977 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode());
   1.978 +}
   1.979 +
   1.980 +BufferOffset
   1.981 +Assembler::as_truncws(FloatRegister fd, FloatRegister fs)
   1.982 +{
   1.983 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode());
   1.984 +}
   1.985 +
   1.986 +BufferOffset
   1.987 +Assembler::as_ceilwd(FloatRegister fd, FloatRegister fs)
   1.988 +{
   1.989 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode());
   1.990 +}
   1.991 +
   1.992 +BufferOffset
   1.993 +Assembler::as_floorwd(FloatRegister fd, FloatRegister fs)
   1.994 +{
   1.995 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode());
   1.996 +}
   1.997 +
   1.998 +BufferOffset
   1.999 +Assembler::as_roundwd(FloatRegister fd, FloatRegister fs)
  1.1000 +{
  1.1001 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode());
  1.1002 +}
  1.1003 +
  1.1004 +BufferOffset
  1.1005 +Assembler::as_truncwd(FloatRegister fd, FloatRegister fs)
  1.1006 +{
  1.1007 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
  1.1008 +}
  1.1009 +
  1.1010 +BufferOffset
  1.1011 +Assembler::as_cvtds(FloatRegister fd, FloatRegister fs)
  1.1012 +{
  1.1013 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode());
  1.1014 +}
  1.1015 +
  1.1016 +BufferOffset
  1.1017 +Assembler::as_cvtdw(FloatRegister fd, FloatRegister fs)
  1.1018 +{
  1.1019 +    return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode());
  1.1020 +}
  1.1021 +
  1.1022 +BufferOffset
  1.1023 +Assembler::as_cvtsd(FloatRegister fd, FloatRegister fs)
  1.1024 +{
  1.1025 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode());
  1.1026 +}
  1.1027 +
  1.1028 +BufferOffset
  1.1029 +Assembler::as_cvtsw(FloatRegister fd, FloatRegister fs)
  1.1030 +{
  1.1031 +    return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode());
  1.1032 +}
  1.1033 +
  1.1034 +BufferOffset
  1.1035 +Assembler::as_cvtwd(FloatRegister fd, FloatRegister fs)
  1.1036 +{
  1.1037 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode());
  1.1038 +}
  1.1039 +
  1.1040 +BufferOffset
  1.1041 +Assembler::as_cvtws(FloatRegister fd, FloatRegister fs)
  1.1042 +{
  1.1043 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode());
  1.1044 +}
  1.1045 +
  1.1046 +// FP arithmetic instructions
  1.1047 +BufferOffset
  1.1048 +Assembler::as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1049 +{
  1.1050 +    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode());
  1.1051 +}
  1.1052 +
  1.1053 +BufferOffset
  1.1054 +Assembler::as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1055 +{
  1.1056 +    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode());
  1.1057 +}
  1.1058 +
  1.1059 +BufferOffset
  1.1060 +Assembler::as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1061 +{
  1.1062 +    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode());
  1.1063 +}
  1.1064 +
  1.1065 +BufferOffset
  1.1066 +Assembler::as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1067 +{
  1.1068 +    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode());
  1.1069 +}
  1.1070 +
  1.1071 +BufferOffset
  1.1072 +Assembler::as_abss(FloatRegister fd, FloatRegister fs)
  1.1073 +{
  1.1074 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode());
  1.1075 +}
  1.1076 +
  1.1077 +BufferOffset
  1.1078 +Assembler::as_absd(FloatRegister fd, FloatRegister fs)
  1.1079 +{
  1.1080 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
  1.1081 +}
  1.1082 +
  1.1083 +BufferOffset
  1.1084 +Assembler::as_negd(FloatRegister fd, FloatRegister fs)
  1.1085 +{
  1.1086 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
  1.1087 +}
  1.1088 +
  1.1089 +BufferOffset
  1.1090 +Assembler::as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1091 +{
  1.1092 +    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode());
  1.1093 +}
  1.1094 +
  1.1095 +BufferOffset
  1.1096 +Assembler::as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1097 +{
  1.1098 +    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode());
  1.1099 +}
  1.1100 +
  1.1101 +BufferOffset
  1.1102 +Assembler::as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1103 +{
  1.1104 +    return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode());
  1.1105 +}
  1.1106 +
  1.1107 +BufferOffset
  1.1108 +Assembler::as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
  1.1109 +{
  1.1110 +    return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode());
  1.1111 +}
  1.1112 +
  1.1113 +BufferOffset
  1.1114 +Assembler::as_sqrts(FloatRegister fd, FloatRegister fs)
  1.1115 +{
  1.1116 +    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode());
  1.1117 +}
  1.1118 +
  1.1119 +BufferOffset
  1.1120 +Assembler::as_sqrtd(FloatRegister fd, FloatRegister fs)
  1.1121 +{
  1.1122 +    return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode());
  1.1123 +}
  1.1124 +
  1.1125 +// FP compare instructions
  1.1126 +BufferOffset
  1.1127 +Assembler::as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1128 +{
  1.1129 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1130 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
  1.1131 +}
  1.1132 +
  1.1133 +BufferOffset
  1.1134 +Assembler::as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1135 +{
  1.1136 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1137 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
  1.1138 +}
  1.1139 +
  1.1140 +BufferOffset
  1.1141 +Assembler::as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1142 +{
  1.1143 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1144 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
  1.1145 +}
  1.1146 +
  1.1147 +BufferOffset
  1.1148 +Assembler::as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1149 +{
  1.1150 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1151 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
  1.1152 +}
  1.1153 +
  1.1154 +BufferOffset
  1.1155 +Assembler::as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1156 +{
  1.1157 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1158 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
  1.1159 +}
  1.1160 +
  1.1161 +BufferOffset
  1.1162 +Assembler::as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1163 +{
  1.1164 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1165 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
  1.1166 +}
  1.1167 +
  1.1168 +BufferOffset
  1.1169 +Assembler::as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1170 +{
  1.1171 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1172 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
  1.1173 +}
  1.1174 +
  1.1175 +BufferOffset
  1.1176 +Assembler::as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
  1.1177 +{
  1.1178 +    RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
  1.1179 +    return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
  1.1180 +}
  1.1181 +
  1.1182 +
  1.1183 +void
  1.1184 +Assembler::bind(Label *label, BufferOffset boff)
  1.1185 +{
  1.1186 +    // If our caller didn't give us an explicit target to bind to
  1.1187 +    // then we want to bind to the location of the next instruction
  1.1188 +    BufferOffset dest = boff.assigned() ? boff : nextOffset();
  1.1189 +    if (label->used()) {
  1.1190 +        int32_t next;
  1.1191 +
  1.1192 +        // A used label holds a link to branch that uses it.
  1.1193 +        BufferOffset b(label);
  1.1194 +        do {
  1.1195 +            Instruction *inst = editSrc(b);
  1.1196 +
  1.1197 +            // Second word holds a pointer to the next branch in label's chain.
  1.1198 +            next = inst[1].encode();
  1.1199 +            bind(reinterpret_cast<InstImm *>(inst), b.getOffset(), dest.getOffset());
  1.1200 +
  1.1201 +            b = BufferOffset(next);
  1.1202 +        } while (next != LabelBase::INVALID_OFFSET);
  1.1203 +    }
  1.1204 +    label->bind(dest.getOffset());
  1.1205 +}
  1.1206 +
  1.1207 +void
  1.1208 +Assembler::bind(InstImm *inst, uint32_t branch, uint32_t target)
  1.1209 +{
  1.1210 +    int32_t offset = target - branch;
  1.1211 +    InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
  1.1212 +    InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
  1.1213 +
  1.1214 +    // If encoded offset is 4, then the jump must be short
  1.1215 +    if (BOffImm16(inst[0]).decode() == 4) {
  1.1216 +        JS_ASSERT(BOffImm16::isInRange(offset));
  1.1217 +        inst[0].setBOffImm16(BOffImm16(offset));
  1.1218 +        inst[1].makeNop();
  1.1219 +        return;
  1.1220 +    }
  1.1221 +    if (BOffImm16::isInRange(offset)) {
  1.1222 +        bool conditional = (inst[0].encode() != inst_bgezal.encode() &&
  1.1223 +                            inst[0].encode() != inst_beq.encode());
  1.1224 +
  1.1225 +        inst[0].setBOffImm16(BOffImm16(offset));
  1.1226 +        inst[1].makeNop();
  1.1227 +
  1.1228 +        // Skip the trailing nops in conditional branches.
  1.1229 +        if (conditional) {
  1.1230 +            inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(3 * sizeof(void *))).encode();
  1.1231 +            // There are 2 nops after this
  1.1232 +        }
  1.1233 +        return;
  1.1234 +    }
  1.1235 +
  1.1236 +    if (inst[0].encode() == inst_bgezal.encode()) {
  1.1237 +        // Handle long call.
  1.1238 +        addLongJump(BufferOffset(branch));
  1.1239 +        writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
  1.1240 +        inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
  1.1241 +        // There is 1 nop after this.
  1.1242 +    } else if (inst[0].encode() == inst_beq.encode()) {
  1.1243 +        // Handle long unconditional jump.
  1.1244 +        addLongJump(BufferOffset(branch));
  1.1245 +        writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
  1.1246 +        inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
  1.1247 +        // There is 1 nop after this.
  1.1248 +    } else {
  1.1249 +        // Handle long conditional jump.
  1.1250 +        inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(void *)));
  1.1251 +        // No need for a "nop" here because we can clobber scratch.
  1.1252 +        addLongJump(BufferOffset(branch + sizeof(void *)));
  1.1253 +        writeLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, target);
  1.1254 +        inst[3] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
  1.1255 +        // There is 1 nop after this.
  1.1256 +    }
  1.1257 +}
  1.1258 +
  1.1259 +void
  1.1260 +Assembler::bind(RepatchLabel *label)
  1.1261 +{
  1.1262 +    BufferOffset dest = nextOffset();
  1.1263 +    if (label->used()) {
  1.1264 +        // If the label has a use, then change this use to refer to
  1.1265 +        // the bound label;
  1.1266 +        BufferOffset b(label->offset());
  1.1267 +        Instruction *inst1 = editSrc(b);
  1.1268 +        Instruction *inst2 = inst1->next();
  1.1269 +
  1.1270 +        updateLuiOriValue(inst1, inst2, dest.getOffset());
  1.1271 +    }
  1.1272 +    label->bind(dest.getOffset());
  1.1273 +}
  1.1274 +
  1.1275 +void
  1.1276 +Assembler::retarget(Label *label, Label *target)
  1.1277 +{
  1.1278 +    if (label->used()) {
  1.1279 +        if (target->bound()) {
  1.1280 +            bind(label, BufferOffset(target));
  1.1281 +        } else if (target->used()) {
  1.1282 +            // The target is not bound but used. Prepend label's branch list
  1.1283 +            // onto target's.
  1.1284 +            int32_t next;
  1.1285 +            BufferOffset labelBranchOffset(label);
  1.1286 +
  1.1287 +            // Find the head of the use chain for label.
  1.1288 +            do {
  1.1289 +                Instruction *inst = editSrc(labelBranchOffset);
  1.1290 +
  1.1291 +                // Second word holds a pointer to the next branch in chain.
  1.1292 +                next = inst[1].encode();
  1.1293 +                labelBranchOffset = BufferOffset(next);
  1.1294 +            } while (next != LabelBase::INVALID_OFFSET);
  1.1295 +
  1.1296 +            // Then patch the head of label's use chain to the tail of
  1.1297 +            // target's use chain, prepending the entire use chain of target.
  1.1298 +            Instruction *inst = editSrc(labelBranchOffset);
  1.1299 +            int32_t prev = target->use(label->offset());
  1.1300 +            inst[1].setData(prev);
  1.1301 +        } else {
  1.1302 +            // The target is unbound and unused.  We can just take the head of
  1.1303 +            // the list hanging off of label, and dump that into target.
  1.1304 +            DebugOnly<uint32_t> prev = target->use(label->offset());
  1.1305 +            JS_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
  1.1306 +        }
  1.1307 +    }
  1.1308 +    label->reset();
  1.1309 +}
  1.1310 +
  1.1311 +void dbg_break() {}
  1.1312 +static int stopBKPT = -1;
  1.1313 +void
  1.1314 +Assembler::as_break(uint32_t code)
  1.1315 +{
  1.1316 +    JS_ASSERT(code <= MAX_BREAK_CODE);
  1.1317 +    writeInst(op_special | code << RTShift | ff_break);
  1.1318 +}
  1.1319 +
  1.1320 +uint32_t
  1.1321 +Assembler::patchWrite_NearCallSize()
  1.1322 +{
  1.1323 +    return 4 * sizeof(uint32_t);
  1.1324 +}
  1.1325 +
  1.1326 +void
  1.1327 +Assembler::patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
  1.1328 +{
  1.1329 +    Instruction *inst = (Instruction *) start.raw();
  1.1330 +    uint8_t *dest = toCall.raw();
  1.1331 +
  1.1332 +    // Overwrite whatever instruction used to be here with a call.
  1.1333 +    // Always use long jump for two reasons:
  1.1334 +    // - Jump has to be the same size because of patchWrite_NearCallSize.
  1.1335 +    // - Return address has to be at the end of replaced block.
  1.1336 +    // Short jump wouldn't be more efficient.
  1.1337 +    writeLuiOriInstructions(inst, &inst[1], ScratchRegister, (uint32_t)dest);
  1.1338 +    inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
  1.1339 +    inst[3] = InstNOP();
  1.1340 +
  1.1341 +    // Ensure everyone sees the code that was just written into memory.
  1.1342 +    AutoFlushICache::flush(uintptr_t(inst), patchWrite_NearCallSize());
  1.1343 +}
  1.1344 +
  1.1345 +uint32_t
  1.1346 +Assembler::extractLuiOriValue(Instruction *inst0, Instruction *inst1)
  1.1347 +{
  1.1348 +    InstImm *i0 = (InstImm *) inst0;
  1.1349 +    InstImm *i1 = (InstImm *) inst1;
  1.1350 +    JS_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
  1.1351 +    JS_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
  1.1352 +
  1.1353 +    uint32_t value = i0->extractImm16Value() << 16;
  1.1354 +    value = value | i1->extractImm16Value();
  1.1355 +    return value;
  1.1356 +}
  1.1357 +
  1.1358 +void
  1.1359 +Assembler::updateLuiOriValue(Instruction *inst0, Instruction *inst1, uint32_t value)
  1.1360 +{
  1.1361 +    JS_ASSERT(inst0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
  1.1362 +    JS_ASSERT(inst1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
  1.1363 +
  1.1364 +    ((InstImm *) inst0)->setImm16(Imm16::upper(Imm32(value)));
  1.1365 +    ((InstImm *) inst1)->setImm16(Imm16::lower(Imm32(value)));
  1.1366 +}
  1.1367 +
  1.1368 +void
  1.1369 +Assembler::writeLuiOriInstructions(Instruction *inst0, Instruction *inst1,
  1.1370 +                                   Register reg, uint32_t value)
  1.1371 +{
  1.1372 +    *inst0 = InstImm(op_lui, zero, reg, Imm16::upper(Imm32(value)));
  1.1373 +    *inst1 = InstImm(op_ori, reg, reg, Imm16::lower(Imm32(value)));
  1.1374 +}
  1.1375 +
  1.1376 +void
  1.1377 +Assembler::patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
  1.1378 +                                   PatchedImmPtr expectedValue)
  1.1379 +{
  1.1380 +    Instruction *inst = (Instruction *) label.raw();
  1.1381 +
  1.1382 +    // Extract old Value
  1.1383 +    DebugOnly<uint32_t> value = Assembler::extractLuiOriValue(&inst[0], &inst[1]);
  1.1384 +    JS_ASSERT(value == uint32_t(expectedValue.value));
  1.1385 +
  1.1386 +    // Replace with new value
  1.1387 +    Assembler::updateLuiOriValue(inst, inst->next(), uint32_t(newValue.value));
  1.1388 +
  1.1389 +    AutoFlushICache::flush(uintptr_t(inst), 8);
  1.1390 +}
  1.1391 +
  1.1392 +void
  1.1393 +Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue)
  1.1394 +{
  1.1395 +    patchDataWithValueCheck(label, PatchedImmPtr(newValue.value),
  1.1396 +                            PatchedImmPtr(expectedValue.value));
  1.1397 +}
  1.1398 +
  1.1399 +// This just stomps over memory with 32 bits of raw data. Its purpose is to
  1.1400 +// overwrite the call of JITed code with 32 bits worth of an offset. This will
  1.1401 +// is only meant to function on code that has been invalidated, so it should
  1.1402 +// be totally safe. Since that instruction will never be executed again, a
  1.1403 +// ICache flush should not be necessary
  1.1404 +void
  1.1405 +Assembler::patchWrite_Imm32(CodeLocationLabel label, Imm32 imm)
  1.1406 +{
  1.1407 +    // Raw is going to be the return address.
  1.1408 +    uint32_t *raw = (uint32_t*)label.raw();
  1.1409 +    // Overwrite the 4 bytes before the return address, which will
  1.1410 +    // end up being the call instruction.
  1.1411 +    *(raw - 1) = imm.value;
  1.1412 +}
  1.1413 +
  1.1414 +uint8_t *
  1.1415 +Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
  1.1416 +{
  1.1417 +    Instruction *inst = reinterpret_cast<Instruction*>(inst_);
  1.1418 +    if (count != nullptr)
  1.1419 +        *count += sizeof(Instruction);
  1.1420 +    return reinterpret_cast<uint8_t*>(inst->next());
  1.1421 +}
  1.1422 +
  1.1423 +// Since there are no pools in MIPS implementation, this should be simple.
  1.1424 +Instruction *
  1.1425 +Instruction::next()
  1.1426 +{
  1.1427 +    return this + 1;
  1.1428 +}
  1.1429 +
  1.1430 +InstImm Assembler::invertBranch(InstImm branch, BOffImm16 skipOffset)
  1.1431 +{
  1.1432 +    uint32_t rt = 0;
  1.1433 +    Opcode op = (Opcode) (branch.extractOpcode() << OpcodeShift);
  1.1434 +    switch(op) {
  1.1435 +      case op_beq:
  1.1436 +        branch.setBOffImm16(skipOffset);
  1.1437 +        branch.setOpcode(op_bne);
  1.1438 +        return branch;
  1.1439 +      case op_bne:
  1.1440 +        branch.setBOffImm16(skipOffset);
  1.1441 +        branch.setOpcode(op_beq);
  1.1442 +        return branch;
  1.1443 +      case op_bgtz:
  1.1444 +        branch.setBOffImm16(skipOffset);
  1.1445 +        branch.setOpcode(op_blez);
  1.1446 +        return branch;
  1.1447 +      case op_blez:
  1.1448 +        branch.setBOffImm16(skipOffset);
  1.1449 +        branch.setOpcode(op_bgtz);
  1.1450 +        return branch;
  1.1451 +      case op_regimm:
  1.1452 +        branch.setBOffImm16(skipOffset);
  1.1453 +        rt = branch.extractRT();
  1.1454 +        if (rt == (rt_bltz >> RTShift)) {
  1.1455 +            branch.setRT(rt_bgez);
  1.1456 +            return branch;
  1.1457 +        }
  1.1458 +        if (rt == (rt_bgez >> RTShift)) {
  1.1459 +            branch.setRT(rt_bltz);
  1.1460 +            return branch;
  1.1461 +        }
  1.1462 +
  1.1463 +        MOZ_ASSUME_UNREACHABLE("Error creating long branch.");
  1.1464 +        return branch;
  1.1465 +
  1.1466 +      case op_cop1:
  1.1467 +        JS_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
  1.1468 +
  1.1469 +        branch.setBOffImm16(skipOffset);
  1.1470 +        rt = branch.extractRT();
  1.1471 +        if (rt & 0x1)
  1.1472 +            branch.setRT((RTField) ((rt & ~0x1) << RTShift));
  1.1473 +        else
  1.1474 +            branch.setRT((RTField) ((rt | 0x1) << RTShift));
  1.1475 +        return branch;
  1.1476 +    }
  1.1477 +
  1.1478 +    MOZ_ASSUME_UNREACHABLE("Error creating long branch.");
  1.1479 +    return branch;
  1.1480 +}
  1.1481 +
  1.1482 +void
  1.1483 +Assembler::ToggleToJmp(CodeLocationLabel inst_)
  1.1484 +{
  1.1485 +    InstImm * inst = (InstImm *)inst_.raw();
  1.1486 +
  1.1487 +    JS_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift));
  1.1488 +    // We converted beq to andi, so now we restore it.
  1.1489 +    inst->setOpcode(op_beq);
  1.1490 +
  1.1491 +    AutoFlushICache::flush(uintptr_t(inst), 4);
  1.1492 +}
  1.1493 +
  1.1494 +void
  1.1495 +Assembler::ToggleToCmp(CodeLocationLabel inst_)
  1.1496 +{
  1.1497 +    InstImm * inst = (InstImm *)inst_.raw();
  1.1498 +
  1.1499 +    // toggledJump is allways used for short jumps.
  1.1500 +    JS_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift));
  1.1501 +    // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset"
  1.1502 +    inst->setOpcode(op_andi);
  1.1503 +
  1.1504 +    AutoFlushICache::flush(uintptr_t(inst), 4);
  1.1505 +}
  1.1506 +
  1.1507 +void
  1.1508 +Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
  1.1509 +{
  1.1510 +    Instruction *inst = (Instruction *)inst_.raw();
  1.1511 +    InstImm *i0 = (InstImm *) inst;
  1.1512 +    InstImm *i1 = (InstImm *) i0->next();
  1.1513 +    Instruction *i2 = (Instruction *) i1->next();
  1.1514 +
  1.1515 +    JS_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
  1.1516 +    JS_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
  1.1517 +
  1.1518 +    if (enabled) {
  1.1519 +        InstReg jalr = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
  1.1520 +        *i2 = jalr;
  1.1521 +    } else {
  1.1522 +        InstNOP nop;
  1.1523 +        *i2 = nop;
  1.1524 +    }
  1.1525 +
  1.1526 +    AutoFlushICache::flush(uintptr_t(i2), 4);
  1.1527 +}
  1.1528 +
  1.1529 +void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst)
  1.1530 +{
  1.1531 +    MOZ_ASSUME_UNREACHABLE("NYI");
  1.1532 +}

mercurial