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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/mips/Assembler-mips.h"
michael@0 8
michael@0 9 #include "mozilla/DebugOnly.h"
michael@0 10 #include "mozilla/MathAlgorithms.h"
michael@0 11
michael@0 12 #include "jscompartment.h"
michael@0 13 #include "jsutil.h"
michael@0 14
michael@0 15 #include "assembler/jit/ExecutableAllocator.h"
michael@0 16 #include "gc/Marking.h"
michael@0 17 #include "jit/JitCompartment.h"
michael@0 18
michael@0 19 using mozilla::DebugOnly;
michael@0 20
michael@0 21 using namespace js;
michael@0 22 using namespace js::jit;
michael@0 23
michael@0 24 ABIArgGenerator::ABIArgGenerator()
michael@0 25 : usedArgSlots_(0),
michael@0 26 firstArgFloat(false),
michael@0 27 current_()
michael@0 28 {}
michael@0 29
michael@0 30 ABIArg
michael@0 31 ABIArgGenerator::next(MIRType type)
michael@0 32 {
michael@0 33 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 34 return ABIArg();
michael@0 35 }
michael@0 36 const Register ABIArgGenerator::NonArgReturnVolatileReg0 = t0;
michael@0 37 const Register ABIArgGenerator::NonArgReturnVolatileReg1 = t1;
michael@0 38
michael@0 39 // Encode a standard register when it is being used as rd, the rs, and
michael@0 40 // an extra register(rt). These should never be called with an InvalidReg.
michael@0 41 uint32_t
michael@0 42 js::jit::RS(Register r)
michael@0 43 {
michael@0 44 JS_ASSERT((r.code() & ~RegMask) == 0);
michael@0 45 return r.code() << RSShift;
michael@0 46 }
michael@0 47
michael@0 48 uint32_t
michael@0 49 js::jit::RT(Register r)
michael@0 50 {
michael@0 51 JS_ASSERT((r.code() & ~RegMask) == 0);
michael@0 52 return r.code() << RTShift;
michael@0 53 }
michael@0 54
michael@0 55 uint32_t
michael@0 56 js::jit::RT(FloatRegister r)
michael@0 57 {
michael@0 58 JS_ASSERT(r.code() < FloatRegisters::Total);
michael@0 59 return r.code() << RTShift;
michael@0 60 }
michael@0 61
michael@0 62 uint32_t
michael@0 63 js::jit::RD(Register r)
michael@0 64 {
michael@0 65 JS_ASSERT((r.code() & ~RegMask) == 0);
michael@0 66 return r.code() << RDShift;
michael@0 67 }
michael@0 68
michael@0 69 uint32_t
michael@0 70 js::jit::RD(FloatRegister r)
michael@0 71 {
michael@0 72 JS_ASSERT(r.code() < FloatRegisters::Total);
michael@0 73 return r.code() << RDShift;
michael@0 74 }
michael@0 75
michael@0 76 uint32_t
michael@0 77 js::jit::SA(uint32_t value)
michael@0 78 {
michael@0 79 JS_ASSERT(value < 32);
michael@0 80 return value << SAShift;
michael@0 81 }
michael@0 82
michael@0 83 uint32_t
michael@0 84 js::jit::SA(FloatRegister r)
michael@0 85 {
michael@0 86 JS_ASSERT(r.code() < FloatRegisters::Total);
michael@0 87 return r.code() << SAShift;
michael@0 88 }
michael@0 89
michael@0 90 Register
michael@0 91 js::jit::toRS(Instruction &i)
michael@0 92 {
michael@0 93 return Register::FromCode((i.encode() & RSMask ) >> RSShift);
michael@0 94 }
michael@0 95
michael@0 96 Register
michael@0 97 js::jit::toRT(Instruction &i)
michael@0 98 {
michael@0 99 return Register::FromCode((i.encode() & RTMask ) >> RTShift);
michael@0 100 }
michael@0 101
michael@0 102 Register
michael@0 103 js::jit::toRD(Instruction &i)
michael@0 104 {
michael@0 105 return Register::FromCode((i.encode() & RDMask ) >> RDShift);
michael@0 106 }
michael@0 107
michael@0 108 Register
michael@0 109 js::jit::toR(Instruction &i)
michael@0 110 {
michael@0 111 return Register::FromCode(i.encode() & RegMask);
michael@0 112 }
michael@0 113
michael@0 114 void
michael@0 115 InstImm::extractImm16(BOffImm16 *dest)
michael@0 116 {
michael@0 117 *dest = BOffImm16(*this);
michael@0 118 }
michael@0 119
michael@0 120 // Used to patch jumps created by MacroAssemblerMIPSCompat::jumpWithPatch.
michael@0 121 void
michael@0 122 jit::PatchJump(CodeLocationJump &jump_, CodeLocationLabel label)
michael@0 123 {
michael@0 124 Instruction *inst1 = (Instruction *)jump_.raw();
michael@0 125 Instruction *inst2 = inst1->next();
michael@0 126
michael@0 127 Assembler::updateLuiOriValue(inst1, inst2, (uint32_t)label.raw());
michael@0 128
michael@0 129 AutoFlushICache::flush(uintptr_t(inst1), 8);
michael@0 130 }
michael@0 131
michael@0 132 void
michael@0 133 Assembler::finish()
michael@0 134 {
michael@0 135 JS_ASSERT(!isFinished);
michael@0 136 isFinished = true;
michael@0 137 }
michael@0 138
michael@0 139 void
michael@0 140 Assembler::executableCopy(uint8_t *buffer)
michael@0 141 {
michael@0 142 JS_ASSERT(isFinished);
michael@0 143 m_buffer.executableCopy(buffer);
michael@0 144
michael@0 145 // Patch all long jumps during code copy.
michael@0 146 for (size_t i = 0; i < longJumps_.length(); i++) {
michael@0 147 Instruction *inst1 = (Instruction *) ((uint32_t)buffer + longJumps_[i]);
michael@0 148
michael@0 149 uint32_t value = extractLuiOriValue(inst1, inst1->next());
michael@0 150 updateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value);
michael@0 151 }
michael@0 152
michael@0 153 AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
michael@0 154 }
michael@0 155
michael@0 156 uint32_t
michael@0 157 Assembler::actualOffset(uint32_t off_) const
michael@0 158 {
michael@0 159 return off_;
michael@0 160 }
michael@0 161
michael@0 162 uint32_t
michael@0 163 Assembler::actualIndex(uint32_t idx_) const
michael@0 164 {
michael@0 165 return idx_;
michael@0 166 }
michael@0 167
michael@0 168 uint8_t *
michael@0 169 Assembler::PatchableJumpAddress(JitCode *code, uint32_t pe_)
michael@0 170 {
michael@0 171 return code->raw() + pe_;
michael@0 172 }
michael@0 173
michael@0 174 class RelocationIterator
michael@0 175 {
michael@0 176 CompactBufferReader reader_;
michael@0 177 // offset in bytes
michael@0 178 uint32_t offset_;
michael@0 179
michael@0 180 public:
michael@0 181 RelocationIterator(CompactBufferReader &reader)
michael@0 182 : reader_(reader)
michael@0 183 { }
michael@0 184
michael@0 185 bool read() {
michael@0 186 if (!reader_.more())
michael@0 187 return false;
michael@0 188 offset_ = reader_.readUnsigned();
michael@0 189 return true;
michael@0 190 }
michael@0 191
michael@0 192 uint32_t offset() const {
michael@0 193 return offset_;
michael@0 194 }
michael@0 195 };
michael@0 196
michael@0 197 uintptr_t
michael@0 198 Assembler::getPointer(uint8_t *instPtr)
michael@0 199 {
michael@0 200 Instruction *inst = (Instruction*)instPtr;
michael@0 201 return Assembler::extractLuiOriValue(inst, inst->next());
michael@0 202 }
michael@0 203
michael@0 204 static JitCode *
michael@0 205 CodeFromJump(Instruction *jump)
michael@0 206 {
michael@0 207 uint8_t *target = (uint8_t *)Assembler::extractLuiOriValue(jump, jump->next());
michael@0 208 return JitCode::FromExecutable(target);
michael@0 209 }
michael@0 210
michael@0 211 void
michael@0 212 Assembler::TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
michael@0 213 {
michael@0 214 RelocationIterator iter(reader);
michael@0 215 while (iter.read()) {
michael@0 216 JitCode *child = CodeFromJump((Instruction *)(code->raw() + iter.offset()));
michael@0 217 MarkJitCodeUnbarriered(trc, &child, "rel32");
michael@0 218 }
michael@0 219 }
michael@0 220
michael@0 221 static void
michael@0 222 TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
michael@0 223 {
michael@0 224 while (reader.more()) {
michael@0 225 size_t offset = reader.readUnsigned();
michael@0 226 Instruction *inst = (Instruction*)(buffer + offset);
michael@0 227 void *ptr = (void *)Assembler::extractLuiOriValue(inst, inst->next());
michael@0 228
michael@0 229 // No barrier needed since these are constants.
michael@0 230 gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
michael@0 231 }
michael@0 232 }
michael@0 233
michael@0 234 static void
michael@0 235 TraceDataRelocations(JSTracer *trc, MIPSBuffer *buffer, CompactBufferReader &reader)
michael@0 236 {
michael@0 237 while (reader.more()) {
michael@0 238 BufferOffset bo (reader.readUnsigned());
michael@0 239 MIPSBuffer::AssemblerBufferInstIterator iter(bo, buffer);
michael@0 240
michael@0 241 void *ptr = (void *)Assembler::extractLuiOriValue(iter.cur(), iter.next());
michael@0 242
michael@0 243 // No barrier needed since these are constants.
michael@0 244 gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
michael@0 245 }
michael@0 246 }
michael@0 247
michael@0 248 void
michael@0 249 Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
michael@0 250 {
michael@0 251 ::TraceDataRelocations(trc, code->raw(), reader);
michael@0 252 }
michael@0 253
michael@0 254 void
michael@0 255 Assembler::copyJumpRelocationTable(uint8_t *dest)
michael@0 256 {
michael@0 257 if (jumpRelocations_.length())
michael@0 258 memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
michael@0 259 }
michael@0 260
michael@0 261 void
michael@0 262 Assembler::copyDataRelocationTable(uint8_t *dest)
michael@0 263 {
michael@0 264 if (dataRelocations_.length())
michael@0 265 memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
michael@0 266 }
michael@0 267
michael@0 268 void
michael@0 269 Assembler::copyPreBarrierTable(uint8_t *dest)
michael@0 270 {
michael@0 271 if (preBarriers_.length())
michael@0 272 memcpy(dest, preBarriers_.buffer(), preBarriers_.length());
michael@0 273 }
michael@0 274
michael@0 275 void
michael@0 276 Assembler::trace(JSTracer *trc)
michael@0 277 {
michael@0 278 for (size_t i = 0; i < jumps_.length(); i++) {
michael@0 279 RelativePatch &rp = jumps_[i];
michael@0 280 if (rp.kind == Relocation::JITCODE) {
michael@0 281 JitCode *code = JitCode::FromExecutable((uint8_t *)rp.target);
michael@0 282 MarkJitCodeUnbarriered(trc, &code, "masmrel32");
michael@0 283 JS_ASSERT(code == JitCode::FromExecutable((uint8_t *)rp.target));
michael@0 284 }
michael@0 285 }
michael@0 286 if (dataRelocations_.length()) {
michael@0 287 CompactBufferReader reader(dataRelocations_);
michael@0 288 ::TraceDataRelocations(trc, &m_buffer, reader);
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 void
michael@0 293 Assembler::processCodeLabels(uint8_t *rawCode)
michael@0 294 {
michael@0 295 for (size_t i = 0; i < codeLabels_.length(); i++) {
michael@0 296 CodeLabel label = codeLabels_[i];
michael@0 297 Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset()));
michael@0 298 }
michael@0 299 }
michael@0 300
michael@0 301 void
michael@0 302 Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
michael@0 303 {
michael@0 304 if (label->used()) {
michael@0 305 int32_t src = label->offset();
michael@0 306 do {
michael@0 307 Instruction *inst = (Instruction *) (rawCode + src);
michael@0 308 uint32_t next = Assembler::extractLuiOriValue(inst, inst->next());
michael@0 309 Assembler::updateLuiOriValue(inst, inst->next(), (uint32_t)address);
michael@0 310 src = next;
michael@0 311 } while (src != AbsoluteLabel::INVALID_OFFSET);
michael@0 312 }
michael@0 313 label->bind();
michael@0 314 }
michael@0 315
michael@0 316 Assembler::Condition
michael@0 317 Assembler::InvertCondition(Condition cond)
michael@0 318 {
michael@0 319 switch (cond) {
michael@0 320 case Equal:
michael@0 321 return NotEqual;
michael@0 322 case NotEqual:
michael@0 323 return Equal;
michael@0 324 case Zero:
michael@0 325 return NonZero;
michael@0 326 case NonZero:
michael@0 327 return Zero;
michael@0 328 case LessThan:
michael@0 329 return GreaterThanOrEqual;
michael@0 330 case LessThanOrEqual:
michael@0 331 return GreaterThan;
michael@0 332 case GreaterThan:
michael@0 333 return LessThanOrEqual;
michael@0 334 case GreaterThanOrEqual:
michael@0 335 return LessThan;
michael@0 336 case Above:
michael@0 337 return BelowOrEqual;
michael@0 338 case AboveOrEqual:
michael@0 339 return Below;
michael@0 340 case Below:
michael@0 341 return AboveOrEqual;
michael@0 342 case BelowOrEqual:
michael@0 343 return Above;
michael@0 344 case Signed:
michael@0 345 return NotSigned;
michael@0 346 case NotSigned:
michael@0 347 return Signed;
michael@0 348 default:
michael@0 349 MOZ_ASSUME_UNREACHABLE("unexpected condition");
michael@0 350 return Equal;
michael@0 351 }
michael@0 352 }
michael@0 353
michael@0 354 Assembler::DoubleCondition
michael@0 355 Assembler::InvertCondition(DoubleCondition cond)
michael@0 356 {
michael@0 357 switch (cond) {
michael@0 358 case DoubleOrdered:
michael@0 359 return DoubleUnordered;
michael@0 360 case DoubleEqual:
michael@0 361 return DoubleNotEqualOrUnordered;
michael@0 362 case DoubleNotEqual:
michael@0 363 return DoubleEqualOrUnordered;
michael@0 364 case DoubleGreaterThan:
michael@0 365 return DoubleLessThanOrEqualOrUnordered;
michael@0 366 case DoubleGreaterThanOrEqual:
michael@0 367 return DoubleLessThanOrUnordered;
michael@0 368 case DoubleLessThan:
michael@0 369 return DoubleGreaterThanOrEqualOrUnordered;
michael@0 370 case DoubleLessThanOrEqual:
michael@0 371 return DoubleGreaterThanOrUnordered;
michael@0 372 case DoubleUnordered:
michael@0 373 return DoubleOrdered;
michael@0 374 case DoubleEqualOrUnordered:
michael@0 375 return DoubleNotEqual;
michael@0 376 case DoubleNotEqualOrUnordered:
michael@0 377 return DoubleEqual;
michael@0 378 case DoubleGreaterThanOrUnordered:
michael@0 379 return DoubleLessThanOrEqual;
michael@0 380 case DoubleGreaterThanOrEqualOrUnordered:
michael@0 381 return DoubleLessThan;
michael@0 382 case DoubleLessThanOrUnordered:
michael@0 383 return DoubleGreaterThanOrEqual;
michael@0 384 case DoubleLessThanOrEqualOrUnordered:
michael@0 385 return DoubleGreaterThan;
michael@0 386 default:
michael@0 387 MOZ_ASSUME_UNREACHABLE("unexpected condition");
michael@0 388 return DoubleEqual;
michael@0 389 }
michael@0 390 }
michael@0 391
michael@0 392 BOffImm16::BOffImm16(InstImm inst)
michael@0 393 : data(inst.encode() & Imm16Mask)
michael@0 394 {
michael@0 395 }
michael@0 396
michael@0 397 bool
michael@0 398 Assembler::oom() const
michael@0 399 {
michael@0 400 return m_buffer.oom() ||
michael@0 401 !enoughMemory_ ||
michael@0 402 jumpRelocations_.oom() ||
michael@0 403 dataRelocations_.oom() ||
michael@0 404 preBarriers_.oom();
michael@0 405 }
michael@0 406
michael@0 407 bool
michael@0 408 Assembler::addCodeLabel(CodeLabel label)
michael@0 409 {
michael@0 410 return codeLabels_.append(label);
michael@0 411 }
michael@0 412
michael@0 413 // Size of the instruction stream, in bytes.
michael@0 414 size_t
michael@0 415 Assembler::size() const
michael@0 416 {
michael@0 417 return m_buffer.size();
michael@0 418 }
michael@0 419
michael@0 420 // Size of the relocation table, in bytes.
michael@0 421 size_t
michael@0 422 Assembler::jumpRelocationTableBytes() const
michael@0 423 {
michael@0 424 return jumpRelocations_.length();
michael@0 425 }
michael@0 426
michael@0 427 size_t
michael@0 428 Assembler::dataRelocationTableBytes() const
michael@0 429 {
michael@0 430 return dataRelocations_.length();
michael@0 431 }
michael@0 432
michael@0 433 size_t
michael@0 434 Assembler::preBarrierTableBytes() const
michael@0 435 {
michael@0 436 return preBarriers_.length();
michael@0 437 }
michael@0 438
michael@0 439 // Size of the data table, in bytes.
michael@0 440 size_t
michael@0 441 Assembler::bytesNeeded() const
michael@0 442 {
michael@0 443 return size() +
michael@0 444 jumpRelocationTableBytes() +
michael@0 445 dataRelocationTableBytes() +
michael@0 446 preBarrierTableBytes();
michael@0 447 }
michael@0 448
michael@0 449 // write a blob of binary into the instruction stream
michael@0 450 BufferOffset
michael@0 451 Assembler::writeInst(uint32_t x, uint32_t *dest)
michael@0 452 {
michael@0 453 if (dest == nullptr)
michael@0 454 return m_buffer.putInt(x);
michael@0 455
michael@0 456 writeInstStatic(x, dest);
michael@0 457 return BufferOffset();
michael@0 458 }
michael@0 459
michael@0 460 void
michael@0 461 Assembler::writeInstStatic(uint32_t x, uint32_t *dest)
michael@0 462 {
michael@0 463 JS_ASSERT(dest != nullptr);
michael@0 464 *dest = x;
michael@0 465 }
michael@0 466
michael@0 467 BufferOffset
michael@0 468 Assembler::align(int alignment)
michael@0 469 {
michael@0 470 BufferOffset ret;
michael@0 471 JS_ASSERT(m_buffer.isAligned(4));
michael@0 472 if (alignment == 8) {
michael@0 473 if (!m_buffer.isAligned(alignment)) {
michael@0 474 BufferOffset tmp = as_nop();
michael@0 475 if (!ret.assigned())
michael@0 476 ret = tmp;
michael@0 477 }
michael@0 478 } else {
michael@0 479 JS_ASSERT((alignment & (alignment - 1)) == 0);
michael@0 480 while (size() & (alignment - 1)) {
michael@0 481 BufferOffset tmp = as_nop();
michael@0 482 if (!ret.assigned())
michael@0 483 ret = tmp;
michael@0 484 }
michael@0 485 }
michael@0 486 return ret;
michael@0 487 }
michael@0 488
michael@0 489 BufferOffset
michael@0 490 Assembler::as_nop()
michael@0 491 {
michael@0 492 return writeInst(op_special | ff_sll);
michael@0 493 }
michael@0 494
michael@0 495 // Logical operations.
michael@0 496 BufferOffset
michael@0 497 Assembler::as_and(Register rd, Register rs, Register rt)
michael@0 498 {
michael@0 499 return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode());
michael@0 500 }
michael@0 501
michael@0 502 BufferOffset
michael@0 503 Assembler::as_or(Register rd, Register rs, Register rt)
michael@0 504 {
michael@0 505 return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode());
michael@0 506 }
michael@0 507
michael@0 508 BufferOffset
michael@0 509 Assembler::as_xor(Register rd, Register rs, Register rt)
michael@0 510 {
michael@0 511 return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode());
michael@0 512 }
michael@0 513
michael@0 514 BufferOffset
michael@0 515 Assembler::as_nor(Register rd, Register rs, Register rt)
michael@0 516 {
michael@0 517 return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode());
michael@0 518 }
michael@0 519
michael@0 520 BufferOffset
michael@0 521 Assembler::as_andi(Register rd, Register rs, int32_t j)
michael@0 522 {
michael@0 523 JS_ASSERT(Imm16::isInUnsignedRange(j));
michael@0 524 return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode());
michael@0 525 }
michael@0 526
michael@0 527 BufferOffset
michael@0 528 Assembler::as_ori(Register rd, Register rs, int32_t j)
michael@0 529 {
michael@0 530 JS_ASSERT(Imm16::isInUnsignedRange(j));
michael@0 531 return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode());
michael@0 532 }
michael@0 533
michael@0 534 BufferOffset
michael@0 535 Assembler::as_xori(Register rd, Register rs, int32_t j)
michael@0 536 {
michael@0 537 JS_ASSERT(Imm16::isInUnsignedRange(j));
michael@0 538 return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode());
michael@0 539 }
michael@0 540
michael@0 541 // Branch and jump instructions
michael@0 542 BufferOffset
michael@0 543 Assembler::as_bal(BOffImm16 off)
michael@0 544 {
michael@0 545 BufferOffset bo = writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode());
michael@0 546 return bo;
michael@0 547 }
michael@0 548
michael@0 549 InstImm
michael@0 550 Assembler::getBranchCode(JumpOrCall jumpOrCall)
michael@0 551 {
michael@0 552 if (jumpOrCall == BranchIsCall)
michael@0 553 return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
michael@0 554
michael@0 555 return InstImm(op_beq, zero, zero, BOffImm16(0));
michael@0 556 }
michael@0 557
michael@0 558 InstImm
michael@0 559 Assembler::getBranchCode(Register s, Register t, Condition c)
michael@0 560 {
michael@0 561 JS_ASSERT(c == Assembler::Equal || c == Assembler::NotEqual);
michael@0 562 return InstImm(c == Assembler::Equal ? op_beq : op_bne, s, t, BOffImm16(0));
michael@0 563 }
michael@0 564
michael@0 565 InstImm
michael@0 566 Assembler::getBranchCode(Register s, Condition c)
michael@0 567 {
michael@0 568 switch (c) {
michael@0 569 case Assembler::Equal:
michael@0 570 case Assembler::Zero:
michael@0 571 case Assembler::BelowOrEqual:
michael@0 572 return InstImm(op_beq, s, zero, BOffImm16(0));
michael@0 573 case Assembler::NotEqual:
michael@0 574 case Assembler::NonZero:
michael@0 575 case Assembler::Above:
michael@0 576 return InstImm(op_bne, s, zero, BOffImm16(0));
michael@0 577 case Assembler::GreaterThan:
michael@0 578 return InstImm(op_bgtz, s, zero, BOffImm16(0));
michael@0 579 case Assembler::GreaterThanOrEqual:
michael@0 580 case Assembler::NotSigned:
michael@0 581 return InstImm(op_regimm, s, rt_bgez, BOffImm16(0));
michael@0 582 case Assembler::LessThan:
michael@0 583 case Assembler::Signed:
michael@0 584 return InstImm(op_regimm, s, rt_bltz, BOffImm16(0));
michael@0 585 case Assembler::LessThanOrEqual:
michael@0 586 return InstImm(op_blez, s, zero, BOffImm16(0));
michael@0 587 default:
michael@0 588 MOZ_ASSUME_UNREACHABLE("Condition not supported.");
michael@0 589 }
michael@0 590 }
michael@0 591
michael@0 592 InstImm
michael@0 593 Assembler::getBranchCode(FloatTestKind testKind, FPConditionBit fcc)
michael@0 594 {
michael@0 595 JS_ASSERT(!(fcc && FccMask));
michael@0 596 uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift)) << RTShift;
michael@0 597
michael@0 598 return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0));
michael@0 599 }
michael@0 600
michael@0 601 BufferOffset
michael@0 602 Assembler::as_j(JOffImm26 off)
michael@0 603 {
michael@0 604 BufferOffset bo = writeInst(InstJump(op_j, off).encode());
michael@0 605 return bo;
michael@0 606 }
michael@0 607 BufferOffset
michael@0 608 Assembler::as_jal(JOffImm26 off)
michael@0 609 {
michael@0 610 BufferOffset bo = writeInst(InstJump(op_jal, off).encode());
michael@0 611 return bo;
michael@0 612 }
michael@0 613
michael@0 614 BufferOffset
michael@0 615 Assembler::as_jr(Register rs)
michael@0 616 {
michael@0 617 BufferOffset bo = writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode());
michael@0 618 return bo;
michael@0 619 }
michael@0 620 BufferOffset
michael@0 621 Assembler::as_jalr(Register rs)
michael@0 622 {
michael@0 623 BufferOffset bo = writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode());
michael@0 624 return bo;
michael@0 625 }
michael@0 626
michael@0 627
michael@0 628 // Arithmetic instructions
michael@0 629 BufferOffset
michael@0 630 Assembler::as_addu(Register rd, Register rs, Register rt)
michael@0 631 {
michael@0 632 return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode());
michael@0 633 }
michael@0 634
michael@0 635 BufferOffset
michael@0 636 Assembler::as_addiu(Register rd, Register rs, int32_t j)
michael@0 637 {
michael@0 638 JS_ASSERT(Imm16::isInSignedRange(j));
michael@0 639 return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
michael@0 640 }
michael@0 641
michael@0 642 BufferOffset
michael@0 643 Assembler::as_subu(Register rd, Register rs, Register rt)
michael@0 644 {
michael@0 645 return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
michael@0 646 }
michael@0 647
michael@0 648 BufferOffset
michael@0 649 Assembler::as_mult(Register rs, Register rt)
michael@0 650 {
michael@0 651 return writeInst(InstReg(op_special, rs, rt, ff_mult).encode());
michael@0 652 }
michael@0 653
michael@0 654 BufferOffset
michael@0 655 Assembler::as_multu(Register rs, Register rt)
michael@0 656 {
michael@0 657 return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
michael@0 658 }
michael@0 659
michael@0 660 BufferOffset
michael@0 661 Assembler::as_div(Register rs, Register rt)
michael@0 662 {
michael@0 663 return writeInst(InstReg(op_special, rs, rt, ff_div).encode());
michael@0 664 }
michael@0 665
michael@0 666 BufferOffset
michael@0 667 Assembler::as_divu(Register rs, Register rt)
michael@0 668 {
michael@0 669 return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
michael@0 670 }
michael@0 671
michael@0 672 BufferOffset
michael@0 673 Assembler::as_mul(Register rd, Register rs, Register rt)
michael@0 674 {
michael@0 675 return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode());
michael@0 676 }
michael@0 677
michael@0 678 BufferOffset
michael@0 679 Assembler::as_lui(Register rd, int32_t j)
michael@0 680 {
michael@0 681 JS_ASSERT(Imm16::isInUnsignedRange(j));
michael@0 682 return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode());
michael@0 683 }
michael@0 684
michael@0 685 // Shift instructions
michael@0 686 BufferOffset
michael@0 687 Assembler::as_sll(Register rd, Register rt, uint16_t sa)
michael@0 688 {
michael@0 689 JS_ASSERT(sa < 32);
michael@0 690 return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
michael@0 691 }
michael@0 692
michael@0 693 BufferOffset
michael@0 694 Assembler::as_sllv(Register rd, Register rt, Register rs)
michael@0 695 {
michael@0 696 return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
michael@0 697 }
michael@0 698
michael@0 699 BufferOffset
michael@0 700 Assembler::as_srl(Register rd, Register rt, uint16_t sa)
michael@0 701 {
michael@0 702 JS_ASSERT(sa < 32);
michael@0 703 return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
michael@0 704 }
michael@0 705
michael@0 706 BufferOffset
michael@0 707 Assembler::as_srlv(Register rd, Register rt, Register rs)
michael@0 708 {
michael@0 709 return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
michael@0 710 }
michael@0 711
michael@0 712 BufferOffset
michael@0 713 Assembler::as_sra(Register rd, Register rt, uint16_t sa)
michael@0 714 {
michael@0 715 JS_ASSERT(sa < 32);
michael@0 716 return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
michael@0 717 }
michael@0 718
michael@0 719 BufferOffset
michael@0 720 Assembler::as_srav(Register rd, Register rt, Register rs)
michael@0 721 {
michael@0 722 return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
michael@0 723 }
michael@0 724
michael@0 725 BufferOffset
michael@0 726 Assembler::as_rotr(Register rd, Register rt, uint16_t sa)
michael@0 727 {
michael@0 728 JS_ASSERT(sa < 32);
michael@0 729 return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
michael@0 730 }
michael@0 731
michael@0 732 BufferOffset
michael@0 733 Assembler::as_rotrv(Register rd, Register rt, Register rs)
michael@0 734 {
michael@0 735 return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
michael@0 736 }
michael@0 737
michael@0 738 // Load and store instructions
michael@0 739 BufferOffset
michael@0 740 Assembler::as_lb(Register rd, Register rs, int16_t off)
michael@0 741 {
michael@0 742 return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode());
michael@0 743 }
michael@0 744
michael@0 745 BufferOffset
michael@0 746 Assembler::as_lbu(Register rd, Register rs, int16_t off)
michael@0 747 {
michael@0 748 return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode());
michael@0 749 }
michael@0 750
michael@0 751 BufferOffset
michael@0 752 Assembler::as_lh(Register rd, Register rs, int16_t off)
michael@0 753 {
michael@0 754 return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode());
michael@0 755 }
michael@0 756
michael@0 757 BufferOffset
michael@0 758 Assembler::as_lhu(Register rd, Register rs, int16_t off)
michael@0 759 {
michael@0 760 return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode());
michael@0 761 }
michael@0 762
michael@0 763 BufferOffset
michael@0 764 Assembler::as_lw(Register rd, Register rs, int16_t off)
michael@0 765 {
michael@0 766 return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
michael@0 767 }
michael@0 768
michael@0 769 BufferOffset
michael@0 770 Assembler::as_lwl(Register rd, Register rs, int16_t off)
michael@0 771 {
michael@0 772 return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode());
michael@0 773 }
michael@0 774
michael@0 775 BufferOffset
michael@0 776 Assembler::as_lwr(Register rd, Register rs, int16_t off)
michael@0 777 {
michael@0 778 return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
michael@0 779 }
michael@0 780
michael@0 781 BufferOffset
michael@0 782 Assembler::as_sb(Register rd, Register rs, int16_t off)
michael@0 783 {
michael@0 784 return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode());
michael@0 785 }
michael@0 786
michael@0 787 BufferOffset
michael@0 788 Assembler::as_sh(Register rd, Register rs, int16_t off)
michael@0 789 {
michael@0 790 return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode());
michael@0 791 }
michael@0 792
michael@0 793 BufferOffset
michael@0 794 Assembler::as_sw(Register rd, Register rs, int16_t off)
michael@0 795 {
michael@0 796 return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode());
michael@0 797 }
michael@0 798
michael@0 799 BufferOffset
michael@0 800 Assembler::as_swl(Register rd, Register rs, int16_t off)
michael@0 801 {
michael@0 802 return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode());
michael@0 803 }
michael@0 804
michael@0 805 BufferOffset
michael@0 806 Assembler::as_swr(Register rd, Register rs, int16_t off)
michael@0 807 {
michael@0 808 return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
michael@0 809 }
michael@0 810
michael@0 811 // Move from HI/LO register.
michael@0 812 BufferOffset
michael@0 813 Assembler::as_mfhi(Register rd)
michael@0 814 {
michael@0 815 return writeInst(InstReg(op_special, rd, ff_mfhi).encode());
michael@0 816 }
michael@0 817
michael@0 818 BufferOffset
michael@0 819 Assembler::as_mflo(Register rd)
michael@0 820 {
michael@0 821 return writeInst(InstReg(op_special, rd, ff_mflo).encode());
michael@0 822 }
michael@0 823
michael@0 824 // Set on less than.
michael@0 825 BufferOffset
michael@0 826 Assembler::as_slt(Register rd, Register rs, Register rt)
michael@0 827 {
michael@0 828 return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode());
michael@0 829 }
michael@0 830
michael@0 831 BufferOffset
michael@0 832 Assembler::as_sltu(Register rd, Register rs, Register rt)
michael@0 833 {
michael@0 834 return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode());
michael@0 835 }
michael@0 836
michael@0 837 BufferOffset
michael@0 838 Assembler::as_slti(Register rd, Register rs, int32_t j)
michael@0 839 {
michael@0 840 JS_ASSERT(Imm16::isInSignedRange(j));
michael@0 841 return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode());
michael@0 842 }
michael@0 843
michael@0 844 BufferOffset
michael@0 845 Assembler::as_sltiu(Register rd, Register rs, uint32_t j)
michael@0 846 {
michael@0 847 JS_ASSERT(Imm16::isInUnsignedRange(j));
michael@0 848 return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode());
michael@0 849 }
michael@0 850
michael@0 851 // Conditional move.
michael@0 852 BufferOffset
michael@0 853 Assembler::as_movz(Register rd, Register rs, Register rt)
michael@0 854 {
michael@0 855 return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode());
michael@0 856 }
michael@0 857
michael@0 858 BufferOffset
michael@0 859 Assembler::as_movn(Register rd, Register rs, Register rt)
michael@0 860 {
michael@0 861 return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode());
michael@0 862 }
michael@0 863
michael@0 864 BufferOffset
michael@0 865 Assembler::as_movt(Register rd, Register rs, uint16_t cc)
michael@0 866 {
michael@0 867 Register rt;
michael@0 868 rt = Register::FromCode((cc & 0x7) << 2 | 1);
michael@0 869 return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
michael@0 870 }
michael@0 871
michael@0 872 BufferOffset
michael@0 873 Assembler::as_movf(Register rd, Register rs, uint16_t cc)
michael@0 874 {
michael@0 875 Register rt;
michael@0 876 rt = Register::FromCode((cc & 0x7) << 2 | 0);
michael@0 877 return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
michael@0 878 }
michael@0 879
michael@0 880 // Bit twiddling.
michael@0 881 BufferOffset
michael@0 882 Assembler::as_clz(Register rd, Register rs, Register rt)
michael@0 883 {
michael@0 884 return writeInst(InstReg(op_special2, rs, rt, rd, ff_clz).encode());
michael@0 885 }
michael@0 886
michael@0 887 BufferOffset
michael@0 888 Assembler::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
michael@0 889 {
michael@0 890 JS_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
michael@0 891 Register rd;
michael@0 892 rd = Register::FromCode(pos + size - 1);
michael@0 893 return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
michael@0 894 }
michael@0 895
michael@0 896 BufferOffset
michael@0 897 Assembler::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
michael@0 898 {
michael@0 899 JS_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
michael@0 900 Register rd;
michael@0 901 rd = Register::FromCode(size - 1);
michael@0 902 return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
michael@0 903 }
michael@0 904
michael@0 905 // FP instructions
michael@0 906 BufferOffset
michael@0 907 Assembler::as_ld(FloatRegister fd, Register base, int32_t off)
michael@0 908 {
michael@0 909 JS_ASSERT(Imm16::isInSignedRange(off));
michael@0 910 return writeInst(InstImm(op_ldc1, base, fd, Imm16(off)).encode());
michael@0 911 }
michael@0 912
michael@0 913 BufferOffset
michael@0 914 Assembler::as_sd(FloatRegister fd, Register base, int32_t off)
michael@0 915 {
michael@0 916 JS_ASSERT(Imm16::isInSignedRange(off));
michael@0 917 return writeInst(InstImm(op_sdc1, base, fd, Imm16(off)).encode());
michael@0 918 }
michael@0 919
michael@0 920 BufferOffset
michael@0 921 Assembler::as_ls(FloatRegister fd, Register base, int32_t off)
michael@0 922 {
michael@0 923 JS_ASSERT(Imm16::isInSignedRange(off));
michael@0 924 return writeInst(InstImm(op_lwc1, base, fd, Imm16(off)).encode());
michael@0 925 }
michael@0 926
michael@0 927 BufferOffset
michael@0 928 Assembler::as_ss(FloatRegister fd, Register base, int32_t off)
michael@0 929 {
michael@0 930 JS_ASSERT(Imm16::isInSignedRange(off));
michael@0 931 return writeInst(InstImm(op_swc1, base, fd, Imm16(off)).encode());
michael@0 932 }
michael@0 933
michael@0 934 BufferOffset
michael@0 935 Assembler::as_movs(FloatRegister fd, FloatRegister fs)
michael@0 936 {
michael@0 937 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode());
michael@0 938 }
michael@0 939
michael@0 940 BufferOffset
michael@0 941 Assembler::as_movd(FloatRegister fd, FloatRegister fs)
michael@0 942 {
michael@0 943 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode());
michael@0 944 }
michael@0 945
michael@0 946 BufferOffset
michael@0 947 Assembler::as_mtc1(Register rt, FloatRegister fs)
michael@0 948 {
michael@0 949 return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode());
michael@0 950 }
michael@0 951
michael@0 952 BufferOffset
michael@0 953 Assembler::as_mfc1(Register rt, FloatRegister fs)
michael@0 954 {
michael@0 955 return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
michael@0 956 }
michael@0 957
michael@0 958 // FP convert instructions
michael@0 959 BufferOffset
michael@0 960 Assembler::as_ceilws(FloatRegister fd, FloatRegister fs)
michael@0 961 {
michael@0 962 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode());
michael@0 963 }
michael@0 964
michael@0 965 BufferOffset
michael@0 966 Assembler::as_floorws(FloatRegister fd, FloatRegister fs)
michael@0 967 {
michael@0 968 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode());
michael@0 969 }
michael@0 970
michael@0 971 BufferOffset
michael@0 972 Assembler::as_roundws(FloatRegister fd, FloatRegister fs)
michael@0 973 {
michael@0 974 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode());
michael@0 975 }
michael@0 976
michael@0 977 BufferOffset
michael@0 978 Assembler::as_truncws(FloatRegister fd, FloatRegister fs)
michael@0 979 {
michael@0 980 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode());
michael@0 981 }
michael@0 982
michael@0 983 BufferOffset
michael@0 984 Assembler::as_ceilwd(FloatRegister fd, FloatRegister fs)
michael@0 985 {
michael@0 986 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode());
michael@0 987 }
michael@0 988
michael@0 989 BufferOffset
michael@0 990 Assembler::as_floorwd(FloatRegister fd, FloatRegister fs)
michael@0 991 {
michael@0 992 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode());
michael@0 993 }
michael@0 994
michael@0 995 BufferOffset
michael@0 996 Assembler::as_roundwd(FloatRegister fd, FloatRegister fs)
michael@0 997 {
michael@0 998 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode());
michael@0 999 }
michael@0 1000
michael@0 1001 BufferOffset
michael@0 1002 Assembler::as_truncwd(FloatRegister fd, FloatRegister fs)
michael@0 1003 {
michael@0 1004 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
michael@0 1005 }
michael@0 1006
michael@0 1007 BufferOffset
michael@0 1008 Assembler::as_cvtds(FloatRegister fd, FloatRegister fs)
michael@0 1009 {
michael@0 1010 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode());
michael@0 1011 }
michael@0 1012
michael@0 1013 BufferOffset
michael@0 1014 Assembler::as_cvtdw(FloatRegister fd, FloatRegister fs)
michael@0 1015 {
michael@0 1016 return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode());
michael@0 1017 }
michael@0 1018
michael@0 1019 BufferOffset
michael@0 1020 Assembler::as_cvtsd(FloatRegister fd, FloatRegister fs)
michael@0 1021 {
michael@0 1022 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode());
michael@0 1023 }
michael@0 1024
michael@0 1025 BufferOffset
michael@0 1026 Assembler::as_cvtsw(FloatRegister fd, FloatRegister fs)
michael@0 1027 {
michael@0 1028 return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode());
michael@0 1029 }
michael@0 1030
michael@0 1031 BufferOffset
michael@0 1032 Assembler::as_cvtwd(FloatRegister fd, FloatRegister fs)
michael@0 1033 {
michael@0 1034 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode());
michael@0 1035 }
michael@0 1036
michael@0 1037 BufferOffset
michael@0 1038 Assembler::as_cvtws(FloatRegister fd, FloatRegister fs)
michael@0 1039 {
michael@0 1040 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode());
michael@0 1041 }
michael@0 1042
michael@0 1043 // FP arithmetic instructions
michael@0 1044 BufferOffset
michael@0 1045 Assembler::as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1046 {
michael@0 1047 return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode());
michael@0 1048 }
michael@0 1049
michael@0 1050 BufferOffset
michael@0 1051 Assembler::as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1052 {
michael@0 1053 return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode());
michael@0 1054 }
michael@0 1055
michael@0 1056 BufferOffset
michael@0 1057 Assembler::as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1058 {
michael@0 1059 return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode());
michael@0 1060 }
michael@0 1061
michael@0 1062 BufferOffset
michael@0 1063 Assembler::as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1064 {
michael@0 1065 return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode());
michael@0 1066 }
michael@0 1067
michael@0 1068 BufferOffset
michael@0 1069 Assembler::as_abss(FloatRegister fd, FloatRegister fs)
michael@0 1070 {
michael@0 1071 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode());
michael@0 1072 }
michael@0 1073
michael@0 1074 BufferOffset
michael@0 1075 Assembler::as_absd(FloatRegister fd, FloatRegister fs)
michael@0 1076 {
michael@0 1077 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
michael@0 1078 }
michael@0 1079
michael@0 1080 BufferOffset
michael@0 1081 Assembler::as_negd(FloatRegister fd, FloatRegister fs)
michael@0 1082 {
michael@0 1083 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
michael@0 1084 }
michael@0 1085
michael@0 1086 BufferOffset
michael@0 1087 Assembler::as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1088 {
michael@0 1089 return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode());
michael@0 1090 }
michael@0 1091
michael@0 1092 BufferOffset
michael@0 1093 Assembler::as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1094 {
michael@0 1095 return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode());
michael@0 1096 }
michael@0 1097
michael@0 1098 BufferOffset
michael@0 1099 Assembler::as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1100 {
michael@0 1101 return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode());
michael@0 1102 }
michael@0 1103
michael@0 1104 BufferOffset
michael@0 1105 Assembler::as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft)
michael@0 1106 {
michael@0 1107 return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode());
michael@0 1108 }
michael@0 1109
michael@0 1110 BufferOffset
michael@0 1111 Assembler::as_sqrts(FloatRegister fd, FloatRegister fs)
michael@0 1112 {
michael@0 1113 return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode());
michael@0 1114 }
michael@0 1115
michael@0 1116 BufferOffset
michael@0 1117 Assembler::as_sqrtd(FloatRegister fd, FloatRegister fs)
michael@0 1118 {
michael@0 1119 return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode());
michael@0 1120 }
michael@0 1121
michael@0 1122 // FP compare instructions
michael@0 1123 BufferOffset
michael@0 1124 Assembler::as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1125 {
michael@0 1126 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1127 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
michael@0 1128 }
michael@0 1129
michael@0 1130 BufferOffset
michael@0 1131 Assembler::as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1132 {
michael@0 1133 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1134 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
michael@0 1135 }
michael@0 1136
michael@0 1137 BufferOffset
michael@0 1138 Assembler::as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1139 {
michael@0 1140 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1141 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
michael@0 1142 }
michael@0 1143
michael@0 1144 BufferOffset
michael@0 1145 Assembler::as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1146 {
michael@0 1147 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1148 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
michael@0 1149 }
michael@0 1150
michael@0 1151 BufferOffset
michael@0 1152 Assembler::as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1153 {
michael@0 1154 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1155 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
michael@0 1156 }
michael@0 1157
michael@0 1158 BufferOffset
michael@0 1159 Assembler::as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1160 {
michael@0 1161 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1162 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
michael@0 1163 }
michael@0 1164
michael@0 1165 BufferOffset
michael@0 1166 Assembler::as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1167 {
michael@0 1168 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1169 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
michael@0 1170 }
michael@0 1171
michael@0 1172 BufferOffset
michael@0 1173 Assembler::as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc)
michael@0 1174 {
michael@0 1175 RSField rs = fmt == DoubleFloat ? rs_d : rs_s;
michael@0 1176 return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
michael@0 1177 }
michael@0 1178
michael@0 1179
michael@0 1180 void
michael@0 1181 Assembler::bind(Label *label, BufferOffset boff)
michael@0 1182 {
michael@0 1183 // If our caller didn't give us an explicit target to bind to
michael@0 1184 // then we want to bind to the location of the next instruction
michael@0 1185 BufferOffset dest = boff.assigned() ? boff : nextOffset();
michael@0 1186 if (label->used()) {
michael@0 1187 int32_t next;
michael@0 1188
michael@0 1189 // A used label holds a link to branch that uses it.
michael@0 1190 BufferOffset b(label);
michael@0 1191 do {
michael@0 1192 Instruction *inst = editSrc(b);
michael@0 1193
michael@0 1194 // Second word holds a pointer to the next branch in label's chain.
michael@0 1195 next = inst[1].encode();
michael@0 1196 bind(reinterpret_cast<InstImm *>(inst), b.getOffset(), dest.getOffset());
michael@0 1197
michael@0 1198 b = BufferOffset(next);
michael@0 1199 } while (next != LabelBase::INVALID_OFFSET);
michael@0 1200 }
michael@0 1201 label->bind(dest.getOffset());
michael@0 1202 }
michael@0 1203
michael@0 1204 void
michael@0 1205 Assembler::bind(InstImm *inst, uint32_t branch, uint32_t target)
michael@0 1206 {
michael@0 1207 int32_t offset = target - branch;
michael@0 1208 InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
michael@0 1209 InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
michael@0 1210
michael@0 1211 // If encoded offset is 4, then the jump must be short
michael@0 1212 if (BOffImm16(inst[0]).decode() == 4) {
michael@0 1213 JS_ASSERT(BOffImm16::isInRange(offset));
michael@0 1214 inst[0].setBOffImm16(BOffImm16(offset));
michael@0 1215 inst[1].makeNop();
michael@0 1216 return;
michael@0 1217 }
michael@0 1218 if (BOffImm16::isInRange(offset)) {
michael@0 1219 bool conditional = (inst[0].encode() != inst_bgezal.encode() &&
michael@0 1220 inst[0].encode() != inst_beq.encode());
michael@0 1221
michael@0 1222 inst[0].setBOffImm16(BOffImm16(offset));
michael@0 1223 inst[1].makeNop();
michael@0 1224
michael@0 1225 // Skip the trailing nops in conditional branches.
michael@0 1226 if (conditional) {
michael@0 1227 inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(3 * sizeof(void *))).encode();
michael@0 1228 // There are 2 nops after this
michael@0 1229 }
michael@0 1230 return;
michael@0 1231 }
michael@0 1232
michael@0 1233 if (inst[0].encode() == inst_bgezal.encode()) {
michael@0 1234 // Handle long call.
michael@0 1235 addLongJump(BufferOffset(branch));
michael@0 1236 writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
michael@0 1237 inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
michael@0 1238 // There is 1 nop after this.
michael@0 1239 } else if (inst[0].encode() == inst_beq.encode()) {
michael@0 1240 // Handle long unconditional jump.
michael@0 1241 addLongJump(BufferOffset(branch));
michael@0 1242 writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
michael@0 1243 inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
michael@0 1244 // There is 1 nop after this.
michael@0 1245 } else {
michael@0 1246 // Handle long conditional jump.
michael@0 1247 inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(void *)));
michael@0 1248 // No need for a "nop" here because we can clobber scratch.
michael@0 1249 addLongJump(BufferOffset(branch + sizeof(void *)));
michael@0 1250 writeLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, target);
michael@0 1251 inst[3] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
michael@0 1252 // There is 1 nop after this.
michael@0 1253 }
michael@0 1254 }
michael@0 1255
michael@0 1256 void
michael@0 1257 Assembler::bind(RepatchLabel *label)
michael@0 1258 {
michael@0 1259 BufferOffset dest = nextOffset();
michael@0 1260 if (label->used()) {
michael@0 1261 // If the label has a use, then change this use to refer to
michael@0 1262 // the bound label;
michael@0 1263 BufferOffset b(label->offset());
michael@0 1264 Instruction *inst1 = editSrc(b);
michael@0 1265 Instruction *inst2 = inst1->next();
michael@0 1266
michael@0 1267 updateLuiOriValue(inst1, inst2, dest.getOffset());
michael@0 1268 }
michael@0 1269 label->bind(dest.getOffset());
michael@0 1270 }
michael@0 1271
michael@0 1272 void
michael@0 1273 Assembler::retarget(Label *label, Label *target)
michael@0 1274 {
michael@0 1275 if (label->used()) {
michael@0 1276 if (target->bound()) {
michael@0 1277 bind(label, BufferOffset(target));
michael@0 1278 } else if (target->used()) {
michael@0 1279 // The target is not bound but used. Prepend label's branch list
michael@0 1280 // onto target's.
michael@0 1281 int32_t next;
michael@0 1282 BufferOffset labelBranchOffset(label);
michael@0 1283
michael@0 1284 // Find the head of the use chain for label.
michael@0 1285 do {
michael@0 1286 Instruction *inst = editSrc(labelBranchOffset);
michael@0 1287
michael@0 1288 // Second word holds a pointer to the next branch in chain.
michael@0 1289 next = inst[1].encode();
michael@0 1290 labelBranchOffset = BufferOffset(next);
michael@0 1291 } while (next != LabelBase::INVALID_OFFSET);
michael@0 1292
michael@0 1293 // Then patch the head of label's use chain to the tail of
michael@0 1294 // target's use chain, prepending the entire use chain of target.
michael@0 1295 Instruction *inst = editSrc(labelBranchOffset);
michael@0 1296 int32_t prev = target->use(label->offset());
michael@0 1297 inst[1].setData(prev);
michael@0 1298 } else {
michael@0 1299 // The target is unbound and unused. We can just take the head of
michael@0 1300 // the list hanging off of label, and dump that into target.
michael@0 1301 DebugOnly<uint32_t> prev = target->use(label->offset());
michael@0 1302 JS_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
michael@0 1303 }
michael@0 1304 }
michael@0 1305 label->reset();
michael@0 1306 }
michael@0 1307
michael@0 1308 void dbg_break() {}
michael@0 1309 static int stopBKPT = -1;
michael@0 1310 void
michael@0 1311 Assembler::as_break(uint32_t code)
michael@0 1312 {
michael@0 1313 JS_ASSERT(code <= MAX_BREAK_CODE);
michael@0 1314 writeInst(op_special | code << RTShift | ff_break);
michael@0 1315 }
michael@0 1316
michael@0 1317 uint32_t
michael@0 1318 Assembler::patchWrite_NearCallSize()
michael@0 1319 {
michael@0 1320 return 4 * sizeof(uint32_t);
michael@0 1321 }
michael@0 1322
michael@0 1323 void
michael@0 1324 Assembler::patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
michael@0 1325 {
michael@0 1326 Instruction *inst = (Instruction *) start.raw();
michael@0 1327 uint8_t *dest = toCall.raw();
michael@0 1328
michael@0 1329 // Overwrite whatever instruction used to be here with a call.
michael@0 1330 // Always use long jump for two reasons:
michael@0 1331 // - Jump has to be the same size because of patchWrite_NearCallSize.
michael@0 1332 // - Return address has to be at the end of replaced block.
michael@0 1333 // Short jump wouldn't be more efficient.
michael@0 1334 writeLuiOriInstructions(inst, &inst[1], ScratchRegister, (uint32_t)dest);
michael@0 1335 inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
michael@0 1336 inst[3] = InstNOP();
michael@0 1337
michael@0 1338 // Ensure everyone sees the code that was just written into memory.
michael@0 1339 AutoFlushICache::flush(uintptr_t(inst), patchWrite_NearCallSize());
michael@0 1340 }
michael@0 1341
michael@0 1342 uint32_t
michael@0 1343 Assembler::extractLuiOriValue(Instruction *inst0, Instruction *inst1)
michael@0 1344 {
michael@0 1345 InstImm *i0 = (InstImm *) inst0;
michael@0 1346 InstImm *i1 = (InstImm *) inst1;
michael@0 1347 JS_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
michael@0 1348 JS_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
michael@0 1349
michael@0 1350 uint32_t value = i0->extractImm16Value() << 16;
michael@0 1351 value = value | i1->extractImm16Value();
michael@0 1352 return value;
michael@0 1353 }
michael@0 1354
michael@0 1355 void
michael@0 1356 Assembler::updateLuiOriValue(Instruction *inst0, Instruction *inst1, uint32_t value)
michael@0 1357 {
michael@0 1358 JS_ASSERT(inst0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
michael@0 1359 JS_ASSERT(inst1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
michael@0 1360
michael@0 1361 ((InstImm *) inst0)->setImm16(Imm16::upper(Imm32(value)));
michael@0 1362 ((InstImm *) inst1)->setImm16(Imm16::lower(Imm32(value)));
michael@0 1363 }
michael@0 1364
michael@0 1365 void
michael@0 1366 Assembler::writeLuiOriInstructions(Instruction *inst0, Instruction *inst1,
michael@0 1367 Register reg, uint32_t value)
michael@0 1368 {
michael@0 1369 *inst0 = InstImm(op_lui, zero, reg, Imm16::upper(Imm32(value)));
michael@0 1370 *inst1 = InstImm(op_ori, reg, reg, Imm16::lower(Imm32(value)));
michael@0 1371 }
michael@0 1372
michael@0 1373 void
michael@0 1374 Assembler::patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
michael@0 1375 PatchedImmPtr expectedValue)
michael@0 1376 {
michael@0 1377 Instruction *inst = (Instruction *) label.raw();
michael@0 1378
michael@0 1379 // Extract old Value
michael@0 1380 DebugOnly<uint32_t> value = Assembler::extractLuiOriValue(&inst[0], &inst[1]);
michael@0 1381 JS_ASSERT(value == uint32_t(expectedValue.value));
michael@0 1382
michael@0 1383 // Replace with new value
michael@0 1384 Assembler::updateLuiOriValue(inst, inst->next(), uint32_t(newValue.value));
michael@0 1385
michael@0 1386 AutoFlushICache::flush(uintptr_t(inst), 8);
michael@0 1387 }
michael@0 1388
michael@0 1389 void
michael@0 1390 Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue)
michael@0 1391 {
michael@0 1392 patchDataWithValueCheck(label, PatchedImmPtr(newValue.value),
michael@0 1393 PatchedImmPtr(expectedValue.value));
michael@0 1394 }
michael@0 1395
michael@0 1396 // This just stomps over memory with 32 bits of raw data. Its purpose is to
michael@0 1397 // overwrite the call of JITed code with 32 bits worth of an offset. This will
michael@0 1398 // is only meant to function on code that has been invalidated, so it should
michael@0 1399 // be totally safe. Since that instruction will never be executed again, a
michael@0 1400 // ICache flush should not be necessary
michael@0 1401 void
michael@0 1402 Assembler::patchWrite_Imm32(CodeLocationLabel label, Imm32 imm)
michael@0 1403 {
michael@0 1404 // Raw is going to be the return address.
michael@0 1405 uint32_t *raw = (uint32_t*)label.raw();
michael@0 1406 // Overwrite the 4 bytes before the return address, which will
michael@0 1407 // end up being the call instruction.
michael@0 1408 *(raw - 1) = imm.value;
michael@0 1409 }
michael@0 1410
michael@0 1411 uint8_t *
michael@0 1412 Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
michael@0 1413 {
michael@0 1414 Instruction *inst = reinterpret_cast<Instruction*>(inst_);
michael@0 1415 if (count != nullptr)
michael@0 1416 *count += sizeof(Instruction);
michael@0 1417 return reinterpret_cast<uint8_t*>(inst->next());
michael@0 1418 }
michael@0 1419
michael@0 1420 // Since there are no pools in MIPS implementation, this should be simple.
michael@0 1421 Instruction *
michael@0 1422 Instruction::next()
michael@0 1423 {
michael@0 1424 return this + 1;
michael@0 1425 }
michael@0 1426
michael@0 1427 InstImm Assembler::invertBranch(InstImm branch, BOffImm16 skipOffset)
michael@0 1428 {
michael@0 1429 uint32_t rt = 0;
michael@0 1430 Opcode op = (Opcode) (branch.extractOpcode() << OpcodeShift);
michael@0 1431 switch(op) {
michael@0 1432 case op_beq:
michael@0 1433 branch.setBOffImm16(skipOffset);
michael@0 1434 branch.setOpcode(op_bne);
michael@0 1435 return branch;
michael@0 1436 case op_bne:
michael@0 1437 branch.setBOffImm16(skipOffset);
michael@0 1438 branch.setOpcode(op_beq);
michael@0 1439 return branch;
michael@0 1440 case op_bgtz:
michael@0 1441 branch.setBOffImm16(skipOffset);
michael@0 1442 branch.setOpcode(op_blez);
michael@0 1443 return branch;
michael@0 1444 case op_blez:
michael@0 1445 branch.setBOffImm16(skipOffset);
michael@0 1446 branch.setOpcode(op_bgtz);
michael@0 1447 return branch;
michael@0 1448 case op_regimm:
michael@0 1449 branch.setBOffImm16(skipOffset);
michael@0 1450 rt = branch.extractRT();
michael@0 1451 if (rt == (rt_bltz >> RTShift)) {
michael@0 1452 branch.setRT(rt_bgez);
michael@0 1453 return branch;
michael@0 1454 }
michael@0 1455 if (rt == (rt_bgez >> RTShift)) {
michael@0 1456 branch.setRT(rt_bltz);
michael@0 1457 return branch;
michael@0 1458 }
michael@0 1459
michael@0 1460 MOZ_ASSUME_UNREACHABLE("Error creating long branch.");
michael@0 1461 return branch;
michael@0 1462
michael@0 1463 case op_cop1:
michael@0 1464 JS_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
michael@0 1465
michael@0 1466 branch.setBOffImm16(skipOffset);
michael@0 1467 rt = branch.extractRT();
michael@0 1468 if (rt & 0x1)
michael@0 1469 branch.setRT((RTField) ((rt & ~0x1) << RTShift));
michael@0 1470 else
michael@0 1471 branch.setRT((RTField) ((rt | 0x1) << RTShift));
michael@0 1472 return branch;
michael@0 1473 }
michael@0 1474
michael@0 1475 MOZ_ASSUME_UNREACHABLE("Error creating long branch.");
michael@0 1476 return branch;
michael@0 1477 }
michael@0 1478
michael@0 1479 void
michael@0 1480 Assembler::ToggleToJmp(CodeLocationLabel inst_)
michael@0 1481 {
michael@0 1482 InstImm * inst = (InstImm *)inst_.raw();
michael@0 1483
michael@0 1484 JS_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift));
michael@0 1485 // We converted beq to andi, so now we restore it.
michael@0 1486 inst->setOpcode(op_beq);
michael@0 1487
michael@0 1488 AutoFlushICache::flush(uintptr_t(inst), 4);
michael@0 1489 }
michael@0 1490
michael@0 1491 void
michael@0 1492 Assembler::ToggleToCmp(CodeLocationLabel inst_)
michael@0 1493 {
michael@0 1494 InstImm * inst = (InstImm *)inst_.raw();
michael@0 1495
michael@0 1496 // toggledJump is allways used for short jumps.
michael@0 1497 JS_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift));
michael@0 1498 // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset"
michael@0 1499 inst->setOpcode(op_andi);
michael@0 1500
michael@0 1501 AutoFlushICache::flush(uintptr_t(inst), 4);
michael@0 1502 }
michael@0 1503
michael@0 1504 void
michael@0 1505 Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
michael@0 1506 {
michael@0 1507 Instruction *inst = (Instruction *)inst_.raw();
michael@0 1508 InstImm *i0 = (InstImm *) inst;
michael@0 1509 InstImm *i1 = (InstImm *) i0->next();
michael@0 1510 Instruction *i2 = (Instruction *) i1->next();
michael@0 1511
michael@0 1512 JS_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
michael@0 1513 JS_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
michael@0 1514
michael@0 1515 if (enabled) {
michael@0 1516 InstReg jalr = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
michael@0 1517 *i2 = jalr;
michael@0 1518 } else {
michael@0 1519 InstNOP nop;
michael@0 1520 *i2 = nop;
michael@0 1521 }
michael@0 1522
michael@0 1523 AutoFlushICache::flush(uintptr_t(i2), 4);
michael@0 1524 }
michael@0 1525
michael@0 1526 void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst)
michael@0 1527 {
michael@0 1528 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1529 }

mercurial