1 // Copyright (c) 1994-2006 Sun Microsystems Inc. 2 // All Rights Reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // - Redistributions of source code must retain the above copyright notice, 9 // this list of conditions and the following disclaimer. 10 // 11 // - Redistribution in binary form must reproduce the above copyright 12 // notice, this list of conditions and the following disclaimer in the 13 // documentation and/or other materials provided with the distribution. 14 // 15 // - Neither the name of Sun Microsystems or the names of contributors may 16 // be used to endorse or promote products derived from this software without 17 // specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // The original source code covered by the above license above has been 32 // modified significantly by Google Inc. 33 // Copyright 2012 the V8 project authors. All rights reserved. 34 35 36 #include "src/v8.h" 37 38 #if V8_TARGET_ARCH_MIPS64 39 40 #include "src/base/cpu.h" 41 #include "src/mips64/assembler-mips64-inl.h" 42 #include "src/serialize.h" 43 44 namespace v8 { 45 namespace internal { 46 47 48 // Get the CPU features enabled by the build. For cross compilation the 49 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS 50 // can be defined to enable FPU instructions when building the 51 // snapshot. 52 static unsigned CpuFeaturesImpliedByCompiler() { 53 unsigned answer = 0; 54 #ifdef CAN_USE_FPU_INSTRUCTIONS 55 answer |= 1u << FPU; 56 #endif // def CAN_USE_FPU_INSTRUCTIONS 57 58 // If the compiler is allowed to use FPU then we can use FPU too in our code 59 // generation even when generating snapshots. This won't work for cross 60 // compilation. 61 #if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0 62 answer |= 1u << FPU; 63 #endif 64 65 return answer; 66 } 67 68 69 const char* DoubleRegister::AllocationIndexToString(int index) { 70 DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters); 71 const char* const names[] = { 72 "f0", 73 "f2", 74 "f4", 75 "f6", 76 "f8", 77 "f10", 78 "f12", 79 "f14", 80 "f16", 81 "f18", 82 "f20", 83 "f22", 84 "f24", 85 "f26" 86 }; 87 return names[index]; 88 } 89 90 91 void CpuFeatures::ProbeImpl(bool cross_compile) { 92 supported_ |= CpuFeaturesImpliedByCompiler(); 93 94 // Only use statically determined features for cross compile (snapshot). 95 if (cross_compile) return; 96 97 // If the compiler is allowed to use fpu then we can use fpu too in our 98 // code generation. 99 #ifndef __mips__ 100 // For the simulator build, use FPU. 101 supported_ |= 1u << FPU; 102 #else 103 // Probe for additional features at runtime. 104 base::CPU cpu; 105 if (cpu.has_fpu()) supported_ |= 1u << FPU; 106 #endif 107 } 108 109 110 void CpuFeatures::PrintTarget() { } 111 void CpuFeatures::PrintFeatures() { } 112 113 114 int ToNumber(Register reg) { 115 DCHECK(reg.is_valid()); 116 const int kNumbers[] = { 117 0, // zero_reg 118 1, // at 119 2, // v0 120 3, // v1 121 4, // a0 122 5, // a1 123 6, // a2 124 7, // a3 125 8, // a4 126 9, // a5 127 10, // a6 128 11, // a7 129 12, // t0 130 13, // t1 131 14, // t2 132 15, // t3 133 16, // s0 134 17, // s1 135 18, // s2 136 19, // s3 137 20, // s4 138 21, // s5 139 22, // s6 140 23, // s7 141 24, // t8 142 25, // t9 143 26, // k0 144 27, // k1 145 28, // gp 146 29, // sp 147 30, // fp 148 31, // ra 149 }; 150 return kNumbers[reg.code()]; 151 } 152 153 154 Register ToRegister(int num) { 155 DCHECK(num >= 0 && num < kNumRegisters); 156 const Register kRegisters[] = { 157 zero_reg, 158 at, 159 v0, v1, 160 a0, a1, a2, a3, a4, a5, a6, a7, 161 t0, t1, t2, t3, 162 s0, s1, s2, s3, s4, s5, s6, s7, 163 t8, t9, 164 k0, k1, 165 gp, 166 sp, 167 fp, 168 ra 169 }; 170 return kRegisters[num]; 171 } 172 173 174 // ----------------------------------------------------------------------------- 175 // Implementation of RelocInfo. 176 177 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | 178 1 << RelocInfo::INTERNAL_REFERENCE; 179 180 181 bool RelocInfo::IsCodedSpecially() { 182 // The deserializer needs to know whether a pointer is specially coded. Being 183 // specially coded on MIPS means that it is a lui/ori instruction, and that is 184 // always the case inside code objects. 185 return true; 186 } 187 188 189 bool RelocInfo::IsInConstantPool() { 190 return false; 191 } 192 193 194 // Patch the code at the current address with the supplied instructions. 195 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { 196 Instr* pc = reinterpret_cast<Instr*>(pc_); 197 Instr* instr = reinterpret_cast<Instr*>(instructions); 198 for (int i = 0; i < instruction_count; i++) { 199 *(pc + i) = *(instr + i); 200 } 201 202 // Indicate that code has changed. 203 CpuFeatures::FlushICache(pc_, instruction_count * Assembler::kInstrSize); 204 } 205 206 207 // Patch the code at the current PC with a call to the target address. 208 // Additional guard instructions can be added if required. 209 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { 210 // Patch the code at the current address with a call to the target. 211 UNIMPLEMENTED_MIPS(); 212 } 213 214 215 // ----------------------------------------------------------------------------- 216 // Implementation of Operand and MemOperand. 217 // See assembler-mips-inl.h for inlined constructors. 218 219 Operand::Operand(Handle<Object> handle) { 220 AllowDeferredHandleDereference using_raw_address; 221 rm_ = no_reg; 222 // Verify all Objects referred by code are NOT in new space. 223 Object* obj = *handle; 224 if (obj->IsHeapObject()) { 225 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj)); 226 imm64_ = reinterpret_cast<intptr_t>(handle.location()); 227 rmode_ = RelocInfo::EMBEDDED_OBJECT; 228 } else { 229 // No relocation needed. 230 imm64_ = reinterpret_cast<intptr_t>(obj); 231 rmode_ = RelocInfo::NONE64; 232 } 233 } 234 235 236 MemOperand::MemOperand(Register rm, int64_t offset) : Operand(rm) { 237 offset_ = offset; 238 } 239 240 241 MemOperand::MemOperand(Register rm, int64_t unit, int64_t multiplier, 242 OffsetAddend offset_addend) : Operand(rm) { 243 offset_ = unit * multiplier + offset_addend; 244 } 245 246 247 // ----------------------------------------------------------------------------- 248 // Specific instructions, constants, and masks. 249 250 static const int kNegOffset = 0x00008000; 251 // daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r) 252 // operations as post-increment of sp. 253 const Instr kPopInstruction = DADDIU | (kRegister_sp_Code << kRsShift) 254 | (kRegister_sp_Code << kRtShift) 255 | (kPointerSize & kImm16Mask); // NOLINT 256 // daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp. 257 const Instr kPushInstruction = DADDIU | (kRegister_sp_Code << kRsShift) 258 | (kRegister_sp_Code << kRtShift) 259 | (-kPointerSize & kImm16Mask); // NOLINT 260 // sd(r, MemOperand(sp, 0)) 261 const Instr kPushRegPattern = SD | (kRegister_sp_Code << kRsShift) 262 | (0 & kImm16Mask); // NOLINT 263 // ld(r, MemOperand(sp, 0)) 264 const Instr kPopRegPattern = LD | (kRegister_sp_Code << kRsShift) 265 | (0 & kImm16Mask); // NOLINT 266 267 const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift) 268 | (0 & kImm16Mask); // NOLINT 269 270 const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift) 271 | (0 & kImm16Mask); // NOLINT 272 273 const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift) 274 | (kNegOffset & kImm16Mask); // NOLINT 275 276 const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift) 277 | (kNegOffset & kImm16Mask); // NOLINT 278 // A mask for the Rt register for push, pop, lw, sw instructions. 279 const Instr kRtMask = kRtFieldMask; 280 const Instr kLwSwInstrTypeMask = 0xffe00000; 281 const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask; 282 const Instr kLwSwOffsetMask = kImm16Mask; 283 284 285 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) 286 : AssemblerBase(isolate, buffer, buffer_size), 287 recorded_ast_id_(TypeFeedbackId::None()), 288 positions_recorder_(this) { 289 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); 290 291 last_trampoline_pool_end_ = 0; 292 no_trampoline_pool_before_ = 0; 293 trampoline_pool_blocked_nesting_ = 0; 294 // We leave space (16 * kTrampolineSlotsSize) 295 // for BlockTrampolinePoolScope buffer. 296 next_buffer_check_ = FLAG_force_long_branches 297 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16; 298 internal_trampoline_exception_ = false; 299 last_bound_pos_ = 0; 300 301 trampoline_emitted_ = FLAG_force_long_branches; 302 unbound_labels_count_ = 0; 303 block_buffer_growth_ = false; 304 305 ClearRecordedAstId(); 306 } 307 308 309 void Assembler::GetCode(CodeDesc* desc) { 310 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap. 311 // Set up code descriptor. 312 desc->buffer = buffer_; 313 desc->buffer_size = buffer_size_; 314 desc->instr_size = pc_offset(); 315 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 316 desc->origin = this; 317 } 318 319 320 void Assembler::Align(int m) { 321 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m)); 322 while ((pc_offset() & (m - 1)) != 0) { 323 nop(); 324 } 325 } 326 327 328 void Assembler::CodeTargetAlign() { 329 // No advantage to aligning branch/call targets to more than 330 // single instruction, that I am aware of. 331 Align(4); 332 } 333 334 335 Register Assembler::GetRtReg(Instr instr) { 336 Register rt; 337 rt.code_ = (instr & kRtFieldMask) >> kRtShift; 338 return rt; 339 } 340 341 342 Register Assembler::GetRsReg(Instr instr) { 343 Register rs; 344 rs.code_ = (instr & kRsFieldMask) >> kRsShift; 345 return rs; 346 } 347 348 349 Register Assembler::GetRdReg(Instr instr) { 350 Register rd; 351 rd.code_ = (instr & kRdFieldMask) >> kRdShift; 352 return rd; 353 } 354 355 356 uint32_t Assembler::GetRt(Instr instr) { 357 return (instr & kRtFieldMask) >> kRtShift; 358 } 359 360 361 uint32_t Assembler::GetRtField(Instr instr) { 362 return instr & kRtFieldMask; 363 } 364 365 366 uint32_t Assembler::GetRs(Instr instr) { 367 return (instr & kRsFieldMask) >> kRsShift; 368 } 369 370 371 uint32_t Assembler::GetRsField(Instr instr) { 372 return instr & kRsFieldMask; 373 } 374 375 376 uint32_t Assembler::GetRd(Instr instr) { 377 return (instr & kRdFieldMask) >> kRdShift; 378 } 379 380 381 uint32_t Assembler::GetRdField(Instr instr) { 382 return instr & kRdFieldMask; 383 } 384 385 386 uint32_t Assembler::GetSa(Instr instr) { 387 return (instr & kSaFieldMask) >> kSaShift; 388 } 389 390 391 uint32_t Assembler::GetSaField(Instr instr) { 392 return instr & kSaFieldMask; 393 } 394 395 396 uint32_t Assembler::GetOpcodeField(Instr instr) { 397 return instr & kOpcodeMask; 398 } 399 400 401 uint32_t Assembler::GetFunction(Instr instr) { 402 return (instr & kFunctionFieldMask) >> kFunctionShift; 403 } 404 405 406 uint32_t Assembler::GetFunctionField(Instr instr) { 407 return instr & kFunctionFieldMask; 408 } 409 410 411 uint32_t Assembler::GetImmediate16(Instr instr) { 412 return instr & kImm16Mask; 413 } 414 415 416 uint32_t Assembler::GetLabelConst(Instr instr) { 417 return instr & ~kImm16Mask; 418 } 419 420 421 bool Assembler::IsPop(Instr instr) { 422 return (instr & ~kRtMask) == kPopRegPattern; 423 } 424 425 426 bool Assembler::IsPush(Instr instr) { 427 return (instr & ~kRtMask) == kPushRegPattern; 428 } 429 430 431 bool Assembler::IsSwRegFpOffset(Instr instr) { 432 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern); 433 } 434 435 436 bool Assembler::IsLwRegFpOffset(Instr instr) { 437 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern); 438 } 439 440 441 bool Assembler::IsSwRegFpNegOffset(Instr instr) { 442 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) == 443 kSwRegFpNegOffsetPattern); 444 } 445 446 447 bool Assembler::IsLwRegFpNegOffset(Instr instr) { 448 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) == 449 kLwRegFpNegOffsetPattern); 450 } 451 452 453 // Labels refer to positions in the (to be) generated code. 454 // There are bound, linked, and unused labels. 455 // 456 // Bound labels refer to known positions in the already 457 // generated code. pos() is the position the label refers to. 458 // 459 // Linked labels refer to unknown positions in the code 460 // to be generated; pos() is the position of the last 461 // instruction using the label. 462 463 // The link chain is terminated by a value in the instruction of -1, 464 // which is an otherwise illegal value (branch -1 is inf loop). 465 // The instruction 16-bit offset field addresses 32-bit words, but in 466 // code is conv to an 18-bit value addressing bytes, hence the -4 value. 467 468 const int kEndOfChain = -4; 469 // Determines the end of the Jump chain (a subset of the label link chain). 470 const int kEndOfJumpChain = 0; 471 472 473 bool Assembler::IsBranch(Instr instr) { 474 uint32_t opcode = GetOpcodeField(instr); 475 uint32_t rt_field = GetRtField(instr); 476 uint32_t rs_field = GetRsField(instr); 477 // Checks if the instruction is a branch. 478 return opcode == BEQ || 479 opcode == BNE || 480 opcode == BLEZ || 481 opcode == BGTZ || 482 opcode == BEQL || 483 opcode == BNEL || 484 opcode == BLEZL || 485 opcode == BGTZL || 486 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ || 487 rt_field == BLTZAL || rt_field == BGEZAL)) || 488 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch. 489 (opcode == COP1 && rs_field == BC1EQZ) || 490 (opcode == COP1 && rs_field == BC1NEZ); 491 } 492 493 494 bool Assembler::IsEmittedConstant(Instr instr) { 495 uint32_t label_constant = GetLabelConst(instr); 496 return label_constant == 0; // Emitted label const in reg-exp engine. 497 } 498 499 500 bool Assembler::IsBeq(Instr instr) { 501 return GetOpcodeField(instr) == BEQ; 502 } 503 504 505 bool Assembler::IsBne(Instr instr) { 506 return GetOpcodeField(instr) == BNE; 507 } 508 509 510 bool Assembler::IsJump(Instr instr) { 511 uint32_t opcode = GetOpcodeField(instr); 512 uint32_t rt_field = GetRtField(instr); 513 uint32_t rd_field = GetRdField(instr); 514 uint32_t function_field = GetFunctionField(instr); 515 // Checks if the instruction is a jump. 516 return opcode == J || opcode == JAL || 517 (opcode == SPECIAL && rt_field == 0 && 518 ((function_field == JALR) || (rd_field == 0 && (function_field == JR)))); 519 } 520 521 522 bool Assembler::IsJ(Instr instr) { 523 uint32_t opcode = GetOpcodeField(instr); 524 // Checks if the instruction is a jump. 525 return opcode == J; 526 } 527 528 529 bool Assembler::IsJal(Instr instr) { 530 return GetOpcodeField(instr) == JAL; 531 } 532 533 534 bool Assembler::IsJr(Instr instr) { 535 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR; 536 } 537 538 539 bool Assembler::IsJalr(Instr instr) { 540 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR; 541 } 542 543 544 bool Assembler::IsLui(Instr instr) { 545 uint32_t opcode = GetOpcodeField(instr); 546 // Checks if the instruction is a load upper immediate. 547 return opcode == LUI; 548 } 549 550 551 bool Assembler::IsOri(Instr instr) { 552 uint32_t opcode = GetOpcodeField(instr); 553 // Checks if the instruction is a load upper immediate. 554 return opcode == ORI; 555 } 556 557 558 bool Assembler::IsNop(Instr instr, unsigned int type) { 559 // See Assembler::nop(type). 560 DCHECK(type < 32); 561 uint32_t opcode = GetOpcodeField(instr); 562 uint32_t function = GetFunctionField(instr); 563 uint32_t rt = GetRt(instr); 564 uint32_t rd = GetRd(instr); 565 uint32_t sa = GetSa(instr); 566 567 // Traditional mips nop == sll(zero_reg, zero_reg, 0) 568 // When marking non-zero type, use sll(zero_reg, at, type) 569 // to avoid use of mips ssnop and ehb special encodings 570 // of the sll instruction. 571 572 Register nop_rt_reg = (type == 0) ? zero_reg : at; 573 bool ret = (opcode == SPECIAL && function == SLL && 574 rd == static_cast<uint32_t>(ToNumber(zero_reg)) && 575 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) && 576 sa == type); 577 578 return ret; 579 } 580 581 582 int32_t Assembler::GetBranchOffset(Instr instr) { 583 DCHECK(IsBranch(instr)); 584 return (static_cast<int16_t>(instr & kImm16Mask)) << 2; 585 } 586 587 588 bool Assembler::IsLw(Instr instr) { 589 return ((instr & kOpcodeMask) == LW); 590 } 591 592 593 int16_t Assembler::GetLwOffset(Instr instr) { 594 DCHECK(IsLw(instr)); 595 return ((instr & kImm16Mask)); 596 } 597 598 599 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) { 600 DCHECK(IsLw(instr)); 601 602 // We actually create a new lw instruction based on the original one. 603 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask) 604 | (offset & kImm16Mask); 605 606 return temp_instr; 607 } 608 609 610 bool Assembler::IsSw(Instr instr) { 611 return ((instr & kOpcodeMask) == SW); 612 } 613 614 615 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) { 616 DCHECK(IsSw(instr)); 617 return ((instr & ~kImm16Mask) | (offset & kImm16Mask)); 618 } 619 620 621 bool Assembler::IsAddImmediate(Instr instr) { 622 return ((instr & kOpcodeMask) == ADDIU || (instr & kOpcodeMask) == DADDIU); 623 } 624 625 626 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) { 627 DCHECK(IsAddImmediate(instr)); 628 return ((instr & ~kImm16Mask) | (offset & kImm16Mask)); 629 } 630 631 632 bool Assembler::IsAndImmediate(Instr instr) { 633 return GetOpcodeField(instr) == ANDI; 634 } 635 636 637 int64_t Assembler::target_at(int64_t pos) { 638 Instr instr = instr_at(pos); 639 if ((instr & ~kImm16Mask) == 0) { 640 // Emitted label constant, not part of a branch. 641 if (instr == 0) { 642 return kEndOfChain; 643 } else { 644 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14; 645 return (imm18 + pos); 646 } 647 } 648 // Check we have a branch or jump instruction. 649 DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr)); 650 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming 651 // the compiler uses arithmetic shifts for signed integers. 652 if (IsBranch(instr)) { 653 int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14; 654 if (imm18 == kEndOfChain) { 655 // EndOfChain sentinel is returned directly, not relative to pc or pos. 656 return kEndOfChain; 657 } else { 658 return pos + kBranchPCOffset + imm18; 659 } 660 } else if (IsLui(instr)) { 661 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize); 662 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize); 663 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize); 664 DCHECK(IsOri(instr_ori)); 665 DCHECK(IsOri(instr_ori2)); 666 667 // TODO(plind) create named constants for shift values. 668 int64_t imm = static_cast<int64_t>(instr_lui & kImm16Mask) << 48; 669 imm |= static_cast<int64_t>(instr_ori & kImm16Mask) << 32; 670 imm |= static_cast<int64_t>(instr_ori2 & kImm16Mask) << 16; 671 // Sign extend address; 672 imm >>= 16; 673 674 if (imm == kEndOfJumpChain) { 675 // EndOfChain sentinel is returned directly, not relative to pc or pos. 676 return kEndOfChain; 677 } else { 678 uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos); 679 int64_t delta = instr_address - imm; 680 DCHECK(pos > delta); 681 return pos - delta; 682 } 683 } else { 684 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; 685 if (imm28 == kEndOfJumpChain) { 686 // EndOfChain sentinel is returned directly, not relative to pc or pos. 687 return kEndOfChain; 688 } else { 689 uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos); 690 instr_address &= kImm28Mask; 691 int64_t delta = instr_address - imm28; 692 DCHECK(pos > delta); 693 return pos - delta; 694 } 695 } 696 } 697 698 699 void Assembler::target_at_put(int64_t pos, int64_t target_pos) { 700 Instr instr = instr_at(pos); 701 if ((instr & ~kImm16Mask) == 0) { 702 DCHECK(target_pos == kEndOfChain || target_pos >= 0); 703 // Emitted label constant, not part of a branch. 704 // Make label relative to Code* of generated Code object. 705 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); 706 return; 707 } 708 709 DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr)); 710 if (IsBranch(instr)) { 711 int32_t imm18 = target_pos - (pos + kBranchPCOffset); 712 DCHECK((imm18 & 3) == 0); 713 714 instr &= ~kImm16Mask; 715 int32_t imm16 = imm18 >> 2; 716 DCHECK(is_int16(imm16)); 717 718 instr_at_put(pos, instr | (imm16 & kImm16Mask)); 719 } else if (IsLui(instr)) { 720 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize); 721 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize); 722 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize); 723 DCHECK(IsOri(instr_ori)); 724 DCHECK(IsOri(instr_ori2)); 725 726 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos; 727 DCHECK((imm & 3) == 0); 728 729 instr_lui &= ~kImm16Mask; 730 instr_ori &= ~kImm16Mask; 731 instr_ori2 &= ~kImm16Mask; 732 733 instr_at_put(pos + 0 * Assembler::kInstrSize, 734 instr_lui | ((imm >> 32) & kImm16Mask)); 735 instr_at_put(pos + 1 * Assembler::kInstrSize, 736 instr_ori | ((imm >> 16) & kImm16Mask)); 737 instr_at_put(pos + 3 * Assembler::kInstrSize, 738 instr_ori2 | (imm & kImm16Mask)); 739 } else { 740 uint64_t imm28 = reinterpret_cast<uint64_t>(buffer_) + target_pos; 741 imm28 &= kImm28Mask; 742 DCHECK((imm28 & 3) == 0); 743 744 instr &= ~kImm26Mask; 745 uint32_t imm26 = imm28 >> 2; 746 DCHECK(is_uint26(imm26)); 747 748 instr_at_put(pos, instr | (imm26 & kImm26Mask)); 749 } 750 } 751 752 753 void Assembler::print(Label* L) { 754 if (L->is_unused()) { 755 PrintF("unused label\n"); 756 } else if (L->is_bound()) { 757 PrintF("bound label to %d\n", L->pos()); 758 } else if (L->is_linked()) { 759 Label l = *L; 760 PrintF("unbound label"); 761 while (l.is_linked()) { 762 PrintF("@ %d ", l.pos()); 763 Instr instr = instr_at(l.pos()); 764 if ((instr & ~kImm16Mask) == 0) { 765 PrintF("value\n"); 766 } else { 767 PrintF("%d\n", instr); 768 } 769 next(&l); 770 } 771 } else { 772 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); 773 } 774 } 775 776 777 void Assembler::bind_to(Label* L, int pos) { 778 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position. 779 int32_t trampoline_pos = kInvalidSlotPos; 780 if (L->is_linked() && !trampoline_emitted_) { 781 unbound_labels_count_--; 782 next_buffer_check_ += kTrampolineSlotsSize; 783 } 784 785 while (L->is_linked()) { 786 int32_t fixup_pos = L->pos(); 787 int32_t dist = pos - fixup_pos; 788 next(L); // Call next before overwriting link with target at fixup_pos. 789 Instr instr = instr_at(fixup_pos); 790 if (IsBranch(instr)) { 791 if (dist > kMaxBranchOffset) { 792 if (trampoline_pos == kInvalidSlotPos) { 793 trampoline_pos = get_trampoline_entry(fixup_pos); 794 CHECK(trampoline_pos != kInvalidSlotPos); 795 } 796 DCHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset); 797 target_at_put(fixup_pos, trampoline_pos); 798 fixup_pos = trampoline_pos; 799 dist = pos - fixup_pos; 800 } 801 target_at_put(fixup_pos, pos); 802 } else { 803 DCHECK(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr)); 804 target_at_put(fixup_pos, pos); 805 } 806 } 807 L->bind_to(pos); 808 809 // Keep track of the last bound label so we don't eliminate any instructions 810 // before a bound label. 811 if (pos > last_bound_pos_) 812 last_bound_pos_ = pos; 813 } 814 815 816 void Assembler::bind(Label* L) { 817 DCHECK(!L->is_bound()); // Label can only be bound once. 818 bind_to(L, pc_offset()); 819 } 820 821 822 void Assembler::next(Label* L) { 823 DCHECK(L->is_linked()); 824 int link = target_at(L->pos()); 825 if (link == kEndOfChain) { 826 L->Unuse(); 827 } else { 828 DCHECK(link >= 0); 829 L->link_to(link); 830 } 831 } 832 833 834 bool Assembler::is_near(Label* L) { 835 if (L->is_bound()) { 836 return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize); 837 } 838 return false; 839 } 840 841 842 // We have to use a temporary register for things that can be relocated even 843 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction 844 // space. There is no guarantee that the relocated location can be similarly 845 // encoded. 846 bool Assembler::MustUseReg(RelocInfo::Mode rmode) { 847 return !RelocInfo::IsNone(rmode); 848 } 849 850 void Assembler::GenInstrRegister(Opcode opcode, 851 Register rs, 852 Register rt, 853 Register rd, 854 uint16_t sa, 855 SecondaryField func) { 856 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa)); 857 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) 858 | (rd.code() << kRdShift) | (sa << kSaShift) | func; 859 emit(instr); 860 } 861 862 863 void Assembler::GenInstrRegister(Opcode opcode, 864 Register rs, 865 Register rt, 866 uint16_t msb, 867 uint16_t lsb, 868 SecondaryField func) { 869 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb)); 870 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) 871 | (msb << kRdShift) | (lsb << kSaShift) | func; 872 emit(instr); 873 } 874 875 876 void Assembler::GenInstrRegister(Opcode opcode, 877 SecondaryField fmt, 878 FPURegister ft, 879 FPURegister fs, 880 FPURegister fd, 881 SecondaryField func) { 882 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid()); 883 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift) 884 | (fd.code() << kFdShift) | func; 885 emit(instr); 886 } 887 888 889 void Assembler::GenInstrRegister(Opcode opcode, 890 FPURegister fr, 891 FPURegister ft, 892 FPURegister fs, 893 FPURegister fd, 894 SecondaryField func) { 895 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid()); 896 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift) 897 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func; 898 emit(instr); 899 } 900 901 902 void Assembler::GenInstrRegister(Opcode opcode, 903 SecondaryField fmt, 904 Register rt, 905 FPURegister fs, 906 FPURegister fd, 907 SecondaryField func) { 908 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid()); 909 Instr instr = opcode | fmt | (rt.code() << kRtShift) 910 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func; 911 emit(instr); 912 } 913 914 915 void Assembler::GenInstrRegister(Opcode opcode, 916 SecondaryField fmt, 917 Register rt, 918 FPUControlRegister fs, 919 SecondaryField func) { 920 DCHECK(fs.is_valid() && rt.is_valid()); 921 Instr instr = 922 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func; 923 emit(instr); 924 } 925 926 927 // Instructions with immediate value. 928 // Registers are in the order of the instruction encoding, from left to right. 929 void Assembler::GenInstrImmediate(Opcode opcode, 930 Register rs, 931 Register rt, 932 int32_t j) { 933 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j))); 934 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) 935 | (j & kImm16Mask); 936 emit(instr); 937 } 938 939 940 void Assembler::GenInstrImmediate(Opcode opcode, 941 Register rs, 942 SecondaryField SF, 943 int32_t j) { 944 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j))); 945 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask); 946 emit(instr); 947 } 948 949 950 void Assembler::GenInstrImmediate(Opcode opcode, 951 Register rs, 952 FPURegister ft, 953 int32_t j) { 954 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j))); 955 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift) 956 | (j & kImm16Mask); 957 emit(instr); 958 } 959 960 961 void Assembler::GenInstrJump(Opcode opcode, 962 uint32_t address) { 963 BlockTrampolinePoolScope block_trampoline_pool(this); 964 DCHECK(is_uint26(address)); 965 Instr instr = opcode | address; 966 emit(instr); 967 BlockTrampolinePoolFor(1); // For associated delay slot. 968 } 969 970 971 // Returns the next free trampoline entry. 972 int32_t Assembler::get_trampoline_entry(int32_t pos) { 973 int32_t trampoline_entry = kInvalidSlotPos; 974 if (!internal_trampoline_exception_) { 975 if (trampoline_.start() > pos) { 976 trampoline_entry = trampoline_.take_slot(); 977 } 978 979 if (kInvalidSlotPos == trampoline_entry) { 980 internal_trampoline_exception_ = true; 981 } 982 } 983 return trampoline_entry; 984 } 985 986 987 uint64_t Assembler::jump_address(Label* L) { 988 int64_t target_pos; 989 if (L->is_bound()) { 990 target_pos = L->pos(); 991 } else { 992 if (L->is_linked()) { 993 target_pos = L->pos(); // L's link. 994 L->link_to(pc_offset()); 995 } else { 996 L->link_to(pc_offset()); 997 return kEndOfJumpChain; 998 } 999 } 1000 1001 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos; 1002 DCHECK((imm & 3) == 0); 1003 1004 return imm; 1005 } 1006 1007 1008 int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { 1009 int32_t target_pos; 1010 if (L->is_bound()) { 1011 target_pos = L->pos(); 1012 } else { 1013 if (L->is_linked()) { 1014 target_pos = L->pos(); 1015 L->link_to(pc_offset()); 1016 } else { 1017 L->link_to(pc_offset()); 1018 if (!trampoline_emitted_) { 1019 unbound_labels_count_++; 1020 next_buffer_check_ -= kTrampolineSlotsSize; 1021 } 1022 return kEndOfChain; 1023 } 1024 } 1025 1026 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset); 1027 DCHECK((offset & 3) == 0); 1028 DCHECK(is_int16(offset >> 2)); 1029 1030 return offset; 1031 } 1032 1033 1034 int32_t Assembler::branch_offset_compact(Label* L, 1035 bool jump_elimination_allowed) { 1036 int32_t target_pos; 1037 if (L->is_bound()) { 1038 target_pos = L->pos(); 1039 } else { 1040 if (L->is_linked()) { 1041 target_pos = L->pos(); 1042 L->link_to(pc_offset()); 1043 } else { 1044 L->link_to(pc_offset()); 1045 if (!trampoline_emitted_) { 1046 unbound_labels_count_++; 1047 next_buffer_check_ -= kTrampolineSlotsSize; 1048 } 1049 return kEndOfChain; 1050 } 1051 } 1052 1053 int32_t offset = target_pos - pc_offset(); 1054 DCHECK((offset & 3) == 0); 1055 DCHECK(is_int16(offset >> 2)); 1056 1057 return offset; 1058 } 1059 1060 1061 int32_t Assembler::branch_offset21(Label* L, bool jump_elimination_allowed) { 1062 int32_t target_pos; 1063 if (L->is_bound()) { 1064 target_pos = L->pos(); 1065 } else { 1066 if (L->is_linked()) { 1067 target_pos = L->pos(); 1068 L->link_to(pc_offset()); 1069 } else { 1070 L->link_to(pc_offset()); 1071 if (!trampoline_emitted_) { 1072 unbound_labels_count_++; 1073 next_buffer_check_ -= kTrampolineSlotsSize; 1074 } 1075 return kEndOfChain; 1076 } 1077 } 1078 1079 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset); 1080 DCHECK((offset & 3) == 0); 1081 DCHECK(((offset >> 2) & 0xFFE00000) == 0); // Offset is 21bit width. 1082 1083 return offset; 1084 } 1085 1086 1087 int32_t Assembler::branch_offset21_compact(Label* L, 1088 bool jump_elimination_allowed) { 1089 int32_t target_pos; 1090 if (L->is_bound()) { 1091 target_pos = L->pos(); 1092 } else { 1093 if (L->is_linked()) { 1094 target_pos = L->pos(); 1095 L->link_to(pc_offset()); 1096 } else { 1097 L->link_to(pc_offset()); 1098 if (!trampoline_emitted_) { 1099 unbound_labels_count_++; 1100 next_buffer_check_ -= kTrampolineSlotsSize; 1101 } 1102 return kEndOfChain; 1103 } 1104 } 1105 1106 int32_t offset = target_pos - pc_offset(); 1107 DCHECK((offset & 3) == 0); 1108 DCHECK(((offset >> 2) & 0xFFE00000) == 0); // Offset is 21bit width. 1109 1110 return offset; 1111 } 1112 1113 1114 void Assembler::label_at_put(Label* L, int at_offset) { 1115 int target_pos; 1116 if (L->is_bound()) { 1117 target_pos = L->pos(); 1118 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); 1119 } else { 1120 if (L->is_linked()) { 1121 target_pos = L->pos(); // L's link. 1122 int32_t imm18 = target_pos - at_offset; 1123 DCHECK((imm18 & 3) == 0); 1124 int32_t imm16 = imm18 >> 2; 1125 DCHECK(is_int16(imm16)); 1126 instr_at_put(at_offset, (imm16 & kImm16Mask)); 1127 } else { 1128 target_pos = kEndOfChain; 1129 instr_at_put(at_offset, 0); 1130 if (!trampoline_emitted_) { 1131 unbound_labels_count_++; 1132 next_buffer_check_ -= kTrampolineSlotsSize; 1133 } 1134 } 1135 L->link_to(at_offset); 1136 } 1137 } 1138 1139 1140 //------- Branch and jump instructions -------- 1141 1142 void Assembler::b(int16_t offset) { 1143 beq(zero_reg, zero_reg, offset); 1144 } 1145 1146 1147 void Assembler::bal(int16_t offset) { 1148 positions_recorder()->WriteRecordedPositions(); 1149 bgezal(zero_reg, offset); 1150 } 1151 1152 1153 void Assembler::beq(Register rs, Register rt, int16_t offset) { 1154 BlockTrampolinePoolScope block_trampoline_pool(this); 1155 GenInstrImmediate(BEQ, rs, rt, offset); 1156 BlockTrampolinePoolFor(1); // For associated delay slot. 1157 } 1158 1159 1160 void Assembler::bgez(Register rs, int16_t offset) { 1161 BlockTrampolinePoolScope block_trampoline_pool(this); 1162 GenInstrImmediate(REGIMM, rs, BGEZ, offset); 1163 BlockTrampolinePoolFor(1); // For associated delay slot. 1164 } 1165 1166 1167 void Assembler::bgezc(Register rt, int16_t offset) { 1168 DCHECK(kArchVariant == kMips64r6); 1169 DCHECK(!(rt.is(zero_reg))); 1170 GenInstrImmediate(BLEZL, rt, rt, offset); 1171 } 1172 1173 1174 void Assembler::bgeuc(Register rs, Register rt, int16_t offset) { 1175 DCHECK(kArchVariant == kMips64r6); 1176 DCHECK(!(rs.is(zero_reg))); 1177 DCHECK(!(rt.is(zero_reg))); 1178 DCHECK(rs.code() != rt.code()); 1179 GenInstrImmediate(BLEZ, rs, rt, offset); 1180 } 1181 1182 1183 void Assembler::bgec(Register rs, Register rt, int16_t offset) { 1184 DCHECK(kArchVariant == kMips64r6); 1185 DCHECK(!(rs.is(zero_reg))); 1186 DCHECK(!(rt.is(zero_reg))); 1187 DCHECK(rs.code() != rt.code()); 1188 GenInstrImmediate(BLEZL, rs, rt, offset); 1189 } 1190 1191 1192 void Assembler::bgezal(Register rs, int16_t offset) { 1193 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg)); 1194 BlockTrampolinePoolScope block_trampoline_pool(this); 1195 positions_recorder()->WriteRecordedPositions(); 1196 GenInstrImmediate(REGIMM, rs, BGEZAL, offset); 1197 BlockTrampolinePoolFor(1); // For associated delay slot. 1198 } 1199 1200 1201 void Assembler::bgtz(Register rs, int16_t offset) { 1202 BlockTrampolinePoolScope block_trampoline_pool(this); 1203 GenInstrImmediate(BGTZ, rs, zero_reg, offset); 1204 BlockTrampolinePoolFor(1); // For associated delay slot. 1205 } 1206 1207 1208 void Assembler::bgtzc(Register rt, int16_t offset) { 1209 DCHECK(kArchVariant == kMips64r6); 1210 DCHECK(!(rt.is(zero_reg))); 1211 GenInstrImmediate(BGTZL, zero_reg, rt, offset); 1212 } 1213 1214 1215 void Assembler::blez(Register rs, int16_t offset) { 1216 BlockTrampolinePoolScope block_trampoline_pool(this); 1217 GenInstrImmediate(BLEZ, rs, zero_reg, offset); 1218 BlockTrampolinePoolFor(1); // For associated delay slot. 1219 } 1220 1221 1222 void Assembler::blezc(Register rt, int16_t offset) { 1223 DCHECK(kArchVariant == kMips64r6); 1224 DCHECK(!(rt.is(zero_reg))); 1225 GenInstrImmediate(BLEZL, zero_reg, rt, offset); 1226 } 1227 1228 1229 void Assembler::bltzc(Register rt, int16_t offset) { 1230 DCHECK(kArchVariant == kMips64r6); 1231 DCHECK(!(rt.is(zero_reg))); 1232 GenInstrImmediate(BGTZL, rt, rt, offset); 1233 } 1234 1235 1236 void Assembler::bltuc(Register rs, Register rt, int16_t offset) { 1237 DCHECK(kArchVariant == kMips64r6); 1238 DCHECK(!(rs.is(zero_reg))); 1239 DCHECK(!(rt.is(zero_reg))); 1240 DCHECK(rs.code() != rt.code()); 1241 GenInstrImmediate(BGTZ, rs, rt, offset); 1242 } 1243 1244 1245 void Assembler::bltc(Register rs, Register rt, int16_t offset) { 1246 DCHECK(kArchVariant == kMips64r6); 1247 DCHECK(!(rs.is(zero_reg))); 1248 DCHECK(!(rt.is(zero_reg))); 1249 DCHECK(rs.code() != rt.code()); 1250 GenInstrImmediate(BGTZL, rs, rt, offset); 1251 } 1252 1253 1254 void Assembler::bltz(Register rs, int16_t offset) { 1255 BlockTrampolinePoolScope block_trampoline_pool(this); 1256 GenInstrImmediate(REGIMM, rs, BLTZ, offset); 1257 BlockTrampolinePoolFor(1); // For associated delay slot. 1258 } 1259 1260 1261 void Assembler::bltzal(Register rs, int16_t offset) { 1262 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg)); 1263 BlockTrampolinePoolScope block_trampoline_pool(this); 1264 positions_recorder()->WriteRecordedPositions(); 1265 GenInstrImmediate(REGIMM, rs, BLTZAL, offset); 1266 BlockTrampolinePoolFor(1); // For associated delay slot. 1267 } 1268 1269 1270 void Assembler::bne(Register rs, Register rt, int16_t offset) { 1271 BlockTrampolinePoolScope block_trampoline_pool(this); 1272 GenInstrImmediate(BNE, rs, rt, offset); 1273 BlockTrampolinePoolFor(1); // For associated delay slot. 1274 } 1275 1276 1277 void Assembler::bovc(Register rs, Register rt, int16_t offset) { 1278 DCHECK(kArchVariant == kMips64r6); 1279 DCHECK(!(rs.is(zero_reg))); 1280 DCHECK(rs.code() >= rt.code()); 1281 GenInstrImmediate(ADDI, rs, rt, offset); 1282 } 1283 1284 1285 void Assembler::bnvc(Register rs, Register rt, int16_t offset) { 1286 DCHECK(kArchVariant == kMips64r6); 1287 DCHECK(!(rs.is(zero_reg))); 1288 DCHECK(rs.code() >= rt.code()); 1289 GenInstrImmediate(DADDI, rs, rt, offset); 1290 } 1291 1292 1293 void Assembler::blezalc(Register rt, int16_t offset) { 1294 DCHECK(kArchVariant == kMips64r6); 1295 DCHECK(!(rt.is(zero_reg))); 1296 GenInstrImmediate(BLEZ, zero_reg, rt, offset); 1297 } 1298 1299 1300 void Assembler::bgezalc(Register rt, int16_t offset) { 1301 DCHECK(kArchVariant == kMips64r6); 1302 DCHECK(!(rt.is(zero_reg))); 1303 GenInstrImmediate(BLEZ, rt, rt, offset); 1304 } 1305 1306 1307 void Assembler::bgezall(Register rs, int16_t offset) { 1308 DCHECK(kArchVariant == kMips64r6); 1309 DCHECK(!(rs.is(zero_reg))); 1310 GenInstrImmediate(REGIMM, rs, BGEZALL, offset); 1311 } 1312 1313 1314 void Assembler::bltzalc(Register rt, int16_t offset) { 1315 DCHECK(kArchVariant == kMips64r6); 1316 DCHECK(!(rt.is(zero_reg))); 1317 GenInstrImmediate(BGTZ, rt, rt, offset); 1318 } 1319 1320 1321 void Assembler::bgtzalc(Register rt, int16_t offset) { 1322 DCHECK(kArchVariant == kMips64r6); 1323 DCHECK(!(rt.is(zero_reg))); 1324 GenInstrImmediate(BGTZ, zero_reg, rt, offset); 1325 } 1326 1327 1328 void Assembler::beqzalc(Register rt, int16_t offset) { 1329 DCHECK(kArchVariant == kMips64r6); 1330 DCHECK(!(rt.is(zero_reg))); 1331 GenInstrImmediate(ADDI, zero_reg, rt, offset); 1332 } 1333 1334 1335 void Assembler::bnezalc(Register rt, int16_t offset) { 1336 DCHECK(kArchVariant == kMips64r6); 1337 DCHECK(!(rt.is(zero_reg))); 1338 GenInstrImmediate(DADDI, zero_reg, rt, offset); 1339 } 1340 1341 1342 void Assembler::beqc(Register rs, Register rt, int16_t offset) { 1343 DCHECK(kArchVariant == kMips64r6); 1344 DCHECK(rs.code() < rt.code()); 1345 GenInstrImmediate(ADDI, rs, rt, offset); 1346 } 1347 1348 1349 void Assembler::beqzc(Register rs, int32_t offset) { 1350 DCHECK(kArchVariant == kMips64r6); 1351 DCHECK(!(rs.is(zero_reg))); 1352 Instr instr = BEQZC | (rs.code() << kRsShift) | offset; 1353 emit(instr); 1354 } 1355 1356 1357 void Assembler::bnec(Register rs, Register rt, int16_t offset) { 1358 DCHECK(kArchVariant == kMips64r6); 1359 DCHECK(rs.code() < rt.code()); 1360 GenInstrImmediate(DADDI, rs, rt, offset); 1361 } 1362 1363 1364 void Assembler::bnezc(Register rs, int32_t offset) { 1365 DCHECK(kArchVariant == kMips64r6); 1366 DCHECK(!(rs.is(zero_reg))); 1367 Instr instr = BNEZC | (rs.code() << kRsShift) | offset; 1368 emit(instr); 1369 } 1370 1371 1372 void Assembler::j(int64_t target) { 1373 #if DEBUG 1374 // Get pc of delay slot. 1375 uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); 1376 bool in_range = (ipc ^ static_cast<uint64_t>(target) >> 1377 (kImm26Bits + kImmFieldShift)) == 0; 1378 DCHECK(in_range && ((target & 3) == 0)); 1379 #endif 1380 GenInstrJump(J, target >> 2); 1381 } 1382 1383 1384 void Assembler::jr(Register rs) { 1385 if (kArchVariant != kMips64r6) { 1386 BlockTrampolinePoolScope block_trampoline_pool(this); 1387 if (rs.is(ra)) { 1388 positions_recorder()->WriteRecordedPositions(); 1389 } 1390 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR); 1391 BlockTrampolinePoolFor(1); // For associated delay slot. 1392 } else { 1393 jalr(rs, zero_reg); 1394 } 1395 } 1396 1397 1398 void Assembler::jal(int64_t target) { 1399 #ifdef DEBUG 1400 // Get pc of delay slot. 1401 uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); 1402 bool in_range = (ipc ^ static_cast<uint64_t>(target) >> 1403 (kImm26Bits + kImmFieldShift)) == 0; 1404 DCHECK(in_range && ((target & 3) == 0)); 1405 #endif 1406 positions_recorder()->WriteRecordedPositions(); 1407 GenInstrJump(JAL, target >> 2); 1408 } 1409 1410 1411 void Assembler::jalr(Register rs, Register rd) { 1412 BlockTrampolinePoolScope block_trampoline_pool(this); 1413 positions_recorder()->WriteRecordedPositions(); 1414 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR); 1415 BlockTrampolinePoolFor(1); // For associated delay slot. 1416 } 1417 1418 1419 void Assembler::j_or_jr(int64_t target, Register rs) { 1420 // Get pc of delay slot. 1421 uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); 1422 bool in_range = (ipc ^ static_cast<uint64_t>(target) >> 1423 (kImm26Bits + kImmFieldShift)) == 0; 1424 if (in_range) { 1425 j(target); 1426 } else { 1427 jr(t9); 1428 } 1429 } 1430 1431 1432 void Assembler::jal_or_jalr(int64_t target, Register rs) { 1433 // Get pc of delay slot. 1434 uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); 1435 bool in_range = (ipc ^ static_cast<uint64_t>(target) >> 1436 (kImm26Bits+kImmFieldShift)) == 0; 1437 if (in_range) { 1438 jal(target); 1439 } else { 1440 jalr(t9); 1441 } 1442 } 1443 1444 1445 // -------Data-processing-instructions--------- 1446 1447 // Arithmetic. 1448 1449 void Assembler::addu(Register rd, Register rs, Register rt) { 1450 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU); 1451 } 1452 1453 1454 void Assembler::addiu(Register rd, Register rs, int32_t j) { 1455 GenInstrImmediate(ADDIU, rs, rd, j); 1456 } 1457 1458 1459 void Assembler::subu(Register rd, Register rs, Register rt) { 1460 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU); 1461 } 1462 1463 1464 void Assembler::mul(Register rd, Register rs, Register rt) { 1465 if (kArchVariant == kMips64r6) { 1466 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH); 1467 } else { 1468 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL); 1469 } 1470 } 1471 1472 1473 void Assembler::muh(Register rd, Register rs, Register rt) { 1474 DCHECK(kArchVariant == kMips64r6); 1475 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH); 1476 } 1477 1478 1479 void Assembler::mulu(Register rd, Register rs, Register rt) { 1480 DCHECK(kArchVariant == kMips64r6); 1481 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U); 1482 } 1483 1484 1485 void Assembler::muhu(Register rd, Register rs, Register rt) { 1486 DCHECK(kArchVariant == kMips64r6); 1487 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U); 1488 } 1489 1490 1491 void Assembler::dmul(Register rd, Register rs, Register rt) { 1492 DCHECK(kArchVariant == kMips64r6); 1493 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH); 1494 } 1495 1496 1497 void Assembler::dmuh(Register rd, Register rs, Register rt) { 1498 DCHECK(kArchVariant == kMips64r6); 1499 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH); 1500 } 1501 1502 1503 void Assembler::dmulu(Register rd, Register rs, Register rt) { 1504 DCHECK(kArchVariant == kMips64r6); 1505 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH_U); 1506 } 1507 1508 1509 void Assembler::dmuhu(Register rd, Register rs, Register rt) { 1510 DCHECK(kArchVariant == kMips64r6); 1511 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH_U); 1512 } 1513 1514 1515 void Assembler::mult(Register rs, Register rt) { 1516 DCHECK(kArchVariant != kMips64r6); 1517 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT); 1518 } 1519 1520 1521 void Assembler::multu(Register rs, Register rt) { 1522 DCHECK(kArchVariant != kMips64r6); 1523 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU); 1524 } 1525 1526 1527 void Assembler::daddiu(Register rd, Register rs, int32_t j) { 1528 GenInstrImmediate(DADDIU, rs, rd, j); 1529 } 1530 1531 1532 void Assembler::div(Register rs, Register rt) { 1533 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV); 1534 } 1535 1536 1537 void Assembler::div(Register rd, Register rs, Register rt) { 1538 DCHECK(kArchVariant == kMips64r6); 1539 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD); 1540 } 1541 1542 1543 void Assembler::mod(Register rd, Register rs, Register rt) { 1544 DCHECK(kArchVariant == kMips64r6); 1545 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD); 1546 } 1547 1548 1549 void Assembler::divu(Register rs, Register rt) { 1550 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU); 1551 } 1552 1553 1554 void Assembler::divu(Register rd, Register rs, Register rt) { 1555 DCHECK(kArchVariant == kMips64r6); 1556 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U); 1557 } 1558 1559 1560 void Assembler::modu(Register rd, Register rs, Register rt) { 1561 DCHECK(kArchVariant == kMips64r6); 1562 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U); 1563 } 1564 1565 1566 void Assembler::daddu(Register rd, Register rs, Register rt) { 1567 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DADDU); 1568 } 1569 1570 1571 void Assembler::dsubu(Register rd, Register rs, Register rt) { 1572 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSUBU); 1573 } 1574 1575 1576 void Assembler::dmult(Register rs, Register rt) { 1577 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULT); 1578 } 1579 1580 1581 void Assembler::dmultu(Register rs, Register rt) { 1582 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULTU); 1583 } 1584 1585 1586 void Assembler::ddiv(Register rs, Register rt) { 1587 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIV); 1588 } 1589 1590 1591 void Assembler::ddiv(Register rd, Register rs, Register rt) { 1592 DCHECK(kArchVariant == kMips64r6); 1593 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD); 1594 } 1595 1596 1597 void Assembler::dmod(Register rd, Register rs, Register rt) { 1598 DCHECK(kArchVariant == kMips64r6); 1599 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD); 1600 } 1601 1602 1603 void Assembler::ddivu(Register rs, Register rt) { 1604 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIVU); 1605 } 1606 1607 1608 void Assembler::ddivu(Register rd, Register rs, Register rt) { 1609 DCHECK(kArchVariant == kMips64r6); 1610 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD_U); 1611 } 1612 1613 1614 void Assembler::dmodu(Register rd, Register rs, Register rt) { 1615 DCHECK(kArchVariant == kMips64r6); 1616 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD_U); 1617 } 1618 1619 1620 // Logical. 1621 1622 void Assembler::and_(Register rd, Register rs, Register rt) { 1623 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND); 1624 } 1625 1626 1627 void Assembler::andi(Register rt, Register rs, int32_t j) { 1628 DCHECK(is_uint16(j)); 1629 GenInstrImmediate(ANDI, rs, rt, j); 1630 } 1631 1632 1633 void Assembler::or_(Register rd, Register rs, Register rt) { 1634 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR); 1635 } 1636 1637 1638 void Assembler::ori(Register rt, Register rs, int32_t j) { 1639 DCHECK(is_uint16(j)); 1640 GenInstrImmediate(ORI, rs, rt, j); 1641 } 1642 1643 1644 void Assembler::xor_(Register rd, Register rs, Register rt) { 1645 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR); 1646 } 1647 1648 1649 void Assembler::xori(Register rt, Register rs, int32_t j) { 1650 DCHECK(is_uint16(j)); 1651 GenInstrImmediate(XORI, rs, rt, j); 1652 } 1653 1654 1655 void Assembler::nor(Register rd, Register rs, Register rt) { 1656 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR); 1657 } 1658 1659 1660 // Shifts. 1661 void Assembler::sll(Register rd, 1662 Register rt, 1663 uint16_t sa, 1664 bool coming_from_nop) { 1665 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be 1666 // generated using the sll instruction. They must be generated using 1667 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo 1668 // instructions. 1669 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg))); 1670 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL); 1671 } 1672 1673 1674 void Assembler::sllv(Register rd, Register rt, Register rs) { 1675 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV); 1676 } 1677 1678 1679 void Assembler::srl(Register rd, Register rt, uint16_t sa) { 1680 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL); 1681 } 1682 1683 1684 void Assembler::srlv(Register rd, Register rt, Register rs) { 1685 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV); 1686 } 1687 1688 1689 void Assembler::sra(Register rd, Register rt, uint16_t sa) { 1690 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA); 1691 } 1692 1693 1694 void Assembler::srav(Register rd, Register rt, Register rs) { 1695 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV); 1696 } 1697 1698 1699 void Assembler::rotr(Register rd, Register rt, uint16_t sa) { 1700 // Should be called via MacroAssembler::Ror. 1701 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa)); 1702 DCHECK(kArchVariant == kMips64r2); 1703 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift) 1704 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL; 1705 emit(instr); 1706 } 1707 1708 1709 void Assembler::rotrv(Register rd, Register rt, Register rs) { 1710 // Should be called via MacroAssembler::Ror. 1711 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() ); 1712 DCHECK(kArchVariant == kMips64r2); 1713 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) 1714 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV; 1715 emit(instr); 1716 } 1717 1718 1719 void Assembler::dsll(Register rd, Register rt, uint16_t sa) { 1720 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSLL); 1721 } 1722 1723 1724 void Assembler::dsllv(Register rd, Register rt, Register rs) { 1725 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSLLV); 1726 } 1727 1728 1729 void Assembler::dsrl(Register rd, Register rt, uint16_t sa) { 1730 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRL); 1731 } 1732 1733 1734 void Assembler::dsrlv(Register rd, Register rt, Register rs) { 1735 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRLV); 1736 } 1737 1738 1739 void Assembler::drotr(Register rd, Register rt, uint16_t sa) { 1740 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa)); 1741 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift) 1742 | (rd.code() << kRdShift) | (sa << kSaShift) | DSRL; 1743 emit(instr); 1744 } 1745 1746 1747 void Assembler::drotrv(Register rd, Register rt, Register rs) { 1748 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() ); 1749 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) 1750 | (rd.code() << kRdShift) | (1 << kSaShift) | DSRLV; 1751 emit(instr); 1752 } 1753 1754 1755 void Assembler::dsra(Register rd, Register rt, uint16_t sa) { 1756 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRA); 1757 } 1758 1759 1760 void Assembler::dsrav(Register rd, Register rt, Register rs) { 1761 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRAV); 1762 } 1763 1764 1765 void Assembler::dsll32(Register rd, Register rt, uint16_t sa) { 1766 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSLL32); 1767 } 1768 1769 1770 void Assembler::dsrl32(Register rd, Register rt, uint16_t sa) { 1771 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRL32); 1772 } 1773 1774 1775 void Assembler::dsra32(Register rd, Register rt, uint16_t sa) { 1776 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRA32); 1777 } 1778 1779 1780 // ------------Memory-instructions------------- 1781 1782 // Helper for base-reg + offset, when offset is larger than int16. 1783 void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) { 1784 DCHECK(!src.rm().is(at)); 1785 DCHECK(is_int32(src.offset_)); 1786 daddiu(at, zero_reg, (src.offset_ >> kLuiShift) & kImm16Mask); 1787 dsll(at, at, kLuiShift); 1788 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset. 1789 daddu(at, at, src.rm()); // Add base register. 1790 } 1791 1792 1793 void Assembler::lb(Register rd, const MemOperand& rs) { 1794 if (is_int16(rs.offset_)) { 1795 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_); 1796 } else { // Offset > 16 bits, use multiple instructions to load. 1797 LoadRegPlusOffsetToAt(rs); 1798 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0)); 1799 } 1800 } 1801 1802 1803 void Assembler::lbu(Register rd, const MemOperand& rs) { 1804 if (is_int16(rs.offset_)) { 1805 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_); 1806 } else { // Offset > 16 bits, use multiple instructions to load. 1807 LoadRegPlusOffsetToAt(rs); 1808 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0)); 1809 } 1810 } 1811 1812 1813 void Assembler::lh(Register rd, const MemOperand& rs) { 1814 if (is_int16(rs.offset_)) { 1815 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_); 1816 } else { // Offset > 16 bits, use multiple instructions to load. 1817 LoadRegPlusOffsetToAt(rs); 1818 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0)); 1819 } 1820 } 1821 1822 1823 void Assembler::lhu(Register rd, const MemOperand& rs) { 1824 if (is_int16(rs.offset_)) { 1825 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_); 1826 } else { // Offset > 16 bits, use multiple instructions to load. 1827 LoadRegPlusOffsetToAt(rs); 1828 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0)); 1829 } 1830 } 1831 1832 1833 void Assembler::lw(Register rd, const MemOperand& rs) { 1834 if (is_int16(rs.offset_)) { 1835 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_); 1836 } else { // Offset > 16 bits, use multiple instructions to load. 1837 LoadRegPlusOffsetToAt(rs); 1838 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0)); 1839 } 1840 } 1841 1842 1843 void Assembler::lwu(Register rd, const MemOperand& rs) { 1844 if (is_int16(rs.offset_)) { 1845 GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_); 1846 } else { // Offset > 16 bits, use multiple instructions to load. 1847 LoadRegPlusOffsetToAt(rs); 1848 GenInstrImmediate(LWU, at, rd, 0); // Equiv to lwu(rd, MemOperand(at, 0)); 1849 } 1850 } 1851 1852 1853 void Assembler::lwl(Register rd, const MemOperand& rs) { 1854 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_); 1855 } 1856 1857 1858 void Assembler::lwr(Register rd, const MemOperand& rs) { 1859 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_); 1860 } 1861 1862 1863 void Assembler::sb(Register rd, const MemOperand& rs) { 1864 if (is_int16(rs.offset_)) { 1865 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_); 1866 } else { // Offset > 16 bits, use multiple instructions to store. 1867 LoadRegPlusOffsetToAt(rs); 1868 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0)); 1869 } 1870 } 1871 1872 1873 void Assembler::sh(Register rd, const MemOperand& rs) { 1874 if (is_int16(rs.offset_)) { 1875 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_); 1876 } else { // Offset > 16 bits, use multiple instructions to store. 1877 LoadRegPlusOffsetToAt(rs); 1878 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0)); 1879 } 1880 } 1881 1882 1883 void Assembler::sw(Register rd, const MemOperand& rs) { 1884 if (is_int16(rs.offset_)) { 1885 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_); 1886 } else { // Offset > 16 bits, use multiple instructions to store. 1887 LoadRegPlusOffsetToAt(rs); 1888 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0)); 1889 } 1890 } 1891 1892 1893 void Assembler::swl(Register rd, const MemOperand& rs) { 1894 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_); 1895 } 1896 1897 1898 void Assembler::swr(Register rd, const MemOperand& rs) { 1899 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_); 1900 } 1901 1902 1903 void Assembler::lui(Register rd, int32_t j) { 1904 DCHECK(is_uint16(j)); 1905 GenInstrImmediate(LUI, zero_reg, rd, j); 1906 } 1907 1908 1909 void Assembler::aui(Register rs, Register rt, int32_t j) { 1910 // This instruction uses same opcode as 'lui'. The difference in encoding is 1911 // 'lui' has zero reg. for rs field. 1912 DCHECK(is_uint16(j)); 1913 GenInstrImmediate(LUI, rs, rt, j); 1914 } 1915 1916 1917 void Assembler::daui(Register rs, Register rt, int32_t j) { 1918 DCHECK(is_uint16(j)); 1919 GenInstrImmediate(DAUI, rs, rt, j); 1920 } 1921 1922 1923 void Assembler::dahi(Register rs, int32_t j) { 1924 DCHECK(is_uint16(j)); 1925 GenInstrImmediate(REGIMM, rs, DAHI, j); 1926 } 1927 1928 1929 void Assembler::dati(Register rs, int32_t j) { 1930 DCHECK(is_uint16(j)); 1931 GenInstrImmediate(REGIMM, rs, DATI, j); 1932 } 1933 1934 1935 void Assembler::ldl(Register rd, const MemOperand& rs) { 1936 GenInstrImmediate(LDL, rs.rm(), rd, rs.offset_); 1937 } 1938 1939 1940 void Assembler::ldr(Register rd, const MemOperand& rs) { 1941 GenInstrImmediate(LDR, rs.rm(), rd, rs.offset_); 1942 } 1943 1944 1945 void Assembler::sdl(Register rd, const MemOperand& rs) { 1946 GenInstrImmediate(SDL, rs.rm(), rd, rs.offset_); 1947 } 1948 1949 1950 void Assembler::sdr(Register rd, const MemOperand& rs) { 1951 GenInstrImmediate(SDR, rs.rm(), rd, rs.offset_); 1952 } 1953 1954 1955 void Assembler::ld(Register rd, const MemOperand& rs) { 1956 if (is_int16(rs.offset_)) { 1957 GenInstrImmediate(LD, rs.rm(), rd, rs.offset_); 1958 } else { // Offset > 16 bits, use multiple instructions to load. 1959 LoadRegPlusOffsetToAt(rs); 1960 GenInstrImmediate(LD, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0)); 1961 } 1962 } 1963 1964 1965 void Assembler::sd(Register rd, const MemOperand& rs) { 1966 if (is_int16(rs.offset_)) { 1967 GenInstrImmediate(SD, rs.rm(), rd, rs.offset_); 1968 } else { // Offset > 16 bits, use multiple instructions to store. 1969 LoadRegPlusOffsetToAt(rs); 1970 GenInstrImmediate(SD, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0)); 1971 } 1972 } 1973 1974 1975 // -------------Misc-instructions-------------- 1976 1977 // Break / Trap instructions. 1978 void Assembler::break_(uint32_t code, bool break_as_stop) { 1979 DCHECK((code & ~0xfffff) == 0); 1980 // We need to invalidate breaks that could be stops as well because the 1981 // simulator expects a char pointer after the stop instruction. 1982 // See constants-mips.h for explanation. 1983 DCHECK((break_as_stop && 1984 code <= kMaxStopCode && 1985 code > kMaxWatchpointCode) || 1986 (!break_as_stop && 1987 (code > kMaxStopCode || 1988 code <= kMaxWatchpointCode))); 1989 Instr break_instr = SPECIAL | BREAK | (code << 6); 1990 emit(break_instr); 1991 } 1992 1993 1994 void Assembler::stop(const char* msg, uint32_t code) { 1995 DCHECK(code > kMaxWatchpointCode); 1996 DCHECK(code <= kMaxStopCode); 1997 #if defined(V8_HOST_ARCH_MIPS) || defined(V8_HOST_ARCH_MIPS64) 1998 break_(0x54321); 1999 #else // V8_HOST_ARCH_MIPS 2000 BlockTrampolinePoolFor(3); 2001 // The Simulator will handle the stop instruction and get the message address. 2002 // On MIPS stop() is just a special kind of break_(). 2003 break_(code, true); 2004 emit(reinterpret_cast<uint64_t>(msg)); 2005 #endif 2006 } 2007 2008 2009 void Assembler::tge(Register rs, Register rt, uint16_t code) { 2010 DCHECK(is_uint10(code)); 2011 Instr instr = SPECIAL | TGE | rs.code() << kRsShift 2012 | rt.code() << kRtShift | code << 6; 2013 emit(instr); 2014 } 2015 2016 2017 void Assembler::tgeu(Register rs, Register rt, uint16_t code) { 2018 DCHECK(is_uint10(code)); 2019 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift 2020 | rt.code() << kRtShift | code << 6; 2021 emit(instr); 2022 } 2023 2024 2025 void Assembler::tlt(Register rs, Register rt, uint16_t code) { 2026 DCHECK(is_uint10(code)); 2027 Instr instr = 2028 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6; 2029 emit(instr); 2030 } 2031 2032 2033 void Assembler::tltu(Register rs, Register rt, uint16_t code) { 2034 DCHECK(is_uint10(code)); 2035 Instr instr = 2036 SPECIAL | TLTU | rs.code() << kRsShift 2037 | rt.code() << kRtShift | code << 6; 2038 emit(instr); 2039 } 2040 2041 2042 void Assembler::teq(Register rs, Register rt, uint16_t code) { 2043 DCHECK(is_uint10(code)); 2044 Instr instr = 2045 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6; 2046 emit(instr); 2047 } 2048 2049 2050 void Assembler::tne(Register rs, Register rt, uint16_t code) { 2051 DCHECK(is_uint10(code)); 2052 Instr instr = 2053 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6; 2054 emit(instr); 2055 } 2056 2057 2058 // Move from HI/LO register. 2059 2060 void Assembler::mfhi(Register rd) { 2061 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI); 2062 } 2063 2064 2065 void Assembler::mflo(Register rd) { 2066 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO); 2067 } 2068 2069 2070 // Set on less than instructions. 2071 void Assembler::slt(Register rd, Register rs, Register rt) { 2072 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT); 2073 } 2074 2075 2076 void Assembler::sltu(Register rd, Register rs, Register rt) { 2077 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU); 2078 } 2079 2080 2081 void Assembler::slti(Register rt, Register rs, int32_t j) { 2082 GenInstrImmediate(SLTI, rs, rt, j); 2083 } 2084 2085 2086 void Assembler::sltiu(Register rt, Register rs, int32_t j) { 2087 GenInstrImmediate(SLTIU, rs, rt, j); 2088 } 2089 2090 2091 // Conditional move. 2092 void Assembler::movz(Register rd, Register rs, Register rt) { 2093 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ); 2094 } 2095 2096 2097 void Assembler::movn(Register rd, Register rs, Register rt) { 2098 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN); 2099 } 2100 2101 2102 void Assembler::movt(Register rd, Register rs, uint16_t cc) { 2103 Register rt; 2104 rt.code_ = (cc & 0x0007) << 2 | 1; 2105 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI); 2106 } 2107 2108 2109 void Assembler::movf(Register rd, Register rs, uint16_t cc) { 2110 Register rt; 2111 rt.code_ = (cc & 0x0007) << 2 | 0; 2112 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI); 2113 } 2114 2115 2116 void Assembler::sel(SecondaryField fmt, FPURegister fd, 2117 FPURegister ft, FPURegister fs, uint8_t sel) { 2118 DCHECK(kArchVariant == kMips64r6); 2119 DCHECK(fmt == D); 2120 DCHECK(fmt == S); 2121 2122 Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift | 2123 fs.code() << kFsShift | fd.code() << kFdShift | SEL; 2124 emit(instr); 2125 } 2126 2127 2128 // GPR. 2129 void Assembler::seleqz(Register rs, Register rt, Register rd) { 2130 DCHECK(kArchVariant == kMips64r6); 2131 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S); 2132 } 2133 2134 2135 // FPR. 2136 void Assembler::seleqz(SecondaryField fmt, FPURegister fd, 2137 FPURegister ft, FPURegister fs) { 2138 DCHECK(kArchVariant == kMips64r6); 2139 DCHECK(fmt == D); 2140 DCHECK(fmt == S); 2141 2142 Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift | 2143 fs.code() << kFsShift | fd.code() << kFdShift | SELEQZ_C; 2144 emit(instr); 2145 } 2146 2147 2148 // GPR. 2149 void Assembler::selnez(Register rs, Register rt, Register rd) { 2150 DCHECK(kArchVariant == kMips64r6); 2151 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S); 2152 } 2153 2154 2155 // FPR. 2156 void Assembler::selnez(SecondaryField fmt, FPURegister fd, 2157 FPURegister ft, FPURegister fs) { 2158 DCHECK(kArchVariant == kMips64r6); 2159 DCHECK(fmt == D); 2160 DCHECK(fmt == S); 2161 2162 Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift | 2163 fs.code() << kFsShift | fd.code() << kFdShift | SELNEZ_C; 2164 emit(instr); 2165 } 2166 2167 2168 // Bit twiddling. 2169 void Assembler::clz(Register rd, Register rs) { 2170 if (kArchVariant != kMips64r6) { 2171 // Clz instr requires same GPR number in 'rd' and 'rt' fields. 2172 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ); 2173 } else { 2174 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6); 2175 } 2176 } 2177 2178 2179 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) { 2180 // Should be called via MacroAssembler::Ins. 2181 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb. 2182 DCHECK((kArchVariant == kMips64r2) || (kArchVariant == kMips64r6)); 2183 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS); 2184 } 2185 2186 2187 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) { 2188 // Should be called via MacroAssembler::Ext. 2189 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb. 2190 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6); 2191 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT); 2192 } 2193 2194 2195 void Assembler::pref(int32_t hint, const MemOperand& rs) { 2196 DCHECK(is_uint5(hint) && is_uint16(rs.offset_)); 2197 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift) 2198 | (rs.offset_); 2199 emit(instr); 2200 } 2201 2202 2203 // --------Coprocessor-instructions---------------- 2204 2205 // Load, store, move. 2206 void Assembler::lwc1(FPURegister fd, const MemOperand& src) { 2207 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_); 2208 } 2209 2210 2211 void Assembler::ldc1(FPURegister fd, const MemOperand& src) { 2212 GenInstrImmediate(LDC1, src.rm(), fd, src.offset_); 2213 } 2214 2215 2216 void Assembler::swc1(FPURegister fd, const MemOperand& src) { 2217 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_); 2218 } 2219 2220 2221 void Assembler::sdc1(FPURegister fd, const MemOperand& src) { 2222 GenInstrImmediate(SDC1, src.rm(), fd, src.offset_); 2223 } 2224 2225 2226 void Assembler::mtc1(Register rt, FPURegister fs) { 2227 GenInstrRegister(COP1, MTC1, rt, fs, f0); 2228 } 2229 2230 2231 void Assembler::mthc1(Register rt, FPURegister fs) { 2232 GenInstrRegister(COP1, MTHC1, rt, fs, f0); 2233 } 2234 2235 2236 void Assembler::dmtc1(Register rt, FPURegister fs) { 2237 GenInstrRegister(COP1, DMTC1, rt, fs, f0); 2238 } 2239 2240 2241 void Assembler::mfc1(Register rt, FPURegister fs) { 2242 GenInstrRegister(COP1, MFC1, rt, fs, f0); 2243 } 2244 2245 2246 void Assembler::mfhc1(Register rt, FPURegister fs) { 2247 GenInstrRegister(COP1, MFHC1, rt, fs, f0); 2248 } 2249 2250 2251 void Assembler::dmfc1(Register rt, FPURegister fs) { 2252 GenInstrRegister(COP1, DMFC1, rt, fs, f0); 2253 } 2254 2255 2256 void Assembler::ctc1(Register rt, FPUControlRegister fs) { 2257 GenInstrRegister(COP1, CTC1, rt, fs); 2258 } 2259 2260 2261 void Assembler::cfc1(Register rt, FPUControlRegister fs) { 2262 GenInstrRegister(COP1, CFC1, rt, fs); 2263 } 2264 2265 2266 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) { 2267 uint64_t i; 2268 memcpy(&i, &d, 8); 2269 2270 *lo = i & 0xffffffff; 2271 *hi = i >> 32; 2272 } 2273 2274 2275 // Arithmetic. 2276 2277 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) { 2278 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D); 2279 } 2280 2281 2282 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) { 2283 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D); 2284 } 2285 2286 2287 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) { 2288 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D); 2289 } 2290 2291 2292 void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs, 2293 FPURegister ft) { 2294 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D); 2295 } 2296 2297 2298 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) { 2299 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D); 2300 } 2301 2302 2303 void Assembler::abs_d(FPURegister fd, FPURegister fs) { 2304 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D); 2305 } 2306 2307 2308 void Assembler::mov_d(FPURegister fd, FPURegister fs) { 2309 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D); 2310 } 2311 2312 2313 void Assembler::neg_d(FPURegister fd, FPURegister fs) { 2314 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D); 2315 } 2316 2317 2318 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) { 2319 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D); 2320 } 2321 2322 2323 // Conversions. 2324 2325 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) { 2326 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S); 2327 } 2328 2329 2330 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) { 2331 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D); 2332 } 2333 2334 2335 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) { 2336 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S); 2337 } 2338 2339 2340 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) { 2341 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D); 2342 } 2343 2344 2345 void Assembler::round_w_s(FPURegister fd, FPURegister fs) { 2346 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S); 2347 } 2348 2349 2350 void Assembler::round_w_d(FPURegister fd, FPURegister fs) { 2351 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D); 2352 } 2353 2354 2355 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) { 2356 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S); 2357 } 2358 2359 2360 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) { 2361 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D); 2362 } 2363 2364 2365 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) { 2366 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S); 2367 } 2368 2369 2370 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) { 2371 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D); 2372 } 2373 2374 2375 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) { 2376 DCHECK(kArchVariant == kMips64r2); 2377 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S); 2378 } 2379 2380 2381 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) { 2382 DCHECK(kArchVariant == kMips64r2); 2383 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D); 2384 } 2385 2386 2387 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) { 2388 DCHECK(kArchVariant == kMips64r2); 2389 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S); 2390 } 2391 2392 2393 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) { 2394 DCHECK(kArchVariant == kMips64r2); 2395 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D); 2396 } 2397 2398 2399 void Assembler::round_l_s(FPURegister fd, FPURegister fs) { 2400 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S); 2401 } 2402 2403 2404 void Assembler::round_l_d(FPURegister fd, FPURegister fs) { 2405 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D); 2406 } 2407 2408 2409 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) { 2410 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S); 2411 } 2412 2413 2414 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) { 2415 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D); 2416 } 2417 2418 2419 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) { 2420 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S); 2421 } 2422 2423 2424 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) { 2425 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D); 2426 } 2427 2428 2429 void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister ft, 2430 FPURegister fs) { 2431 DCHECK(kArchVariant == kMips64r6); 2432 DCHECK((fmt == D) || (fmt == S)); 2433 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN); 2434 } 2435 2436 2437 void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft, 2438 FPURegister fs) { 2439 DCHECK(kArchVariant == kMips64r6); 2440 DCHECK((fmt == D) || (fmt == S)); 2441 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA); 2442 } 2443 2444 2445 void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister ft, 2446 FPURegister fs) { 2447 DCHECK(kArchVariant == kMips64r6); 2448 DCHECK((fmt == D) || (fmt == S)); 2449 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX); 2450 } 2451 2452 2453 void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister ft, 2454 FPURegister fs) { 2455 DCHECK(kArchVariant == kMips64r6); 2456 DCHECK((fmt == D) || (fmt == S)); 2457 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA); 2458 } 2459 2460 2461 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) { 2462 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W); 2463 } 2464 2465 2466 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) { 2467 DCHECK(kArchVariant == kMips64r2); 2468 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L); 2469 } 2470 2471 2472 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) { 2473 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D); 2474 } 2475 2476 2477 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) { 2478 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W); 2479 } 2480 2481 2482 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) { 2483 DCHECK(kArchVariant == kMips64r2); 2484 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L); 2485 } 2486 2487 2488 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) { 2489 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S); 2490 } 2491 2492 2493 // Conditions for >= MIPSr6. 2494 void Assembler::cmp(FPUCondition cond, SecondaryField fmt, 2495 FPURegister fd, FPURegister fs, FPURegister ft) { 2496 DCHECK(kArchVariant == kMips64r6); 2497 DCHECK((fmt & ~(31 << kRsShift)) == 0); 2498 Instr instr = COP1 | fmt | ft.code() << kFtShift | 2499 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond; 2500 emit(instr); 2501 } 2502 2503 2504 void Assembler::bc1eqz(int16_t offset, FPURegister ft) { 2505 DCHECK(kArchVariant == kMips64r6); 2506 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask); 2507 emit(instr); 2508 } 2509 2510 2511 void Assembler::bc1nez(int16_t offset, FPURegister ft) { 2512 DCHECK(kArchVariant == kMips64r6); 2513 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask); 2514 emit(instr); 2515 } 2516 2517 2518 // Conditions for < MIPSr6. 2519 void Assembler::c(FPUCondition cond, SecondaryField fmt, 2520 FPURegister fs, FPURegister ft, uint16_t cc) { 2521 DCHECK(kArchVariant != kMips64r6); 2522 DCHECK(is_uint3(cc)); 2523 DCHECK((fmt & ~(31 << kRsShift)) == 0); 2524 Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift 2525 | cc << 8 | 3 << 4 | cond; 2526 emit(instr); 2527 } 2528 2529 2530 void Assembler::fcmp(FPURegister src1, const double src2, 2531 FPUCondition cond) { 2532 DCHECK(src2 == 0.0); 2533 mtc1(zero_reg, f14); 2534 cvt_d_w(f14, f14); 2535 c(cond, D, src1, f14, 0); 2536 } 2537 2538 2539 void Assembler::bc1f(int16_t offset, uint16_t cc) { 2540 DCHECK(is_uint3(cc)); 2541 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask); 2542 emit(instr); 2543 } 2544 2545 2546 void Assembler::bc1t(int16_t offset, uint16_t cc) { 2547 DCHECK(is_uint3(cc)); 2548 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask); 2549 emit(instr); 2550 } 2551 2552 2553 // Debugging. 2554 void Assembler::RecordJSReturn() { 2555 positions_recorder()->WriteRecordedPositions(); 2556 CheckBuffer(); 2557 RecordRelocInfo(RelocInfo::JS_RETURN); 2558 } 2559 2560 2561 void Assembler::RecordDebugBreakSlot() { 2562 positions_recorder()->WriteRecordedPositions(); 2563 CheckBuffer(); 2564 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); 2565 } 2566 2567 2568 void Assembler::RecordComment(const char* msg) { 2569 if (FLAG_code_comments) { 2570 CheckBuffer(); 2571 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); 2572 } 2573 } 2574 2575 2576 int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) { 2577 Instr instr = instr_at(pc); 2578 DCHECK(IsJ(instr) || IsLui(instr)); 2579 if (IsLui(instr)) { 2580 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize); 2581 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize); 2582 Instr instr_ori2 = instr_at(pc + 3 * Assembler::kInstrSize); 2583 DCHECK(IsOri(instr_ori)); 2584 DCHECK(IsOri(instr_ori2)); 2585 // TODO(plind): symbolic names for the shifts. 2586 int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 48; 2587 imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 32; 2588 imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask)) << 16; 2589 // Sign extend address. 2590 imm >>= 16; 2591 2592 if (imm == kEndOfJumpChain) { 2593 return 0; // Number of instructions patched. 2594 } 2595 imm += pc_delta; 2596 DCHECK((imm & 3) == 0); 2597 2598 instr_lui &= ~kImm16Mask; 2599 instr_ori &= ~kImm16Mask; 2600 instr_ori2 &= ~kImm16Mask; 2601 2602 instr_at_put(pc + 0 * Assembler::kInstrSize, 2603 instr_lui | ((imm >> 32) & kImm16Mask)); 2604 instr_at_put(pc + 1 * Assembler::kInstrSize, 2605 instr_ori | (imm >> 16 & kImm16Mask)); 2606 instr_at_put(pc + 3 * Assembler::kInstrSize, 2607 instr_ori2 | (imm & kImm16Mask)); 2608 return 4; // Number of instructions patched. 2609 } else { 2610 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; 2611 if (static_cast<int32_t>(imm28) == kEndOfJumpChain) { 2612 return 0; // Number of instructions patched. 2613 } 2614 2615 imm28 += pc_delta; 2616 imm28 &= kImm28Mask; 2617 DCHECK((imm28 & 3) == 0); 2618 2619 instr &= ~kImm26Mask; 2620 uint32_t imm26 = imm28 >> 2; 2621 DCHECK(is_uint26(imm26)); 2622 2623 instr_at_put(pc, instr | (imm26 & kImm26Mask)); 2624 return 1; // Number of instructions patched. 2625 } 2626 } 2627 2628 2629 void Assembler::GrowBuffer() { 2630 if (!own_buffer_) FATAL("external code buffer is too small"); 2631 2632 // Compute new buffer size. 2633 CodeDesc desc; // The new buffer. 2634 if (buffer_size_ < 1 * MB) { 2635 desc.buffer_size = 2*buffer_size_; 2636 } else { 2637 desc.buffer_size = buffer_size_ + 1*MB; 2638 } 2639 CHECK_GT(desc.buffer_size, 0); // No overflow. 2640 2641 // Set up new buffer. 2642 desc.buffer = NewArray<byte>(desc.buffer_size); 2643 2644 desc.instr_size = pc_offset(); 2645 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); 2646 2647 // Copy the data. 2648 intptr_t pc_delta = desc.buffer - buffer_; 2649 intptr_t rc_delta = (desc.buffer + desc.buffer_size) - 2650 (buffer_ + buffer_size_); 2651 MemMove(desc.buffer, buffer_, desc.instr_size); 2652 MemMove(reloc_info_writer.pos() + rc_delta, 2653 reloc_info_writer.pos(), desc.reloc_size); 2654 2655 // Switch buffers. 2656 DeleteArray(buffer_); 2657 buffer_ = desc.buffer; 2658 buffer_size_ = desc.buffer_size; 2659 pc_ += pc_delta; 2660 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 2661 reloc_info_writer.last_pc() + pc_delta); 2662 2663 // Relocate runtime entries. 2664 for (RelocIterator it(desc); !it.done(); it.next()) { 2665 RelocInfo::Mode rmode = it.rinfo()->rmode(); 2666 if (rmode == RelocInfo::INTERNAL_REFERENCE) { 2667 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc()); 2668 RelocateInternalReference(p, pc_delta); 2669 } 2670 } 2671 2672 DCHECK(!overflow()); 2673 } 2674 2675 2676 void Assembler::db(uint8_t data) { 2677 CheckBuffer(); 2678 *reinterpret_cast<uint8_t*>(pc_) = data; 2679 pc_ += sizeof(uint8_t); 2680 } 2681 2682 2683 void Assembler::dd(uint32_t data) { 2684 CheckBuffer(); 2685 *reinterpret_cast<uint32_t*>(pc_) = data; 2686 pc_ += sizeof(uint32_t); 2687 } 2688 2689 2690 void Assembler::emit_code_stub_address(Code* stub) { 2691 CheckBuffer(); 2692 *reinterpret_cast<uint64_t*>(pc_) = 2693 reinterpret_cast<uint64_t>(stub->instruction_start()); 2694 pc_ += sizeof(uint64_t); 2695 } 2696 2697 2698 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 2699 // We do not try to reuse pool constants. 2700 RelocInfo rinfo(pc_, rmode, data, NULL); 2701 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { 2702 // Adjust code for new modes. 2703 DCHECK(RelocInfo::IsDebugBreakSlot(rmode) 2704 || RelocInfo::IsJSReturn(rmode) 2705 || RelocInfo::IsComment(rmode) 2706 || RelocInfo::IsPosition(rmode)); 2707 // These modes do not need an entry in the constant pool. 2708 } 2709 if (!RelocInfo::IsNone(rinfo.rmode())) { 2710 // Don't record external references unless the heap will be serialized. 2711 if (rmode == RelocInfo::EXTERNAL_REFERENCE && 2712 !serializer_enabled() && !emit_debug_code()) { 2713 return; 2714 } 2715 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here. 2716 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { 2717 RelocInfo reloc_info_with_ast_id(pc_, 2718 rmode, 2719 RecordedAstId().ToInt(), 2720 NULL); 2721 ClearRecordedAstId(); 2722 reloc_info_writer.Write(&reloc_info_with_ast_id); 2723 } else { 2724 reloc_info_writer.Write(&rinfo); 2725 } 2726 } 2727 } 2728 2729 2730 void Assembler::BlockTrampolinePoolFor(int instructions) { 2731 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); 2732 } 2733 2734 2735 void Assembler::CheckTrampolinePool() { 2736 // Some small sequences of instructions must not be broken up by the 2737 // insertion of a trampoline pool; such sequences are protected by setting 2738 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, 2739 // which are both checked here. Also, recursive calls to CheckTrampolinePool 2740 // are blocked by trampoline_pool_blocked_nesting_. 2741 if ((trampoline_pool_blocked_nesting_ > 0) || 2742 (pc_offset() < no_trampoline_pool_before_)) { 2743 // Emission is currently blocked; make sure we try again as soon as 2744 // possible. 2745 if (trampoline_pool_blocked_nesting_ > 0) { 2746 next_buffer_check_ = pc_offset() + kInstrSize; 2747 } else { 2748 next_buffer_check_ = no_trampoline_pool_before_; 2749 } 2750 return; 2751 } 2752 2753 DCHECK(!trampoline_emitted_); 2754 DCHECK(unbound_labels_count_ >= 0); 2755 if (unbound_labels_count_ > 0) { 2756 // First we emit jump (2 instructions), then we emit trampoline pool. 2757 { BlockTrampolinePoolScope block_trampoline_pool(this); 2758 Label after_pool; 2759 b(&after_pool); 2760 nop(); 2761 2762 int pool_start = pc_offset(); 2763 for (int i = 0; i < unbound_labels_count_; i++) { 2764 uint64_t imm64; 2765 imm64 = jump_address(&after_pool); 2766 { BlockGrowBufferScope block_buf_growth(this); 2767 // Buffer growth (and relocation) must be blocked for internal 2768 // references until associated instructions are emitted and available 2769 // to be patched. 2770 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); 2771 // TODO(plind): Verify this, presume I cannot use macro-assembler 2772 // here. 2773 lui(at, (imm64 >> 32) & kImm16Mask); 2774 ori(at, at, (imm64 >> 16) & kImm16Mask); 2775 dsll(at, at, 16); 2776 ori(at, at, imm64 & kImm16Mask); 2777 } 2778 jr(at); 2779 nop(); 2780 } 2781 bind(&after_pool); 2782 trampoline_ = Trampoline(pool_start, unbound_labels_count_); 2783 2784 trampoline_emitted_ = true; 2785 // As we are only going to emit trampoline once, we need to prevent any 2786 // further emission. 2787 next_buffer_check_ = kMaxInt; 2788 } 2789 } else { 2790 // Number of branches to unbound label at this point is zero, so we can 2791 // move next buffer check to maximum. 2792 next_buffer_check_ = pc_offset() + 2793 kMaxBranchOffset - kTrampolineSlotsSize * 16; 2794 } 2795 return; 2796 } 2797 2798 2799 Address Assembler::target_address_at(Address pc) { 2800 Instr instr0 = instr_at(pc); 2801 Instr instr1 = instr_at(pc + 1 * kInstrSize); 2802 Instr instr3 = instr_at(pc + 3 * kInstrSize); 2803 2804 // Interpret 4 instructions for address generated by li: See listing in 2805 // Assembler::set_target_address_at() just below. 2806 if ((GetOpcodeField(instr0) == LUI) && (GetOpcodeField(instr1) == ORI) && 2807 (GetOpcodeField(instr3) == ORI)) { 2808 // Assemble the 48 bit value. 2809 int64_t addr = static_cast<int64_t>( 2810 ((uint64_t)(GetImmediate16(instr0)) << 32) | 2811 ((uint64_t)(GetImmediate16(instr1)) << 16) | 2812 ((uint64_t)(GetImmediate16(instr3)))); 2813 2814 // Sign extend to get canonical address. 2815 addr = (addr << 16) >> 16; 2816 return reinterpret_cast<Address>(addr); 2817 } 2818 // We should never get here, force a bad address if we do. 2819 UNREACHABLE(); 2820 return (Address)0x0; 2821 } 2822 2823 2824 // MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32 2825 // qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap 2826 // snapshot generated on ia32, the resulting MIPS sNaN must be quieted. 2827 // OS::nan_value() returns a qNaN. 2828 void Assembler::QuietNaN(HeapObject* object) { 2829 HeapNumber::cast(object)->set_value(base::OS::nan_value()); 2830 } 2831 2832 2833 // On Mips64, a target address is stored in a 4-instruction sequence: 2834 // 0: lui(rd, (j.imm64_ >> 32) & kImm16Mask); 2835 // 1: ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask); 2836 // 2: dsll(rd, rd, 16); 2837 // 3: ori(rd, rd, j.imm32_ & kImm16Mask); 2838 // 2839 // Patching the address must replace all the lui & ori instructions, 2840 // and flush the i-cache. 2841 // 2842 // There is an optimization below, which emits a nop when the address 2843 // fits in just 16 bits. This is unlikely to help, and should be benchmarked, 2844 // and possibly removed. 2845 void Assembler::set_target_address_at(Address pc, 2846 Address target, 2847 ICacheFlushMode icache_flush_mode) { 2848 // There is an optimization where only 4 instructions are used to load address 2849 // in code on MIP64 because only 48-bits of address is effectively used. 2850 // It relies on fact the upper [63:48] bits are not used for virtual address 2851 // translation and they have to be set according to value of bit 47 in order 2852 // get canonical address. 2853 Instr instr1 = instr_at(pc + kInstrSize); 2854 uint32_t rt_code = GetRt(instr1); 2855 uint32_t* p = reinterpret_cast<uint32_t*>(pc); 2856 uint64_t itarget = reinterpret_cast<uint64_t>(target); 2857 2858 #ifdef DEBUG 2859 // Check we have the result from a li macro-instruction. 2860 Instr instr0 = instr_at(pc); 2861 Instr instr3 = instr_at(pc + kInstrSize * 3); 2862 CHECK((GetOpcodeField(instr0) == LUI && GetOpcodeField(instr1) == ORI && 2863 GetOpcodeField(instr3) == ORI)); 2864 #endif 2865 2866 // Must use 4 instructions to insure patchable code. 2867 // lui rt, upper-16. 2868 // ori rt, rt, lower-16. 2869 // dsll rt, rt, 16. 2870 // ori rt rt, lower-16. 2871 *p = LUI | (rt_code << kRtShift) | ((itarget >> 32) & kImm16Mask); 2872 *(p + 1) = ORI | (rt_code << kRtShift) | (rt_code << kRsShift) 2873 | ((itarget >> 16) & kImm16Mask); 2874 *(p + 3) = ORI | (rt_code << kRsShift) | (rt_code << kRtShift) 2875 | (itarget & kImm16Mask); 2876 2877 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 2878 CpuFeatures::FlushICache(pc, 4 * Assembler::kInstrSize); 2879 } 2880 } 2881 2882 2883 void Assembler::JumpLabelToJumpRegister(Address pc) { 2884 // Address pc points to lui/ori instructions. 2885 // Jump to label may follow at pc + 2 * kInstrSize. 2886 uint32_t* p = reinterpret_cast<uint32_t*>(pc); 2887 #ifdef DEBUG 2888 Instr instr1 = instr_at(pc); 2889 #endif 2890 Instr instr2 = instr_at(pc + 1 * kInstrSize); 2891 Instr instr3 = instr_at(pc + 6 * kInstrSize); 2892 bool patched = false; 2893 2894 if (IsJal(instr3)) { 2895 DCHECK(GetOpcodeField(instr1) == LUI); 2896 DCHECK(GetOpcodeField(instr2) == ORI); 2897 2898 uint32_t rs_field = GetRt(instr2) << kRsShift; 2899 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg. 2900 *(p+6) = SPECIAL | rs_field | rd_field | JALR; 2901 patched = true; 2902 } else if (IsJ(instr3)) { 2903 DCHECK(GetOpcodeField(instr1) == LUI); 2904 DCHECK(GetOpcodeField(instr2) == ORI); 2905 2906 uint32_t rs_field = GetRt(instr2) << kRsShift; 2907 *(p+6) = SPECIAL | rs_field | JR; 2908 patched = true; 2909 } 2910 2911 if (patched) { 2912 CpuFeatures::FlushICache(pc+6, sizeof(int32_t)); 2913 } 2914 } 2915 2916 2917 Handle<ConstantPoolArray> Assembler::NewConstantPool(Isolate* isolate) { 2918 // No out-of-line constant pool support. 2919 DCHECK(!FLAG_enable_ool_constant_pool); 2920 return isolate->factory()->empty_constant_pool_array(); 2921 } 2922 2923 2924 void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) { 2925 // No out-of-line constant pool support. 2926 DCHECK(!FLAG_enable_ool_constant_pool); 2927 return; 2928 } 2929 2930 2931 } } // namespace v8::internal 2932 2933 #endif // V8_TARGET_ARCH_MIPS64 2934