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 +}