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