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