1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "assembler_mips.h" 18 19 #include "base/bit_utils.h" 20 #include "base/casts.h" 21 #include "entrypoints/quick/quick_entrypoints.h" 22 #include "entrypoints/quick/quick_entrypoints_enum.h" 23 #include "memory_region.h" 24 #include "thread.h" 25 26 namespace art { 27 namespace mips { 28 29 static_assert(static_cast<size_t>(kMipsPointerSize) == kMipsWordSize, 30 "Unexpected Mips pointer size."); 31 static_assert(kMipsPointerSize == PointerSize::k32, "Unexpected Mips pointer size."); 32 33 34 std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { 35 if (rhs >= D0 && rhs < kNumberOfDRegisters) { 36 os << "d" << static_cast<int>(rhs); 37 } else { 38 os << "DRegister[" << static_cast<int>(rhs) << "]"; 39 } 40 return os; 41 } 42 43 MipsAssembler::DelaySlot::DelaySlot() 44 : instruction_(0), 45 gpr_outs_mask_(0), 46 gpr_ins_mask_(0), 47 fpr_outs_mask_(0), 48 fpr_ins_mask_(0), 49 cc_outs_mask_(0), 50 cc_ins_mask_(0) {} 51 52 void MipsAssembler::DsFsmInstr(uint32_t instruction, 53 uint32_t gpr_outs_mask, 54 uint32_t gpr_ins_mask, 55 uint32_t fpr_outs_mask, 56 uint32_t fpr_ins_mask, 57 uint32_t cc_outs_mask, 58 uint32_t cc_ins_mask) { 59 if (!reordering_) { 60 CHECK_EQ(ds_fsm_state_, kExpectingLabel); 61 CHECK_EQ(delay_slot_.instruction_, 0u); 62 return; 63 } 64 switch (ds_fsm_state_) { 65 case kExpectingLabel: 66 break; 67 case kExpectingInstruction: 68 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); 69 // If the last instruction is not suitable for delay slots, drop 70 // the PC of the label preceding it so that no unconditional branch 71 // uses this instruction to fill its delay slot. 72 if (instruction == 0) { 73 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel. 74 } else { 75 // Otherwise wait for another instruction or label before we can 76 // commit the label PC. The label PC will be dropped if instead 77 // of another instruction or label there's a call from the code 78 // generator to CodePosition() to record the buffer size. 79 // Instructions after which the buffer size is recorded cannot 80 // be moved into delay slots or anywhere else because they may 81 // trigger signals and the signal handlers expect these signals 82 // to be coming from the instructions immediately preceding the 83 // recorded buffer locations. 84 ds_fsm_state_ = kExpectingCommit; 85 } 86 break; 87 case kExpectingCommit: 88 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size()); 89 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel. 90 break; 91 } 92 delay_slot_.instruction_ = instruction; 93 delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u; // Ignore register ZERO. 94 delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u; // Ignore register ZERO. 95 delay_slot_.fpr_outs_mask_ = fpr_outs_mask; 96 delay_slot_.fpr_ins_mask_ = fpr_ins_mask; 97 delay_slot_.cc_outs_mask_ = cc_outs_mask; 98 delay_slot_.cc_ins_mask_ = cc_ins_mask; 99 } 100 101 void MipsAssembler::DsFsmLabel() { 102 if (!reordering_) { 103 CHECK_EQ(ds_fsm_state_, kExpectingLabel); 104 CHECK_EQ(delay_slot_.instruction_, 0u); 105 return; 106 } 107 switch (ds_fsm_state_) { 108 case kExpectingLabel: 109 ds_fsm_target_pc_ = buffer_.Size(); 110 ds_fsm_state_ = kExpectingInstruction; 111 break; 112 case kExpectingInstruction: 113 // Allow consecutive labels. 114 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size()); 115 break; 116 case kExpectingCommit: 117 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); 118 DsFsmCommitLabel(); 119 ds_fsm_target_pc_ = buffer_.Size(); 120 ds_fsm_state_ = kExpectingInstruction; 121 break; 122 } 123 // We cannot move instructions into delay slots across labels. 124 delay_slot_.instruction_ = 0; 125 } 126 127 void MipsAssembler::DsFsmCommitLabel() { 128 if (ds_fsm_state_ == kExpectingCommit) { 129 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_); 130 } 131 ds_fsm_state_ = kExpectingLabel; 132 } 133 134 void MipsAssembler::DsFsmDropLabel() { 135 ds_fsm_state_ = kExpectingLabel; 136 } 137 138 bool MipsAssembler::SetReorder(bool enable) { 139 bool last_state = reordering_; 140 if (last_state != enable) { 141 DsFsmCommitLabel(); 142 DsFsmInstrNop(0); 143 } 144 reordering_ = enable; 145 return last_state; 146 } 147 148 size_t MipsAssembler::CodePosition() { 149 // The last instruction cannot be used in a delay slot, do not commit 150 // the label before it (if any) and clear the delay slot. 151 DsFsmDropLabel(); 152 DsFsmInstrNop(0); 153 size_t size = buffer_.Size(); 154 // In theory we can get the following sequence: 155 // label1: 156 // instr 157 // label2: # label1 gets committed when label2 is seen 158 // CodePosition() call 159 // and we need to uncommit label1. 160 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) { 161 ds_fsm_target_pcs_.pop_back(); 162 } 163 return size; 164 } 165 166 void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) { 167 DsFsmInstr(0, 0, 0, 0, 0, 0, 0); 168 } 169 170 void MipsAssembler::DsFsmInstrRrr(uint32_t instruction, Register out, Register in1, Register in2) { 171 DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0); 172 } 173 174 void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction, 175 Register in1_out, 176 Register in2, 177 Register in3) { 178 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0); 179 } 180 181 void MipsAssembler::DsFsmInstrFff(uint32_t instruction, 182 FRegister out, 183 FRegister in1, 184 FRegister in2) { 185 DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0); 186 } 187 188 void MipsAssembler::DsFsmInstrFfff(uint32_t instruction, 189 FRegister in1_out, 190 FRegister in2, 191 FRegister in3) { 192 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0); 193 } 194 195 void MipsAssembler::DsFsmInstrFffr(uint32_t instruction, 196 FRegister in1_out, 197 FRegister in2, 198 Register in3) { 199 DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0); 200 } 201 202 void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) { 203 DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0); 204 } 205 206 void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) { 207 DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0); 208 } 209 210 void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) { 211 DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0); 212 } 213 214 void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) { 215 DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0); 216 } 217 218 void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction, 219 Register in1_out, 220 Register in2, 221 int cc_in) { 222 DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in)); 223 } 224 225 void MipsAssembler::DsFsmInstrFffc(uint32_t instruction, 226 FRegister in1_out, 227 FRegister in2, 228 int cc_in) { 229 DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in)); 230 } 231 232 void MipsAssembler::FinalizeCode() { 233 for (auto& exception_block : exception_blocks_) { 234 EmitExceptionPoll(&exception_block); 235 } 236 // Commit the last branch target label (if any) and disable instruction reordering. 237 DsFsmCommitLabel(); 238 SetReorder(false); 239 EmitLiterals(); 240 ReserveJumpTableSpace(); 241 PromoteBranches(); 242 } 243 244 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) { 245 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs(); 246 EmitBranches(); 247 EmitJumpTables(); 248 Assembler::FinalizeInstructions(region); 249 PatchCFI(number_of_delayed_adjust_pcs); 250 } 251 252 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) { 253 if (cfi().NumberOfDelayedAdvancePCs() == 0u) { 254 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u); 255 return; 256 } 257 258 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; 259 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); 260 const std::vector<uint8_t>& old_stream = data.first; 261 const std::vector<DelayedAdvancePC>& advances = data.second; 262 263 // PCs recorded before EmitBranches() need to be adjusted. 264 // PCs recorded during EmitBranches() are already adjusted. 265 // Both ranges are separately sorted but they may overlap. 266 if (kIsDebugBuild) { 267 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) { 268 return lhs.pc < rhs.pc; 269 }; 270 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp)); 271 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp)); 272 } 273 274 // Append initial CFI data if any. 275 size_t size = advances.size(); 276 DCHECK_NE(size, 0u); 277 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos); 278 // Emit PC adjustments interleaved with the old CFI stream. 279 size_t adjust_pos = 0u; 280 size_t late_emit_pos = number_of_delayed_adjust_pcs; 281 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) { 282 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs) 283 ? GetAdjustedPosition(advances[adjust_pos].pc) 284 : static_cast<size_t>(-1); 285 size_t late_emit_pc = (late_emit_pos != size) 286 ? advances[late_emit_pos].pc 287 : static_cast<size_t>(-1); 288 size_t advance_pc = std::min(adjusted_pc, late_emit_pc); 289 DCHECK_NE(advance_pc, static_cast<size_t>(-1)); 290 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos; 291 if (adjusted_pc <= late_emit_pc) { 292 ++adjust_pos; 293 } else { 294 ++late_emit_pos; 295 } 296 cfi().AdvancePC(advance_pc); 297 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos; 298 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos); 299 } 300 } 301 302 void MipsAssembler::EmitBranches() { 303 CHECK(!overwriting_); 304 CHECK(!reordering_); 305 // Now that everything has its final position in the buffer (the branches have 306 // been promoted), adjust the target label PCs. 307 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) { 308 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]); 309 } 310 // Switch from appending instructions at the end of the buffer to overwriting 311 // existing instructions (branch placeholders) in the buffer. 312 overwriting_ = true; 313 for (auto& branch : branches_) { 314 EmitBranch(&branch); 315 } 316 overwriting_ = false; 317 } 318 319 void MipsAssembler::Emit(uint32_t value) { 320 if (overwriting_) { 321 // Branches to labels are emitted into their placeholders here. 322 buffer_.Store<uint32_t>(overwrite_location_, value); 323 overwrite_location_ += sizeof(uint32_t); 324 } else { 325 // Other instructions are simply appended at the end here. 326 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 327 buffer_.Emit<uint32_t>(value); 328 } 329 } 330 331 uint32_t MipsAssembler::EmitR(int opcode, 332 Register rs, 333 Register rt, 334 Register rd, 335 int shamt, 336 int funct) { 337 CHECK_NE(rs, kNoRegister); 338 CHECK_NE(rt, kNoRegister); 339 CHECK_NE(rd, kNoRegister); 340 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 341 static_cast<uint32_t>(rs) << kRsShift | 342 static_cast<uint32_t>(rt) << kRtShift | 343 static_cast<uint32_t>(rd) << kRdShift | 344 shamt << kShamtShift | 345 funct; 346 Emit(encoding); 347 return encoding; 348 } 349 350 uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) { 351 CHECK_NE(rs, kNoRegister); 352 CHECK_NE(rt, kNoRegister); 353 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 354 static_cast<uint32_t>(rs) << kRsShift | 355 static_cast<uint32_t>(rt) << kRtShift | 356 imm; 357 Emit(encoding); 358 return encoding; 359 } 360 361 uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) { 362 CHECK_NE(rs, kNoRegister); 363 CHECK(IsUint<21>(imm21)) << imm21; 364 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 365 static_cast<uint32_t>(rs) << kRsShift | 366 imm21; 367 Emit(encoding); 368 return encoding; 369 } 370 371 uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) { 372 CHECK(IsUint<26>(imm26)) << imm26; 373 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; 374 Emit(encoding); 375 return encoding; 376 } 377 378 uint32_t MipsAssembler::EmitFR(int opcode, 379 int fmt, 380 FRegister ft, 381 FRegister fs, 382 FRegister fd, 383 int funct) { 384 CHECK_NE(ft, kNoFRegister); 385 CHECK_NE(fs, kNoFRegister); 386 CHECK_NE(fd, kNoFRegister); 387 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 388 fmt << kFmtShift | 389 static_cast<uint32_t>(ft) << kFtShift | 390 static_cast<uint32_t>(fs) << kFsShift | 391 static_cast<uint32_t>(fd) << kFdShift | 392 funct; 393 Emit(encoding); 394 return encoding; 395 } 396 397 uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) { 398 CHECK_NE(ft, kNoFRegister); 399 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 400 fmt << kFmtShift | 401 static_cast<uint32_t>(ft) << kFtShift | 402 imm; 403 Emit(encoding); 404 return encoding; 405 } 406 407 void MipsAssembler::Addu(Register rd, Register rs, Register rt) { 408 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt); 409 } 410 411 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { 412 DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs); 413 } 414 415 void MipsAssembler::Subu(Register rd, Register rs, Register rt) { 416 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt); 417 } 418 419 void MipsAssembler::MultR2(Register rs, Register rt) { 420 CHECK(!IsR6()); 421 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt); 422 } 423 424 void MipsAssembler::MultuR2(Register rs, Register rt) { 425 CHECK(!IsR6()); 426 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt); 427 } 428 429 void MipsAssembler::DivR2(Register rs, Register rt) { 430 CHECK(!IsR6()); 431 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt); 432 } 433 434 void MipsAssembler::DivuR2(Register rs, Register rt) { 435 CHECK(!IsR6()); 436 DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt); 437 } 438 439 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) { 440 CHECK(!IsR6()); 441 DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt); 442 } 443 444 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) { 445 CHECK(!IsR6()); 446 DivR2(rs, rt); 447 Mflo(rd); 448 } 449 450 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) { 451 CHECK(!IsR6()); 452 DivR2(rs, rt); 453 Mfhi(rd); 454 } 455 456 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) { 457 CHECK(!IsR6()); 458 DivuR2(rs, rt); 459 Mflo(rd); 460 } 461 462 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) { 463 CHECK(!IsR6()); 464 DivuR2(rs, rt); 465 Mfhi(rd); 466 } 467 468 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) { 469 CHECK(IsR6()); 470 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt); 471 } 472 473 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) { 474 CHECK(IsR6()); 475 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt); 476 } 477 478 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) { 479 CHECK(IsR6()); 480 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt); 481 } 482 483 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) { 484 CHECK(IsR6()); 485 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt); 486 } 487 488 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) { 489 CHECK(IsR6()); 490 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt); 491 } 492 493 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) { 494 CHECK(IsR6()); 495 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt); 496 } 497 498 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) { 499 CHECK(IsR6()); 500 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt); 501 } 502 503 void MipsAssembler::And(Register rd, Register rs, Register rt) { 504 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt); 505 } 506 507 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { 508 DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs); 509 } 510 511 void MipsAssembler::Or(Register rd, Register rs, Register rt) { 512 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt); 513 } 514 515 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { 516 DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs); 517 } 518 519 void MipsAssembler::Xor(Register rd, Register rs, Register rt) { 520 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt); 521 } 522 523 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { 524 DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs); 525 } 526 527 void MipsAssembler::Nor(Register rd, Register rs, Register rt) { 528 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt); 529 } 530 531 void MipsAssembler::Movz(Register rd, Register rs, Register rt) { 532 CHECK(!IsR6()); 533 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt); 534 } 535 536 void MipsAssembler::Movn(Register rd, Register rs, Register rt) { 537 CHECK(!IsR6()); 538 DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt); 539 } 540 541 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { 542 CHECK(IsR6()); 543 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt); 544 } 545 546 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { 547 CHECK(IsR6()); 548 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt); 549 } 550 551 void MipsAssembler::ClzR6(Register rd, Register rs) { 552 CHECK(IsR6()); 553 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs); 554 } 555 556 void MipsAssembler::ClzR2(Register rd, Register rs) { 557 CHECK(!IsR6()); 558 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs); 559 } 560 561 void MipsAssembler::CloR6(Register rd, Register rs) { 562 CHECK(IsR6()); 563 DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs); 564 } 565 566 void MipsAssembler::CloR2(Register rd, Register rs) { 567 CHECK(!IsR6()); 568 DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs); 569 } 570 571 void MipsAssembler::Seb(Register rd, Register rt) { 572 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt); 573 } 574 575 void MipsAssembler::Seh(Register rd, Register rt) { 576 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt); 577 } 578 579 void MipsAssembler::Wsbh(Register rd, Register rt) { 580 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt); 581 } 582 583 void MipsAssembler::Bitswap(Register rd, Register rt) { 584 CHECK(IsR6()); 585 DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt); 586 } 587 588 void MipsAssembler::Sll(Register rd, Register rt, int shamt) { 589 CHECK(IsUint<5>(shamt)) << shamt; 590 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt); 591 } 592 593 void MipsAssembler::Srl(Register rd, Register rt, int shamt) { 594 CHECK(IsUint<5>(shamt)) << shamt; 595 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt); 596 } 597 598 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) { 599 CHECK(IsUint<5>(shamt)) << shamt; 600 DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt); 601 } 602 603 void MipsAssembler::Sra(Register rd, Register rt, int shamt) { 604 CHECK(IsUint<5>(shamt)) << shamt; 605 DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt); 606 } 607 608 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) { 609 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt); 610 } 611 612 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { 613 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt); 614 } 615 616 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { 617 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt); 618 } 619 620 void MipsAssembler::Srav(Register rd, Register rt, Register rs) { 621 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt); 622 } 623 624 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) { 625 CHECK(IsUint<5>(pos)) << pos; 626 CHECK(0 < size && size <= 32) << size; 627 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 628 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt); 629 } 630 631 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) { 632 CHECK(IsUint<5>(pos)) << pos; 633 CHECK(0 < size && size <= 32) << size; 634 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 635 DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt); 636 } 637 638 // TODO: This instruction is available in both R6 and MSA and it should be used when available. 639 void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) { 640 CHECK(IsR6()); 641 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; 642 int sa = saPlusOne - 1; 643 DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt); 644 } 645 646 void MipsAssembler::ShiftAndAdd(Register dst, 647 Register src_idx, 648 Register src_base, 649 int shamt, 650 Register tmp) { 651 CHECK(0 <= shamt && shamt <= 4) << shamt; 652 CHECK_NE(src_base, tmp); 653 if (shamt == TIMES_1) { 654 // Catch the special case where the shift amount is zero (0). 655 Addu(dst, src_base, src_idx); 656 } else if (IsR6()) { 657 Lsa(dst, src_idx, src_base, shamt); 658 } else { 659 Sll(tmp, src_idx, shamt); 660 Addu(dst, src_base, tmp); 661 } 662 } 663 664 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { 665 DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs); 666 } 667 668 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { 669 DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs); 670 } 671 672 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { 673 DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs); 674 } 675 676 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) { 677 CHECK(!IsR6()); 678 DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs); 679 } 680 681 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) { 682 CHECK(!IsR6()); 683 DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs); 684 } 685 686 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { 687 DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs); 688 } 689 690 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { 691 DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs); 692 } 693 694 void MipsAssembler::Lwpc(Register rs, uint32_t imm19) { 695 CHECK(IsR6()); 696 CHECK(IsUint<19>(imm19)) << imm19; 697 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19)); 698 } 699 700 void MipsAssembler::Lui(Register rt, uint16_t imm16) { 701 DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO); 702 } 703 704 void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) { 705 CHECK(IsR6()); 706 DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs); 707 } 708 709 void MipsAssembler::Sync(uint32_t stype) { 710 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf)); 711 } 712 713 void MipsAssembler::Mfhi(Register rd) { 714 CHECK(!IsR6()); 715 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO); 716 } 717 718 void MipsAssembler::Mflo(Register rd) { 719 CHECK(!IsR6()); 720 DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO); 721 } 722 723 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { 724 DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs); 725 } 726 727 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { 728 DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs); 729 } 730 731 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { 732 DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs); 733 } 734 735 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) { 736 CHECK(!IsR6()); 737 DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs); 738 } 739 740 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { 741 CHECK(!IsR6()); 742 DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs); 743 } 744 745 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) { 746 CHECK(!IsR6()); 747 DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base); 748 } 749 750 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) { 751 CHECK(!IsR6()); 752 DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base); 753 } 754 755 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) { 756 CHECK(IsR6()); 757 CHECK(IsInt<9>(imm9)); 758 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base); 759 } 760 761 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) { 762 CHECK(IsR6()); 763 CHECK(IsInt<9>(imm9)); 764 DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base); 765 } 766 767 void MipsAssembler::Slt(Register rd, Register rs, Register rt) { 768 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt); 769 } 770 771 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 772 DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt); 773 } 774 775 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 776 DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs); 777 } 778 779 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 780 DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs); 781 } 782 783 void MipsAssembler::B(uint16_t imm16) { 784 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16)); 785 } 786 787 void MipsAssembler::Bal(uint16_t imm16) { 788 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16)); 789 } 790 791 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { 792 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16)); 793 } 794 795 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { 796 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16)); 797 } 798 799 void MipsAssembler::Beqz(Register rt, uint16_t imm16) { 800 Beq(ZERO, rt, imm16); 801 } 802 803 void MipsAssembler::Bnez(Register rt, uint16_t imm16) { 804 Bne(ZERO, rt, imm16); 805 } 806 807 void MipsAssembler::Bltz(Register rt, uint16_t imm16) { 808 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16)); 809 } 810 811 void MipsAssembler::Bgez(Register rt, uint16_t imm16) { 812 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16)); 813 } 814 815 void MipsAssembler::Blez(Register rt, uint16_t imm16) { 816 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16)); 817 } 818 819 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { 820 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16)); 821 } 822 823 void MipsAssembler::Bc1f(uint16_t imm16) { 824 Bc1f(0, imm16); 825 } 826 827 void MipsAssembler::Bc1f(int cc, uint16_t imm16) { 828 CHECK(!IsR6()); 829 CHECK(IsUint<3>(cc)) << cc; 830 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16)); 831 } 832 833 void MipsAssembler::Bc1t(uint16_t imm16) { 834 Bc1t(0, imm16); 835 } 836 837 void MipsAssembler::Bc1t(int cc, uint16_t imm16) { 838 CHECK(!IsR6()); 839 CHECK(IsUint<3>(cc)) << cc; 840 DsFsmInstrNop(EmitI(0x11, 841 static_cast<Register>(0x8), 842 static_cast<Register>((cc << 2) | 1), 843 imm16)); 844 } 845 846 void MipsAssembler::J(uint32_t addr26) { 847 DsFsmInstrNop(EmitI26(0x2, addr26)); 848 } 849 850 void MipsAssembler::Jal(uint32_t addr26) { 851 DsFsmInstrNop(EmitI26(0x3, addr26)); 852 } 853 854 void MipsAssembler::Jalr(Register rd, Register rs) { 855 uint32_t last_instruction = delay_slot_.instruction_; 856 bool exchange = (last_instruction != 0 && 857 (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 && 858 ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0); 859 if (exchange) { 860 // The last instruction cannot be used in a different delay slot, 861 // do not commit the label before it (if any). 862 DsFsmDropLabel(); 863 } 864 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09)); 865 if (exchange) { 866 // Exchange the last two instructions in the assembler buffer. 867 size_t size = buffer_.Size(); 868 CHECK_GE(size, 2 * sizeof(uint32_t)); 869 size_t pos1 = size - 2 * sizeof(uint32_t); 870 size_t pos2 = size - sizeof(uint32_t); 871 uint32_t instr1 = buffer_.Load<uint32_t>(pos1); 872 uint32_t instr2 = buffer_.Load<uint32_t>(pos2); 873 CHECK_EQ(instr1, last_instruction); 874 buffer_.Store<uint32_t>(pos1, instr2); 875 buffer_.Store<uint32_t>(pos2, instr1); 876 } else if (reordering_) { 877 Nop(); 878 } 879 } 880 881 void MipsAssembler::Jalr(Register rs) { 882 Jalr(RA, rs); 883 } 884 885 void MipsAssembler::Jr(Register rs) { 886 Jalr(ZERO, rs); 887 } 888 889 void MipsAssembler::Nal() { 890 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0)); 891 } 892 893 void MipsAssembler::Auipc(Register rs, uint16_t imm16) { 894 CHECK(IsR6()); 895 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16)); 896 } 897 898 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { 899 CHECK(IsR6()); 900 CHECK(IsUint<19>(imm19)) << imm19; 901 DsFsmInstrNop(EmitI21(0x3B, rs, imm19)); 902 } 903 904 void MipsAssembler::Bc(uint32_t imm26) { 905 CHECK(IsR6()); 906 DsFsmInstrNop(EmitI26(0x32, imm26)); 907 } 908 909 void MipsAssembler::Balc(uint32_t imm26) { 910 CHECK(IsR6()); 911 DsFsmInstrNop(EmitI26(0x3A, imm26)); 912 } 913 914 void MipsAssembler::Jic(Register rt, uint16_t imm16) { 915 CHECK(IsR6()); 916 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16)); 917 } 918 919 void MipsAssembler::Jialc(Register rt, uint16_t imm16) { 920 CHECK(IsR6()); 921 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16)); 922 } 923 924 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) { 925 CHECK(IsR6()); 926 CHECK_NE(rs, ZERO); 927 CHECK_NE(rt, ZERO); 928 CHECK_NE(rs, rt); 929 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16)); 930 } 931 932 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { 933 CHECK(IsR6()); 934 CHECK_NE(rt, ZERO); 935 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16)); 936 } 937 938 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) { 939 CHECK(IsR6()); 940 CHECK_NE(rt, ZERO); 941 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16)); 942 } 943 944 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) { 945 CHECK(IsR6()); 946 CHECK_NE(rs, ZERO); 947 CHECK_NE(rt, ZERO); 948 CHECK_NE(rs, rt); 949 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16)); 950 } 951 952 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { 953 CHECK(IsR6()); 954 CHECK_NE(rt, ZERO); 955 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16)); 956 } 957 958 void MipsAssembler::Blezc(Register rt, uint16_t imm16) { 959 CHECK(IsR6()); 960 CHECK_NE(rt, ZERO); 961 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16)); 962 } 963 964 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) { 965 CHECK(IsR6()); 966 CHECK_NE(rs, ZERO); 967 CHECK_NE(rt, ZERO); 968 CHECK_NE(rs, rt); 969 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16)); 970 } 971 972 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) { 973 CHECK(IsR6()); 974 CHECK_NE(rs, ZERO); 975 CHECK_NE(rt, ZERO); 976 CHECK_NE(rs, rt); 977 DsFsmInstrNop(EmitI(0x6, rs, rt, imm16)); 978 } 979 980 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) { 981 CHECK(IsR6()); 982 CHECK_NE(rs, ZERO); 983 CHECK_NE(rt, ZERO); 984 CHECK_NE(rs, rt); 985 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16)); 986 } 987 988 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) { 989 CHECK(IsR6()); 990 CHECK_NE(rs, ZERO); 991 CHECK_NE(rt, ZERO); 992 CHECK_NE(rs, rt); 993 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16)); 994 } 995 996 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { 997 CHECK(IsR6()); 998 CHECK_NE(rs, ZERO); 999 DsFsmInstrNop(EmitI21(0x36, rs, imm21)); 1000 } 1001 1002 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { 1003 CHECK(IsR6()); 1004 CHECK_NE(rs, ZERO); 1005 DsFsmInstrNop(EmitI21(0x3E, rs, imm21)); 1006 } 1007 1008 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { 1009 CHECK(IsR6()); 1010 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16)); 1011 } 1012 1013 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { 1014 CHECK(IsR6()); 1015 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16)); 1016 } 1017 1018 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { 1019 switch (cond) { 1020 case kCondLTZ: 1021 CHECK_EQ(rt, ZERO); 1022 Bltz(rs, imm16); 1023 break; 1024 case kCondGEZ: 1025 CHECK_EQ(rt, ZERO); 1026 Bgez(rs, imm16); 1027 break; 1028 case kCondLEZ: 1029 CHECK_EQ(rt, ZERO); 1030 Blez(rs, imm16); 1031 break; 1032 case kCondGTZ: 1033 CHECK_EQ(rt, ZERO); 1034 Bgtz(rs, imm16); 1035 break; 1036 case kCondEQ: 1037 Beq(rs, rt, imm16); 1038 break; 1039 case kCondNE: 1040 Bne(rs, rt, imm16); 1041 break; 1042 case kCondEQZ: 1043 CHECK_EQ(rt, ZERO); 1044 Beqz(rs, imm16); 1045 break; 1046 case kCondNEZ: 1047 CHECK_EQ(rt, ZERO); 1048 Bnez(rs, imm16); 1049 break; 1050 case kCondF: 1051 CHECK_EQ(rt, ZERO); 1052 Bc1f(static_cast<int>(rs), imm16); 1053 break; 1054 case kCondT: 1055 CHECK_EQ(rt, ZERO); 1056 Bc1t(static_cast<int>(rs), imm16); 1057 break; 1058 case kCondLT: 1059 case kCondGE: 1060 case kCondLE: 1061 case kCondGT: 1062 case kCondLTU: 1063 case kCondGEU: 1064 case kUncond: 1065 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 1066 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 1067 LOG(FATAL) << "Unexpected branch condition " << cond; 1068 UNREACHABLE(); 1069 } 1070 } 1071 1072 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { 1073 switch (cond) { 1074 case kCondLT: 1075 Bltc(rs, rt, imm16_21); 1076 break; 1077 case kCondGE: 1078 Bgec(rs, rt, imm16_21); 1079 break; 1080 case kCondLE: 1081 Bgec(rt, rs, imm16_21); 1082 break; 1083 case kCondGT: 1084 Bltc(rt, rs, imm16_21); 1085 break; 1086 case kCondLTZ: 1087 CHECK_EQ(rt, ZERO); 1088 Bltzc(rs, imm16_21); 1089 break; 1090 case kCondGEZ: 1091 CHECK_EQ(rt, ZERO); 1092 Bgezc(rs, imm16_21); 1093 break; 1094 case kCondLEZ: 1095 CHECK_EQ(rt, ZERO); 1096 Blezc(rs, imm16_21); 1097 break; 1098 case kCondGTZ: 1099 CHECK_EQ(rt, ZERO); 1100 Bgtzc(rs, imm16_21); 1101 break; 1102 case kCondEQ: 1103 Beqc(rs, rt, imm16_21); 1104 break; 1105 case kCondNE: 1106 Bnec(rs, rt, imm16_21); 1107 break; 1108 case kCondEQZ: 1109 CHECK_EQ(rt, ZERO); 1110 Beqzc(rs, imm16_21); 1111 break; 1112 case kCondNEZ: 1113 CHECK_EQ(rt, ZERO); 1114 Bnezc(rs, imm16_21); 1115 break; 1116 case kCondLTU: 1117 Bltuc(rs, rt, imm16_21); 1118 break; 1119 case kCondGEU: 1120 Bgeuc(rs, rt, imm16_21); 1121 break; 1122 case kCondF: 1123 CHECK_EQ(rt, ZERO); 1124 Bc1eqz(static_cast<FRegister>(rs), imm16_21); 1125 break; 1126 case kCondT: 1127 CHECK_EQ(rt, ZERO); 1128 Bc1nez(static_cast<FRegister>(rs), imm16_21); 1129 break; 1130 case kUncond: 1131 LOG(FATAL) << "Unexpected branch condition " << cond; 1132 UNREACHABLE(); 1133 } 1134 } 1135 1136 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 1137 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft); 1138 } 1139 1140 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 1141 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft); 1142 } 1143 1144 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 1145 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft); 1146 } 1147 1148 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 1149 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft); 1150 } 1151 1152 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { 1153 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft); 1154 } 1155 1156 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { 1157 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft); 1158 } 1159 1160 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { 1161 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft); 1162 } 1163 1164 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { 1165 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft); 1166 } 1167 1168 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) { 1169 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs); 1170 } 1171 1172 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) { 1173 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs); 1174 } 1175 1176 void MipsAssembler::AbsS(FRegister fd, FRegister fs) { 1177 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs); 1178 } 1179 1180 void MipsAssembler::AbsD(FRegister fd, FRegister fs) { 1181 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs); 1182 } 1183 1184 void MipsAssembler::MovS(FRegister fd, FRegister fs) { 1185 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs); 1186 } 1187 1188 void MipsAssembler::MovD(FRegister fd, FRegister fs) { 1189 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs); 1190 } 1191 1192 void MipsAssembler::NegS(FRegister fd, FRegister fs) { 1193 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs); 1194 } 1195 1196 void MipsAssembler::NegD(FRegister fd, FRegister fs) { 1197 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs); 1198 } 1199 1200 void MipsAssembler::CunS(FRegister fs, FRegister ft) { 1201 CunS(0, fs, ft); 1202 } 1203 1204 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { 1205 CHECK(!IsR6()); 1206 CHECK(IsUint<3>(cc)) << cc; 1207 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft); 1208 } 1209 1210 void MipsAssembler::CeqS(FRegister fs, FRegister ft) { 1211 CeqS(0, fs, ft); 1212 } 1213 1214 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { 1215 CHECK(!IsR6()); 1216 CHECK(IsUint<3>(cc)) << cc; 1217 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft); 1218 } 1219 1220 void MipsAssembler::CueqS(FRegister fs, FRegister ft) { 1221 CueqS(0, fs, ft); 1222 } 1223 1224 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { 1225 CHECK(!IsR6()); 1226 CHECK(IsUint<3>(cc)) << cc; 1227 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft); 1228 } 1229 1230 void MipsAssembler::ColtS(FRegister fs, FRegister ft) { 1231 ColtS(0, fs, ft); 1232 } 1233 1234 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { 1235 CHECK(!IsR6()); 1236 CHECK(IsUint<3>(cc)) << cc; 1237 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft); 1238 } 1239 1240 void MipsAssembler::CultS(FRegister fs, FRegister ft) { 1241 CultS(0, fs, ft); 1242 } 1243 1244 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { 1245 CHECK(!IsR6()); 1246 CHECK(IsUint<3>(cc)) << cc; 1247 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft); 1248 } 1249 1250 void MipsAssembler::ColeS(FRegister fs, FRegister ft) { 1251 ColeS(0, fs, ft); 1252 } 1253 1254 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { 1255 CHECK(!IsR6()); 1256 CHECK(IsUint<3>(cc)) << cc; 1257 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft); 1258 } 1259 1260 void MipsAssembler::CuleS(FRegister fs, FRegister ft) { 1261 CuleS(0, fs, ft); 1262 } 1263 1264 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { 1265 CHECK(!IsR6()); 1266 CHECK(IsUint<3>(cc)) << cc; 1267 DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft); 1268 } 1269 1270 void MipsAssembler::CunD(FRegister fs, FRegister ft) { 1271 CunD(0, fs, ft); 1272 } 1273 1274 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { 1275 CHECK(!IsR6()); 1276 CHECK(IsUint<3>(cc)) << cc; 1277 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft); 1278 } 1279 1280 void MipsAssembler::CeqD(FRegister fs, FRegister ft) { 1281 CeqD(0, fs, ft); 1282 } 1283 1284 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { 1285 CHECK(!IsR6()); 1286 CHECK(IsUint<3>(cc)) << cc; 1287 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft); 1288 } 1289 1290 void MipsAssembler::CueqD(FRegister fs, FRegister ft) { 1291 CueqD(0, fs, ft); 1292 } 1293 1294 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { 1295 CHECK(!IsR6()); 1296 CHECK(IsUint<3>(cc)) << cc; 1297 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft); 1298 } 1299 1300 void MipsAssembler::ColtD(FRegister fs, FRegister ft) { 1301 ColtD(0, fs, ft); 1302 } 1303 1304 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { 1305 CHECK(!IsR6()); 1306 CHECK(IsUint<3>(cc)) << cc; 1307 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft); 1308 } 1309 1310 void MipsAssembler::CultD(FRegister fs, FRegister ft) { 1311 CultD(0, fs, ft); 1312 } 1313 1314 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { 1315 CHECK(!IsR6()); 1316 CHECK(IsUint<3>(cc)) << cc; 1317 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft); 1318 } 1319 1320 void MipsAssembler::ColeD(FRegister fs, FRegister ft) { 1321 ColeD(0, fs, ft); 1322 } 1323 1324 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { 1325 CHECK(!IsR6()); 1326 CHECK(IsUint<3>(cc)) << cc; 1327 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft); 1328 } 1329 1330 void MipsAssembler::CuleD(FRegister fs, FRegister ft) { 1331 CuleD(0, fs, ft); 1332 } 1333 1334 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { 1335 CHECK(!IsR6()); 1336 CHECK(IsUint<3>(cc)) << cc; 1337 DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft); 1338 } 1339 1340 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { 1341 CHECK(IsR6()); 1342 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft); 1343 } 1344 1345 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { 1346 CHECK(IsR6()); 1347 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft); 1348 } 1349 1350 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { 1351 CHECK(IsR6()); 1352 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft); 1353 } 1354 1355 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { 1356 CHECK(IsR6()); 1357 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft); 1358 } 1359 1360 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { 1361 CHECK(IsR6()); 1362 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft); 1363 } 1364 1365 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { 1366 CHECK(IsR6()); 1367 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft); 1368 } 1369 1370 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { 1371 CHECK(IsR6()); 1372 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft); 1373 } 1374 1375 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { 1376 CHECK(IsR6()); 1377 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft); 1378 } 1379 1380 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { 1381 CHECK(IsR6()); 1382 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft); 1383 } 1384 1385 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { 1386 CHECK(IsR6()); 1387 DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft); 1388 } 1389 1390 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { 1391 CHECK(IsR6()); 1392 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft); 1393 } 1394 1395 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { 1396 CHECK(IsR6()); 1397 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft); 1398 } 1399 1400 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { 1401 CHECK(IsR6()); 1402 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft); 1403 } 1404 1405 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { 1406 CHECK(IsR6()); 1407 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft); 1408 } 1409 1410 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { 1411 CHECK(IsR6()); 1412 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft); 1413 } 1414 1415 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { 1416 CHECK(IsR6()); 1417 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft); 1418 } 1419 1420 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { 1421 CHECK(IsR6()); 1422 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft); 1423 } 1424 1425 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { 1426 CHECK(IsR6()); 1427 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft); 1428 } 1429 1430 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { 1431 CHECK(IsR6()); 1432 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft); 1433 } 1434 1435 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { 1436 CHECK(IsR6()); 1437 DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft); 1438 } 1439 1440 void MipsAssembler::Movf(Register rd, Register rs, int cc) { 1441 CHECK(!IsR6()); 1442 CHECK(IsUint<3>(cc)) << cc; 1443 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc); 1444 } 1445 1446 void MipsAssembler::Movt(Register rd, Register rs, int cc) { 1447 CHECK(!IsR6()); 1448 CHECK(IsUint<3>(cc)) << cc; 1449 DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc); 1450 } 1451 1452 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) { 1453 CHECK(!IsR6()); 1454 CHECK(IsUint<3>(cc)) << cc; 1455 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc); 1456 } 1457 1458 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) { 1459 CHECK(!IsR6()); 1460 CHECK(IsUint<3>(cc)) << cc; 1461 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc); 1462 } 1463 1464 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) { 1465 CHECK(!IsR6()); 1466 CHECK(IsUint<3>(cc)) << cc; 1467 DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11), 1468 fd, 1469 fs, 1470 cc); 1471 } 1472 1473 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) { 1474 CHECK(!IsR6()); 1475 CHECK(IsUint<3>(cc)) << cc; 1476 DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11), 1477 fd, 1478 fs, 1479 cc); 1480 } 1481 1482 void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) { 1483 CHECK(!IsR6()); 1484 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt); 1485 } 1486 1487 void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) { 1488 CHECK(!IsR6()); 1489 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt); 1490 } 1491 1492 void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) { 1493 CHECK(!IsR6()); 1494 DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt); 1495 } 1496 1497 void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) { 1498 CHECK(!IsR6()); 1499 DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt); 1500 } 1501 1502 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) { 1503 CHECK(IsR6()); 1504 DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft); 1505 } 1506 1507 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) { 1508 CHECK(IsR6()); 1509 DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft); 1510 } 1511 1512 void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) { 1513 CHECK(IsR6()); 1514 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft); 1515 } 1516 1517 void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) { 1518 CHECK(IsR6()); 1519 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft); 1520 } 1521 1522 void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) { 1523 CHECK(IsR6()); 1524 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft); 1525 } 1526 1527 void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) { 1528 CHECK(IsR6()); 1529 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft); 1530 } 1531 1532 void MipsAssembler::ClassS(FRegister fd, FRegister fs) { 1533 CHECK(IsR6()); 1534 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs); 1535 } 1536 1537 void MipsAssembler::ClassD(FRegister fd, FRegister fs) { 1538 CHECK(IsR6()); 1539 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs); 1540 } 1541 1542 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) { 1543 CHECK(IsR6()); 1544 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft); 1545 } 1546 1547 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) { 1548 CHECK(IsR6()); 1549 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft); 1550 } 1551 1552 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) { 1553 CHECK(IsR6()); 1554 DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft); 1555 } 1556 1557 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) { 1558 CHECK(IsR6()); 1559 DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft); 1560 } 1561 1562 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { 1563 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs); 1564 } 1565 1566 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { 1567 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs); 1568 } 1569 1570 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { 1571 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs); 1572 } 1573 1574 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { 1575 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs); 1576 } 1577 1578 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { 1579 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs); 1580 } 1581 1582 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { 1583 DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs); 1584 } 1585 1586 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { 1587 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs); 1588 } 1589 1590 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { 1591 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs); 1592 } 1593 1594 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { 1595 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs); 1596 } 1597 1598 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { 1599 DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs); 1600 } 1601 1602 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) { 1603 DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs); 1604 } 1605 1606 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) { 1607 DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs); 1608 } 1609 1610 void MipsAssembler::Mfc1(Register rt, FRegister fs) { 1611 DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0), 1612 rt, 1613 fs); 1614 } 1615 1616 void MipsAssembler::Mtc1(Register rt, FRegister fs) { 1617 DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0), 1618 fs, 1619 rt); 1620 } 1621 1622 void MipsAssembler::Mfhc1(Register rt, FRegister fs) { 1623 DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0), 1624 rt, 1625 fs); 1626 } 1627 1628 void MipsAssembler::Mthc1(Register rt, FRegister fs) { 1629 DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0), 1630 fs, 1631 rt); 1632 } 1633 1634 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) { 1635 if (Is32BitFPU()) { 1636 CHECK_EQ(fs % 2, 0) << fs; 1637 Mfc1(rt, static_cast<FRegister>(fs + 1)); 1638 } else { 1639 Mfhc1(rt, fs); 1640 } 1641 } 1642 1643 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) { 1644 if (Is32BitFPU()) { 1645 CHECK_EQ(fs % 2, 0) << fs; 1646 Mtc1(rt, static_cast<FRegister>(fs + 1)); 1647 } else { 1648 Mthc1(rt, fs); 1649 } 1650 } 1651 1652 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 1653 DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs); 1654 } 1655 1656 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { 1657 DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs); 1658 } 1659 1660 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 1661 DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs); 1662 } 1663 1664 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { 1665 DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs); 1666 } 1667 1668 void MipsAssembler::Break() { 1669 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD)); 1670 } 1671 1672 void MipsAssembler::Nop() { 1673 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0)); 1674 } 1675 1676 void MipsAssembler::NopIfNoReordering() { 1677 if (!reordering_) { 1678 Nop(); 1679 } 1680 } 1681 1682 void MipsAssembler::Move(Register rd, Register rs) { 1683 Or(rd, rs, ZERO); 1684 } 1685 1686 void MipsAssembler::Clear(Register rd) { 1687 Move(rd, ZERO); 1688 } 1689 1690 void MipsAssembler::Not(Register rd, Register rs) { 1691 Nor(rd, rs, ZERO); 1692 } 1693 1694 void MipsAssembler::Push(Register rs) { 1695 IncreaseFrameSize(kMipsWordSize); 1696 Sw(rs, SP, 0); 1697 } 1698 1699 void MipsAssembler::Pop(Register rd) { 1700 Lw(rd, SP, 0); 1701 DecreaseFrameSize(kMipsWordSize); 1702 } 1703 1704 void MipsAssembler::PopAndReturn(Register rd, Register rt) { 1705 bool reordering = SetReorder(false); 1706 Lw(rd, SP, 0); 1707 Jr(rt); 1708 DecreaseFrameSize(kMipsWordSize); // Single instruction in delay slot. 1709 SetReorder(reordering); 1710 } 1711 1712 void MipsAssembler::LoadConst32(Register rd, int32_t value) { 1713 if (IsUint<16>(value)) { 1714 // Use OR with (unsigned) immediate to encode 16b unsigned int. 1715 Ori(rd, ZERO, value); 1716 } else if (IsInt<16>(value)) { 1717 // Use ADD with (signed) immediate to encode 16b signed int. 1718 Addiu(rd, ZERO, value); 1719 } else { 1720 Lui(rd, High16Bits(value)); 1721 if (value & 0xFFFF) 1722 Ori(rd, rd, Low16Bits(value)); 1723 } 1724 } 1725 1726 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) { 1727 uint32_t low = Low32Bits(value); 1728 uint32_t high = High32Bits(value); 1729 LoadConst32(reg_lo, low); 1730 if (high != low) { 1731 LoadConst32(reg_hi, high); 1732 } else { 1733 Move(reg_hi, reg_lo); 1734 } 1735 } 1736 1737 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) { 1738 if (value == 0) { 1739 temp = ZERO; 1740 } else { 1741 LoadConst32(temp, value); 1742 } 1743 Mtc1(temp, r); 1744 } 1745 1746 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) { 1747 uint32_t low = Low32Bits(value); 1748 uint32_t high = High32Bits(value); 1749 if (low == 0) { 1750 Mtc1(ZERO, rd); 1751 } else { 1752 LoadConst32(temp, low); 1753 Mtc1(temp, rd); 1754 } 1755 if (high == 0) { 1756 MoveToFpuHigh(ZERO, rd); 1757 } else { 1758 LoadConst32(temp, high); 1759 MoveToFpuHigh(temp, rd); 1760 } 1761 } 1762 1763 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) { 1764 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`. 1765 if (IsInt<16>(value)) { 1766 Addiu(rt, rs, value); 1767 } else if (IsR6()) { 1768 int16_t high = High16Bits(value); 1769 int16_t low = Low16Bits(value); 1770 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu. 1771 if (low != 0) { 1772 Aui(temp, rs, high); 1773 Addiu(rt, temp, low); 1774 } else { 1775 Aui(rt, rs, high); 1776 } 1777 } else { 1778 // Do not load the whole 32-bit `value` if it can be represented as 1779 // a sum of two 16-bit signed values. This can save an instruction. 1780 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2; 1781 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2; 1782 if (0 <= value && value <= kMaxValueForSimpleAdjustment) { 1783 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2); 1784 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2); 1785 } else if (kMinValueForSimpleAdjustment <= value && value < 0) { 1786 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2); 1787 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2); 1788 } else { 1789 // Now that all shorter options have been exhausted, load the full 32-bit value. 1790 LoadConst32(temp, value); 1791 Addu(rt, rs, temp); 1792 } 1793 } 1794 } 1795 1796 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size, 1797 MipsAssembler::Branch::Type short_type, 1798 MipsAssembler::Branch::Type long_type) { 1799 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; 1800 } 1801 1802 void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) { 1803 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_); 1804 if (is_r6) { 1805 // R6 1806 switch (initial_type) { 1807 case kLabel: 1808 CHECK(!IsResolved()); 1809 type_ = kR6Label; 1810 break; 1811 case kLiteral: 1812 CHECK(!IsResolved()); 1813 type_ = kR6Literal; 1814 break; 1815 case kCall: 1816 InitShortOrLong(offset_size, kR6Call, kR6LongCall); 1817 break; 1818 case kCondBranch: 1819 switch (condition_) { 1820 case kUncond: 1821 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch); 1822 break; 1823 case kCondEQZ: 1824 case kCondNEZ: 1825 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. 1826 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch; 1827 break; 1828 default: 1829 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch); 1830 break; 1831 } 1832 break; 1833 default: 1834 LOG(FATAL) << "Unexpected branch type " << initial_type; 1835 UNREACHABLE(); 1836 } 1837 } else { 1838 // R2 1839 switch (initial_type) { 1840 case kLabel: 1841 CHECK(!IsResolved()); 1842 type_ = kLabel; 1843 break; 1844 case kLiteral: 1845 CHECK(!IsResolved()); 1846 type_ = kLiteral; 1847 break; 1848 case kCall: 1849 InitShortOrLong(offset_size, kCall, kLongCall); 1850 break; 1851 case kCondBranch: 1852 switch (condition_) { 1853 case kUncond: 1854 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch); 1855 break; 1856 default: 1857 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch); 1858 break; 1859 } 1860 break; 1861 default: 1862 LOG(FATAL) << "Unexpected branch type " << initial_type; 1863 UNREACHABLE(); 1864 } 1865 } 1866 old_type_ = type_; 1867 } 1868 1869 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) { 1870 switch (condition) { 1871 case kCondLT: 1872 case kCondGT: 1873 case kCondNE: 1874 case kCondLTU: 1875 return lhs == rhs; 1876 default: 1877 return false; 1878 } 1879 } 1880 1881 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) { 1882 switch (condition) { 1883 case kUncond: 1884 return true; 1885 case kCondGE: 1886 case kCondLE: 1887 case kCondEQ: 1888 case kCondGEU: 1889 return lhs == rhs; 1890 default: 1891 return false; 1892 } 1893 } 1894 1895 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call) 1896 : old_location_(location), 1897 location_(location), 1898 target_(target), 1899 lhs_reg_(0), 1900 rhs_reg_(0), 1901 condition_(kUncond), 1902 delayed_instruction_(kUnfilledDelaySlot) { 1903 InitializeType((is_call ? kCall : kCondBranch), is_r6); 1904 } 1905 1906 MipsAssembler::Branch::Branch(bool is_r6, 1907 uint32_t location, 1908 uint32_t target, 1909 MipsAssembler::BranchCondition condition, 1910 Register lhs_reg, 1911 Register rhs_reg) 1912 : old_location_(location), 1913 location_(location), 1914 target_(target), 1915 lhs_reg_(lhs_reg), 1916 rhs_reg_(rhs_reg), 1917 condition_(condition), 1918 delayed_instruction_(kUnfilledDelaySlot) { 1919 CHECK_NE(condition, kUncond); 1920 switch (condition) { 1921 case kCondLT: 1922 case kCondGE: 1923 case kCondLE: 1924 case kCondGT: 1925 case kCondLTU: 1926 case kCondGEU: 1927 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 1928 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 1929 // We leave this up to the caller. 1930 CHECK(is_r6); 1931 FALLTHROUGH_INTENDED; 1932 case kCondEQ: 1933 case kCondNE: 1934 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1935 // To compare with 0, use dedicated kCond*Z conditions. 1936 CHECK_NE(lhs_reg, ZERO); 1937 CHECK_NE(rhs_reg, ZERO); 1938 break; 1939 case kCondLTZ: 1940 case kCondGEZ: 1941 case kCondLEZ: 1942 case kCondGTZ: 1943 case kCondEQZ: 1944 case kCondNEZ: 1945 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1946 CHECK_NE(lhs_reg, ZERO); 1947 CHECK_EQ(rhs_reg, ZERO); 1948 break; 1949 case kCondF: 1950 case kCondT: 1951 CHECK_EQ(rhs_reg, ZERO); 1952 break; 1953 case kUncond: 1954 UNREACHABLE(); 1955 } 1956 CHECK(!IsNop(condition, lhs_reg, rhs_reg)); 1957 if (IsUncond(condition, lhs_reg, rhs_reg)) { 1958 // Branch condition is always true, make the branch unconditional. 1959 condition_ = kUncond; 1960 } 1961 InitializeType(kCondBranch, is_r6); 1962 } 1963 1964 MipsAssembler::Branch::Branch(bool is_r6, 1965 uint32_t location, 1966 Register dest_reg, 1967 Register base_reg, 1968 Type label_or_literal_type) 1969 : old_location_(location), 1970 location_(location), 1971 target_(kUnresolved), 1972 lhs_reg_(dest_reg), 1973 rhs_reg_(base_reg), 1974 condition_(kUncond), 1975 delayed_instruction_(kUnfilledDelaySlot) { 1976 CHECK_NE(dest_reg, ZERO); 1977 if (is_r6) { 1978 CHECK_EQ(base_reg, ZERO); 1979 } else { 1980 CHECK_NE(base_reg, ZERO); 1981 } 1982 InitializeType(label_or_literal_type, is_r6); 1983 } 1984 1985 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( 1986 MipsAssembler::BranchCondition cond) { 1987 switch (cond) { 1988 case kCondLT: 1989 return kCondGE; 1990 case kCondGE: 1991 return kCondLT; 1992 case kCondLE: 1993 return kCondGT; 1994 case kCondGT: 1995 return kCondLE; 1996 case kCondLTZ: 1997 return kCondGEZ; 1998 case kCondGEZ: 1999 return kCondLTZ; 2000 case kCondLEZ: 2001 return kCondGTZ; 2002 case kCondGTZ: 2003 return kCondLEZ; 2004 case kCondEQ: 2005 return kCondNE; 2006 case kCondNE: 2007 return kCondEQ; 2008 case kCondEQZ: 2009 return kCondNEZ; 2010 case kCondNEZ: 2011 return kCondEQZ; 2012 case kCondLTU: 2013 return kCondGEU; 2014 case kCondGEU: 2015 return kCondLTU; 2016 case kCondF: 2017 return kCondT; 2018 case kCondT: 2019 return kCondF; 2020 case kUncond: 2021 LOG(FATAL) << "Unexpected branch condition " << cond; 2022 } 2023 UNREACHABLE(); 2024 } 2025 2026 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { 2027 return type_; 2028 } 2029 2030 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { 2031 return condition_; 2032 } 2033 2034 Register MipsAssembler::Branch::GetLeftRegister() const { 2035 return static_cast<Register>(lhs_reg_); 2036 } 2037 2038 Register MipsAssembler::Branch::GetRightRegister() const { 2039 return static_cast<Register>(rhs_reg_); 2040 } 2041 2042 uint32_t MipsAssembler::Branch::GetTarget() const { 2043 return target_; 2044 } 2045 2046 uint32_t MipsAssembler::Branch::GetLocation() const { 2047 return location_; 2048 } 2049 2050 uint32_t MipsAssembler::Branch::GetOldLocation() const { 2051 return old_location_; 2052 } 2053 2054 uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const { 2055 // Short branches with delay slots always consist of two instructions, the branch 2056 // and the delay slot, irrespective of whether the delay slot is filled with a 2057 // useful instruction or not. 2058 // Long composite branches may have a length longer by one instruction than 2059 // specified in branch_info_[].length. This happens when an instruction is taken 2060 // to fill the short branch delay slot, but the branch eventually becomes long 2061 // and formally has no delay slot to fill. This instruction is placed at the 2062 // beginning of the long composite branch and this needs to be accounted for in 2063 // the branch length and the location of the offset encoded in the branch. 2064 switch (type) { 2065 case kLongUncondBranch: 2066 case kLongCondBranch: 2067 case kLongCall: 2068 case kR6LongCondBranch: 2069 return (delayed_instruction_ != kUnfilledDelaySlot && 2070 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0; 2071 default: 2072 return 0; 2073 } 2074 } 2075 2076 uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const { 2077 return GetPrecedingInstructionLength(type) * sizeof(uint32_t); 2078 } 2079 2080 uint32_t MipsAssembler::Branch::GetLength() const { 2081 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length; 2082 } 2083 2084 uint32_t MipsAssembler::Branch::GetOldLength() const { 2085 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length; 2086 } 2087 2088 uint32_t MipsAssembler::Branch::GetSize() const { 2089 return GetLength() * sizeof(uint32_t); 2090 } 2091 2092 uint32_t MipsAssembler::Branch::GetOldSize() const { 2093 return GetOldLength() * sizeof(uint32_t); 2094 } 2095 2096 uint32_t MipsAssembler::Branch::GetEndLocation() const { 2097 return GetLocation() + GetSize(); 2098 } 2099 2100 uint32_t MipsAssembler::Branch::GetOldEndLocation() const { 2101 return GetOldLocation() + GetOldSize(); 2102 } 2103 2104 bool MipsAssembler::Branch::IsLong() const { 2105 switch (type_) { 2106 // R2 short branches. 2107 case kUncondBranch: 2108 case kCondBranch: 2109 case kCall: 2110 // R2 near label. 2111 case kLabel: 2112 // R2 near literal. 2113 case kLiteral: 2114 // R6 short branches. 2115 case kR6UncondBranch: 2116 case kR6CondBranch: 2117 case kR6Call: 2118 // R6 near label. 2119 case kR6Label: 2120 // R6 near literal. 2121 case kR6Literal: 2122 return false; 2123 // R2 long branches. 2124 case kLongUncondBranch: 2125 case kLongCondBranch: 2126 case kLongCall: 2127 // R2 far label. 2128 case kFarLabel: 2129 // R2 far literal. 2130 case kFarLiteral: 2131 // R6 long branches. 2132 case kR6LongUncondBranch: 2133 case kR6LongCondBranch: 2134 case kR6LongCall: 2135 // R6 far label. 2136 case kR6FarLabel: 2137 // R6 far literal. 2138 case kR6FarLiteral: 2139 return true; 2140 } 2141 UNREACHABLE(); 2142 } 2143 2144 bool MipsAssembler::Branch::IsResolved() const { 2145 return target_ != kUnresolved; 2146 } 2147 2148 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const { 2149 OffsetBits offset_size = 2150 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) 2151 ? kOffset23 2152 : branch_info_[type_].offset_size; 2153 return offset_size; 2154 } 2155 2156 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location, 2157 uint32_t target) { 2158 // For unresolved targets assume the shortest encoding 2159 // (later it will be made longer if needed). 2160 if (target == kUnresolved) 2161 return kOffset16; 2162 int64_t distance = static_cast<int64_t>(target) - location; 2163 // To simplify calculations in composite branches consisting of multiple instructions 2164 // bump up the distance by a value larger than the max byte size of a composite branch. 2165 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; 2166 if (IsInt<kOffset16>(distance)) 2167 return kOffset16; 2168 else if (IsInt<kOffset18>(distance)) 2169 return kOffset18; 2170 else if (IsInt<kOffset21>(distance)) 2171 return kOffset21; 2172 else if (IsInt<kOffset23>(distance)) 2173 return kOffset23; 2174 else if (IsInt<kOffset28>(distance)) 2175 return kOffset28; 2176 return kOffset32; 2177 } 2178 2179 void MipsAssembler::Branch::Resolve(uint32_t target) { 2180 target_ = target; 2181 } 2182 2183 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { 2184 if (location_ > expand_location) { 2185 location_ += delta; 2186 } 2187 if (!IsResolved()) { 2188 return; // Don't know the target yet. 2189 } 2190 if (target_ > expand_location) { 2191 target_ += delta; 2192 } 2193 } 2194 2195 void MipsAssembler::Branch::PromoteToLong() { 2196 switch (type_) { 2197 // R2 short branches. 2198 case kUncondBranch: 2199 type_ = kLongUncondBranch; 2200 break; 2201 case kCondBranch: 2202 type_ = kLongCondBranch; 2203 break; 2204 case kCall: 2205 type_ = kLongCall; 2206 break; 2207 // R2 near label. 2208 case kLabel: 2209 type_ = kFarLabel; 2210 break; 2211 // R2 near literal. 2212 case kLiteral: 2213 type_ = kFarLiteral; 2214 break; 2215 // R6 short branches. 2216 case kR6UncondBranch: 2217 type_ = kR6LongUncondBranch; 2218 break; 2219 case kR6CondBranch: 2220 type_ = kR6LongCondBranch; 2221 break; 2222 case kR6Call: 2223 type_ = kR6LongCall; 2224 break; 2225 // R6 near label. 2226 case kR6Label: 2227 type_ = kR6FarLabel; 2228 break; 2229 // R6 near literal. 2230 case kR6Literal: 2231 type_ = kR6FarLiteral; 2232 break; 2233 default: 2234 // Note: 'type_' is already long. 2235 break; 2236 } 2237 CHECK(IsLong()); 2238 } 2239 2240 uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const { 2241 switch (branch->GetType()) { 2242 case Branch::kLabel: 2243 case Branch::kFarLabel: 2244 case Branch::kLiteral: 2245 case Branch::kFarLiteral: 2246 return GetLabelLocation(&pc_rel_base_label_); 2247 default: 2248 return branch->GetLocation(); 2249 } 2250 } 2251 2252 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) { 2253 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or 2254 // `this->GetLocation()` for everything else. 2255 // If the branch is still unresolved or already long, nothing to do. 2256 if (IsLong() || !IsResolved()) { 2257 return 0; 2258 } 2259 // Promote the short branch to long if the offset size is too small 2260 // to hold the distance between location and target_. 2261 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) { 2262 PromoteToLong(); 2263 uint32_t old_size = GetOldSize(); 2264 uint32_t new_size = GetSize(); 2265 CHECK_GT(new_size, old_size); 2266 return new_size - old_size; 2267 } 2268 // The following logic is for debugging/testing purposes. 2269 // Promote some short branches to long when it's not really required. 2270 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) { 2271 int64_t distance = static_cast<int64_t>(target_) - location; 2272 distance = (distance >= 0) ? distance : -distance; 2273 if (distance >= max_short_distance) { 2274 PromoteToLong(); 2275 uint32_t old_size = GetOldSize(); 2276 uint32_t new_size = GetSize(); 2277 CHECK_GT(new_size, old_size); 2278 return new_size - old_size; 2279 } 2280 } 2281 return 0; 2282 } 2283 2284 uint32_t MipsAssembler::Branch::GetOffsetLocation() const { 2285 return location_ + GetPrecedingInstructionSize(type_) + 2286 branch_info_[type_].instr_offset * sizeof(uint32_t); 2287 } 2288 2289 uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const { 2290 switch (branch->GetType()) { 2291 case Branch::kLabel: 2292 case Branch::kFarLabel: 2293 case Branch::kLiteral: 2294 case Branch::kFarLiteral: 2295 return GetLabelLocation(&pc_rel_base_label_); 2296 default: 2297 return branch->GetOffsetLocation() + 2298 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t); 2299 } 2300 } 2301 2302 uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const { 2303 // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or 2304 // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)` 2305 // for everything else. 2306 CHECK(IsResolved()); 2307 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); 2308 // Calculate the byte distance between instructions and also account for 2309 // different PC-relative origins. 2310 uint32_t offset = target_ - location; 2311 // Prepare the offset for encoding into the instruction(s). 2312 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; 2313 return offset; 2314 } 2315 2316 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { 2317 CHECK_LT(branch_id, branches_.size()); 2318 return &branches_[branch_id]; 2319 } 2320 2321 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { 2322 CHECK_LT(branch_id, branches_.size()); 2323 return &branches_[branch_id]; 2324 } 2325 2326 void MipsAssembler::Bind(MipsLabel* label) { 2327 CHECK(!label->IsBound()); 2328 uint32_t bound_pc = buffer_.Size(); 2329 2330 // Make the delay slot FSM aware of the new label. 2331 DsFsmLabel(); 2332 2333 // Walk the list of branches referring to and preceding this label. 2334 // Store the previously unknown target addresses in them. 2335 while (label->IsLinked()) { 2336 uint32_t branch_id = label->Position(); 2337 Branch* branch = GetBranch(branch_id); 2338 branch->Resolve(bound_pc); 2339 2340 uint32_t branch_location = branch->GetLocation(); 2341 // Extract the location of the previous branch in the list (walking the list backwards; 2342 // the previous branch ID was stored in the space reserved for this branch). 2343 uint32_t prev = buffer_.Load<uint32_t>(branch_location); 2344 2345 // On to the previous branch in the list... 2346 label->position_ = prev; 2347 } 2348 2349 // Now make the label object contain its own location (relative to the end of the preceding 2350 // branch, if any; it will be used by the branches referring to and following this label). 2351 label->prev_branch_id_plus_one_ = branches_.size(); 2352 if (label->prev_branch_id_plus_one_) { 2353 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 2354 const Branch* branch = GetBranch(branch_id); 2355 bound_pc -= branch->GetEndLocation(); 2356 } 2357 label->BindTo(bound_pc); 2358 } 2359 2360 uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const { 2361 CHECK(label->IsBound()); 2362 uint32_t target = label->Position(); 2363 if (label->prev_branch_id_plus_one_) { 2364 // Get label location based on the branch preceding it. 2365 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 2366 const Branch* branch = GetBranch(branch_id); 2367 target += branch->GetEndLocation(); 2368 } 2369 return target; 2370 } 2371 2372 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) { 2373 // We can reconstruct the adjustment by going through all the branches from the beginning 2374 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop 2375 // with increasing old_position, we can use the data from last AdjustedPosition() to 2376 // continue where we left off and the whole loop should be O(m+n) where m is the number 2377 // of positions to adjust and n is the number of branches. 2378 if (old_position < last_old_position_) { 2379 last_position_adjustment_ = 0; 2380 last_old_position_ = 0; 2381 last_branch_id_ = 0; 2382 } 2383 while (last_branch_id_ != branches_.size()) { 2384 const Branch* branch = GetBranch(last_branch_id_); 2385 if (branch->GetLocation() >= old_position + last_position_adjustment_) { 2386 break; 2387 } 2388 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); 2389 ++last_branch_id_; 2390 } 2391 last_old_position_ = old_position; 2392 return old_position + last_position_adjustment_; 2393 } 2394 2395 void MipsAssembler::BindPcRelBaseLabel() { 2396 Bind(&pc_rel_base_label_); 2397 } 2398 2399 uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const { 2400 return GetLabelLocation(&pc_rel_base_label_); 2401 } 2402 2403 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) { 2404 uint32_t length = branches_.back().GetLength(); 2405 // Commit the last branch target label (if any). 2406 DsFsmCommitLabel(); 2407 if (!label->IsBound()) { 2408 // Branch forward (to a following label), distance is unknown. 2409 // The first branch forward will contain 0, serving as the terminator of 2410 // the list of forward-reaching branches. 2411 Emit(label->position_); 2412 // Nothing for the delay slot (yet). 2413 DsFsmInstrNop(0); 2414 length--; 2415 // Now make the label object point to this branch 2416 // (this forms a linked list of branches preceding this label). 2417 uint32_t branch_id = branches_.size() - 1; 2418 label->LinkTo(branch_id); 2419 } 2420 // Reserve space for the branch. 2421 while (length--) { 2422 Nop(); 2423 } 2424 } 2425 2426 bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const { 2427 if (delay_slot.instruction_ == 0) { 2428 // NOP or no instruction for the delay slot. 2429 return false; 2430 } 2431 switch (type_) { 2432 // R2 unconditional branches. 2433 case kUncondBranch: 2434 case kLongUncondBranch: 2435 // There are no register interdependencies. 2436 return true; 2437 2438 // R2 calls. 2439 case kCall: 2440 case kLongCall: 2441 // Instructions depending on or modifying RA should not be moved into delay slots 2442 // of branches modifying RA. 2443 return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0; 2444 2445 // R2 conditional branches. 2446 case kCondBranch: 2447 case kLongCondBranch: 2448 switch (condition_) { 2449 // Branches with one GPR source. 2450 case kCondLTZ: 2451 case kCondGEZ: 2452 case kCondLEZ: 2453 case kCondGTZ: 2454 case kCondEQZ: 2455 case kCondNEZ: 2456 return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0; 2457 2458 // Branches with two GPR sources. 2459 case kCondEQ: 2460 case kCondNE: 2461 return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0; 2462 2463 // Branches with one FPU condition code source. 2464 case kCondF: 2465 case kCondT: 2466 return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0; 2467 2468 default: 2469 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 2470 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 2471 LOG(FATAL) << "Unexpected branch condition " << condition_; 2472 UNREACHABLE(); 2473 } 2474 2475 // R6 unconditional branches. 2476 case kR6UncondBranch: 2477 case kR6LongUncondBranch: 2478 // R6 calls. 2479 case kR6Call: 2480 case kR6LongCall: 2481 // There are no delay slots. 2482 return false; 2483 2484 // R6 conditional branches. 2485 case kR6CondBranch: 2486 case kR6LongCondBranch: 2487 switch (condition_) { 2488 // Branches with one FPU register source. 2489 case kCondF: 2490 case kCondT: 2491 return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0; 2492 // Others have a forbidden slot instead of a delay slot. 2493 default: 2494 return false; 2495 } 2496 2497 // Literals. 2498 default: 2499 LOG(FATAL) << "Unexpected branch type " << type_; 2500 UNREACHABLE(); 2501 } 2502 } 2503 2504 uint32_t MipsAssembler::Branch::GetDelayedInstruction() const { 2505 return delayed_instruction_; 2506 } 2507 2508 void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction) { 2509 CHECK_NE(instruction, kUnfilledDelaySlot); 2510 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot); 2511 delayed_instruction_ = instruction; 2512 } 2513 2514 void MipsAssembler::Branch::DecrementLocations() { 2515 // We first create a branch object, which gets its type and locations initialized, 2516 // and then we check if the branch can actually have the preceding instruction moved 2517 // into its delay slot. If it can, the branch locations need to be decremented. 2518 // 2519 // We could make the check before creating the branch object and avoid the location 2520 // adjustment, but the check is cleaner when performed on an initialized branch 2521 // object. 2522 // 2523 // If the branch is backwards (to a previously bound label), reducing the locations 2524 // cannot cause a short branch to exceed its offset range because the offset reduces. 2525 // And this is not at all a problem for a long branch backwards. 2526 // 2527 // If the branch is forward (not linked to any label yet), reducing the locations 2528 // is harmless. The branch will be promoted to long if needed when the target is known. 2529 CHECK_EQ(location_, old_location_); 2530 CHECK_GE(old_location_, sizeof(uint32_t)); 2531 old_location_ -= sizeof(uint32_t); 2532 location_ = old_location_; 2533 } 2534 2535 void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) { 2536 if (branch.CanHaveDelayedInstruction(delay_slot_)) { 2537 // The last instruction cannot be used in a different delay slot, 2538 // do not commit the label before it (if any). 2539 DsFsmDropLabel(); 2540 // Remove the last emitted instruction. 2541 size_t size = buffer_.Size(); 2542 CHECK_GE(size, sizeof(uint32_t)); 2543 size -= sizeof(uint32_t); 2544 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_); 2545 buffer_.Resize(size); 2546 // Attach it to the branch and adjust the branch locations. 2547 branch.DecrementLocations(); 2548 branch.SetDelayedInstruction(delay_slot_.instruction_); 2549 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) { 2550 // If reordefing is disabled, prevent absorption of the target instruction. 2551 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot); 2552 } 2553 } 2554 2555 void MipsAssembler::Buncond(MipsLabel* label) { 2556 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 2557 branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ false); 2558 MoveInstructionToDelaySlot(branches_.back()); 2559 FinalizeLabeledBranch(label); 2560 } 2561 2562 void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) { 2563 // If lhs = rhs, this can be a NOP. 2564 if (Branch::IsNop(condition, lhs, rhs)) { 2565 return; 2566 } 2567 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 2568 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs); 2569 MoveInstructionToDelaySlot(branches_.back()); 2570 FinalizeLabeledBranch(label); 2571 } 2572 2573 void MipsAssembler::Call(MipsLabel* label) { 2574 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 2575 branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ true); 2576 MoveInstructionToDelaySlot(branches_.back()); 2577 FinalizeLabeledBranch(label); 2578 } 2579 2580 void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) { 2581 // Label address loads are treated as pseudo branches since they require very similar handling. 2582 DCHECK(!label->IsBound()); 2583 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel); 2584 FinalizeLabeledBranch(label); 2585 } 2586 2587 Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) { 2588 DCHECK(size == 4u || size == 8u) << size; 2589 literals_.emplace_back(size, data); 2590 return &literals_.back(); 2591 } 2592 2593 void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) { 2594 // Literal loads are treated as pseudo branches since they require very similar handling. 2595 DCHECK_EQ(literal->GetSize(), 4u); 2596 MipsLabel* label = literal->GetLabel(); 2597 DCHECK(!label->IsBound()); 2598 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral); 2599 FinalizeLabeledBranch(label); 2600 } 2601 2602 JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) { 2603 jump_tables_.emplace_back(std::move(labels)); 2604 JumpTable* table = &jump_tables_.back(); 2605 DCHECK(!table->GetLabel()->IsBound()); 2606 return table; 2607 } 2608 2609 void MipsAssembler::EmitLiterals() { 2610 if (!literals_.empty()) { 2611 // We don't support byte and half-word literals. 2612 // TODO: proper alignment for 64-bit literals when they're implemented. 2613 for (Literal& literal : literals_) { 2614 MipsLabel* label = literal.GetLabel(); 2615 Bind(label); 2616 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 2617 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u); 2618 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) { 2619 buffer_.Emit<uint8_t>(literal.GetData()[i]); 2620 } 2621 } 2622 } 2623 } 2624 2625 void MipsAssembler::ReserveJumpTableSpace() { 2626 if (!jump_tables_.empty()) { 2627 for (JumpTable& table : jump_tables_) { 2628 MipsLabel* label = table.GetLabel(); 2629 Bind(label); 2630 2631 // Bulk ensure capacity, as this may be large. 2632 size_t orig_size = buffer_.Size(); 2633 size_t required_capacity = orig_size + table.GetSize(); 2634 if (required_capacity > buffer_.Capacity()) { 2635 buffer_.ExtendCapacity(required_capacity); 2636 } 2637 #ifndef NDEBUG 2638 buffer_.has_ensured_capacity_ = true; 2639 #endif 2640 2641 // Fill the space with dummy data as the data is not final 2642 // until the branches have been promoted. And we shouldn't 2643 // be moving uninitialized data during branch promotion. 2644 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) { 2645 buffer_.Emit<uint32_t>(0x1abe1234u); 2646 } 2647 2648 #ifndef NDEBUG 2649 buffer_.has_ensured_capacity_ = false; 2650 #endif 2651 } 2652 } 2653 } 2654 2655 void MipsAssembler::EmitJumpTables() { 2656 if (!jump_tables_.empty()) { 2657 CHECK(!overwriting_); 2658 // Switch from appending instructions at the end of the buffer to overwriting 2659 // existing instructions (here, jump tables) in the buffer. 2660 overwriting_ = true; 2661 2662 for (JumpTable& table : jump_tables_) { 2663 MipsLabel* table_label = table.GetLabel(); 2664 uint32_t start = GetLabelLocation(table_label); 2665 overwrite_location_ = start; 2666 2667 for (MipsLabel* target : table.GetData()) { 2668 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u); 2669 // The table will contain target addresses relative to the table start. 2670 uint32_t offset = GetLabelLocation(target) - start; 2671 Emit(offset); 2672 } 2673 } 2674 2675 overwriting_ = false; 2676 } 2677 } 2678 2679 void MipsAssembler::PromoteBranches() { 2680 // Promote short branches to long as necessary. 2681 bool changed; 2682 do { 2683 changed = false; 2684 for (auto& branch : branches_) { 2685 CHECK(branch.IsResolved()); 2686 uint32_t base = GetBranchLocationOrPcRelBase(&branch); 2687 uint32_t delta = branch.PromoteIfNeeded(base); 2688 // If this branch has been promoted and needs to expand in size, 2689 // relocate all branches by the expansion size. 2690 if (delta) { 2691 changed = true; 2692 uint32_t expand_location = branch.GetLocation(); 2693 for (auto& branch2 : branches_) { 2694 branch2.Relocate(expand_location, delta); 2695 } 2696 } 2697 } 2698 } while (changed); 2699 2700 // Account for branch expansion by resizing the code buffer 2701 // and moving the code in it to its final location. 2702 size_t branch_count = branches_.size(); 2703 if (branch_count > 0) { 2704 // Resize. 2705 Branch& last_branch = branches_[branch_count - 1]; 2706 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); 2707 uint32_t old_size = buffer_.Size(); 2708 buffer_.Resize(old_size + size_delta); 2709 // Move the code residing between branch placeholders. 2710 uint32_t end = old_size; 2711 for (size_t i = branch_count; i > 0; ) { 2712 Branch& branch = branches_[--i]; 2713 CHECK_GE(end, branch.GetOldEndLocation()); 2714 uint32_t size = end - branch.GetOldEndLocation(); 2715 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); 2716 end = branch.GetOldLocation(); 2717 } 2718 } 2719 } 2720 2721 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 2722 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = { 2723 // R2 short branches. 2724 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch 2725 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch 2726 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall 2727 // R2 near label. 2728 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel 2729 // R2 near literal. 2730 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral 2731 // R2 long branches. 2732 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch 2733 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch 2734 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall 2735 // R2 far label. 2736 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel 2737 // R2 far literal. 2738 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral 2739 // R6 short branches. 2740 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch 2741 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch 2742 // Exception: kOffset23 for beqzc/bnezc. 2743 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call 2744 // R6 near label. 2745 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label 2746 // R6 near literal. 2747 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal 2748 // R6 long branches. 2749 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch 2750 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch 2751 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall 2752 // R6 far label. 2753 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel 2754 // R6 far literal. 2755 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral 2756 }; 2757 2758 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 2759 void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { 2760 CHECK_EQ(overwriting_, true); 2761 overwrite_location_ = branch->GetLocation(); 2762 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch)); 2763 BranchCondition condition = branch->GetCondition(); 2764 Register lhs = branch->GetLeftRegister(); 2765 Register rhs = branch->GetRightRegister(); 2766 uint32_t delayed_instruction = branch->GetDelayedInstruction(); 2767 switch (branch->GetType()) { 2768 // R2 short branches. 2769 case Branch::kUncondBranch: 2770 if (delayed_instruction == Branch::kUnfillableDelaySlot) { 2771 // The branch was created when reordering was disabled, do not absorb the target 2772 // instruction. 2773 delayed_instruction = 0; // NOP. 2774 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) { 2775 // Try to absorb the target instruction into the delay slot. 2776 delayed_instruction = 0; // NOP. 2777 // Incrementing the signed 16-bit offset past the target instruction must not 2778 // cause overflow into the negative subrange, check for the max offset. 2779 if (offset != 0x7FFF) { 2780 uint32_t target = branch->GetTarget(); 2781 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) { 2782 delayed_instruction = buffer_.Load<uint32_t>(target); 2783 offset++; 2784 } 2785 } 2786 } 2787 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2788 B(offset); 2789 Emit(delayed_instruction); 2790 break; 2791 case Branch::kCondBranch: 2792 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2793 if (delayed_instruction == Branch::kUnfilledDelaySlot) { 2794 delayed_instruction = 0; // NOP. 2795 } 2796 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2797 EmitBcondR2(condition, lhs, rhs, offset); 2798 Emit(delayed_instruction); 2799 break; 2800 case Branch::kCall: 2801 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2802 if (delayed_instruction == Branch::kUnfilledDelaySlot) { 2803 delayed_instruction = 0; // NOP. 2804 } 2805 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2806 Bal(offset); 2807 Emit(delayed_instruction); 2808 break; 2809 2810 // R2 near label. 2811 case Branch::kLabel: 2812 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2813 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2814 Addiu(lhs, rhs, offset); 2815 break; 2816 // R2 near literal. 2817 case Branch::kLiteral: 2818 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2819 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2820 Lw(lhs, rhs, offset); 2821 break; 2822 2823 // R2 long branches. 2824 case Branch::kLongUncondBranch: 2825 // To get the value of the PC register we need to use the NAL instruction. 2826 // NAL clobbers the RA register. However, RA must be preserved if the 2827 // method is compiled without the entry/exit sequences that would take care 2828 // of preserving RA (typically, leaf methods don't preserve RA explicitly). 2829 // So, we need to preserve RA in some temporary storage ourselves. The AT 2830 // register can't be used for this because we need it to load a constant 2831 // which will be added to the value that NAL stores in RA. And we can't 2832 // use T9 for this in the context of the JNI compiler, which uses it 2833 // as a scratch register (see InterproceduralScratchRegister()). 2834 // If we were to add a 32-bit constant to RA using two ADDIU instructions, 2835 // we'd also need to use the ROTR instruction, which requires no less than 2836 // MIPSR2. 2837 // Perhaps, we could use T8 or one of R2's multiplier/divider registers 2838 // (LO or HI) or even a floating-point register, but that doesn't seem 2839 // like a nice solution. We may want this to work on both R6 and pre-R6. 2840 // For now simply use the stack for RA. This should be OK since for the 2841 // vast majority of code a short PC-relative branch is sufficient. 2842 // TODO: can this be improved? 2843 // TODO: consider generation of a shorter sequence when we know that RA 2844 // is explicitly preserved by the method entry/exit code. 2845 if (delayed_instruction != Branch::kUnfilledDelaySlot && 2846 delayed_instruction != Branch::kUnfillableDelaySlot) { 2847 Emit(delayed_instruction); 2848 } 2849 Push(RA); 2850 Nal(); 2851 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2852 Lui(AT, High16Bits(offset)); 2853 Ori(AT, AT, Low16Bits(offset)); 2854 Addu(AT, AT, RA); 2855 Lw(RA, SP, 0); 2856 Jr(AT); 2857 DecreaseFrameSize(kMipsWordSize); 2858 break; 2859 case Branch::kLongCondBranch: 2860 // The comment on case 'Branch::kLongUncondBranch' applies here as well. 2861 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2862 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 2863 Emit(delayed_instruction); 2864 } 2865 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the 2866 // number of instructions skipped: 2867 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). 2868 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); 2869 Push(RA); 2870 Nal(); 2871 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2872 Lui(AT, High16Bits(offset)); 2873 Ori(AT, AT, Low16Bits(offset)); 2874 Addu(AT, AT, RA); 2875 Lw(RA, SP, 0); 2876 Jr(AT); 2877 DecreaseFrameSize(kMipsWordSize); 2878 break; 2879 case Branch::kLongCall: 2880 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2881 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 2882 Emit(delayed_instruction); 2883 } 2884 Nal(); 2885 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2886 Lui(AT, High16Bits(offset)); 2887 Ori(AT, AT, Low16Bits(offset)); 2888 Addu(AT, AT, RA); 2889 Jalr(AT); 2890 Nop(); 2891 break; 2892 2893 // R2 far label. 2894 case Branch::kFarLabel: 2895 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2896 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2897 Lui(AT, High16Bits(offset)); 2898 Ori(AT, AT, Low16Bits(offset)); 2899 Addu(lhs, AT, rhs); 2900 break; 2901 // R2 far literal. 2902 case Branch::kFarLiteral: 2903 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2904 offset += (offset & 0x8000) << 1; // Account for sign extension in lw. 2905 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2906 Lui(AT, High16Bits(offset)); 2907 Addu(AT, AT, rhs); 2908 Lw(lhs, AT, Low16Bits(offset)); 2909 break; 2910 2911 // R6 short branches. 2912 case Branch::kR6UncondBranch: 2913 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2914 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2915 Bc(offset); 2916 break; 2917 case Branch::kR6CondBranch: 2918 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2919 EmitBcondR6(condition, lhs, rhs, offset); 2920 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2921 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 2922 Emit(delayed_instruction); 2923 } else { 2924 // TODO: improve by filling the forbidden slot (IFF this is 2925 // a forbidden and not a delay slot). 2926 Nop(); 2927 } 2928 break; 2929 case Branch::kR6Call: 2930 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2931 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2932 Balc(offset); 2933 break; 2934 2935 // R6 near label. 2936 case Branch::kR6Label: 2937 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2938 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2939 Addiupc(lhs, offset); 2940 break; 2941 // R6 near literal. 2942 case Branch::kR6Literal: 2943 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2944 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2945 Lwpc(lhs, offset); 2946 break; 2947 2948 // R6 long branches. 2949 case Branch::kR6LongUncondBranch: 2950 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2951 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 2952 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2953 Auipc(AT, High16Bits(offset)); 2954 Jic(AT, Low16Bits(offset)); 2955 break; 2956 case Branch::kR6LongCondBranch: 2957 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 2958 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 2959 Emit(delayed_instruction); 2960 } 2961 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); 2962 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 2963 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2964 Auipc(AT, High16Bits(offset)); 2965 Jic(AT, Low16Bits(offset)); 2966 break; 2967 case Branch::kR6LongCall: 2968 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2969 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc. 2970 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2971 Auipc(AT, High16Bits(offset)); 2972 Jialc(AT, Low16Bits(offset)); 2973 break; 2974 2975 // R6 far label. 2976 case Branch::kR6FarLabel: 2977 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2978 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu. 2979 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2980 Auipc(AT, High16Bits(offset)); 2981 Addiu(lhs, AT, Low16Bits(offset)); 2982 break; 2983 // R6 far literal. 2984 case Branch::kR6FarLiteral: 2985 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 2986 offset += (offset & 0x8000) << 1; // Account for sign extension in lw. 2987 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2988 Auipc(AT, High16Bits(offset)); 2989 Lw(lhs, AT, Low16Bits(offset)); 2990 break; 2991 } 2992 CHECK_EQ(overwrite_location_, branch->GetEndLocation()); 2993 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); 2994 } 2995 2996 void MipsAssembler::B(MipsLabel* label) { 2997 Buncond(label); 2998 } 2999 3000 void MipsAssembler::Bal(MipsLabel* label) { 3001 Call(label); 3002 } 3003 3004 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) { 3005 Bcond(label, kCondEQ, rs, rt); 3006 } 3007 3008 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) { 3009 Bcond(label, kCondNE, rs, rt); 3010 } 3011 3012 void MipsAssembler::Beqz(Register rt, MipsLabel* label) { 3013 Bcond(label, kCondEQZ, rt); 3014 } 3015 3016 void MipsAssembler::Bnez(Register rt, MipsLabel* label) { 3017 Bcond(label, kCondNEZ, rt); 3018 } 3019 3020 void MipsAssembler::Bltz(Register rt, MipsLabel* label) { 3021 Bcond(label, kCondLTZ, rt); 3022 } 3023 3024 void MipsAssembler::Bgez(Register rt, MipsLabel* label) { 3025 Bcond(label, kCondGEZ, rt); 3026 } 3027 3028 void MipsAssembler::Blez(Register rt, MipsLabel* label) { 3029 Bcond(label, kCondLEZ, rt); 3030 } 3031 3032 void MipsAssembler::Bgtz(Register rt, MipsLabel* label) { 3033 Bcond(label, kCondGTZ, rt); 3034 } 3035 3036 bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const { 3037 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u] 3038 // instruction because either slt[u] depends on `rs` or `rt` or the following 3039 // conditional branch depends on AT set by slt[u]. 3040 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u] 3041 // because slt[u] changes AT. 3042 return (delay_slot_.instruction_ != 0 && 3043 (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 && 3044 (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0); 3045 } 3046 3047 void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) { 3048 // Exchange the last two instructions in the assembler buffer. 3049 size_t size = buffer_.Size(); 3050 CHECK_GE(size, 2 * sizeof(uint32_t)); 3051 size_t pos1 = size - 2 * sizeof(uint32_t); 3052 size_t pos2 = size - sizeof(uint32_t); 3053 uint32_t instr1 = buffer_.Load<uint32_t>(pos1); 3054 uint32_t instr2 = buffer_.Load<uint32_t>(pos2); 3055 CHECK_EQ(instr1, forwarded_slot.instruction_); 3056 CHECK_EQ(instr2, delay_slot_.instruction_); 3057 buffer_.Store<uint32_t>(pos1, instr2); 3058 buffer_.Store<uint32_t>(pos2, instr1); 3059 // Set the current delay slot information to that of the last instruction 3060 // in the buffer. 3061 delay_slot_ = forwarded_slot; 3062 } 3063 3064 void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) { 3065 // If possible, exchange the slt[u] instruction with the preceding instruction, 3066 // so it can fill the delay slot. 3067 DelaySlot forwarded_slot = delay_slot_; 3068 bool exchange = CanExchangeWithSlt(rs, rt); 3069 if (exchange) { 3070 // The last instruction cannot be used in a different delay slot, 3071 // do not commit the label before it (if any). 3072 DsFsmDropLabel(); 3073 } 3074 if (unsigned_slt) { 3075 Sltu(AT, rs, rt); 3076 } else { 3077 Slt(AT, rs, rt); 3078 } 3079 if (exchange) { 3080 ExchangeWithSlt(forwarded_slot); 3081 } 3082 } 3083 3084 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) { 3085 if (IsR6()) { 3086 Bcond(label, kCondLT, rs, rt); 3087 } else if (!Branch::IsNop(kCondLT, rs, rt)) { 3088 // Synthesize the instruction (not available on R2). 3089 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt); 3090 Bnez(AT, label); 3091 } 3092 } 3093 3094 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) { 3095 if (IsR6()) { 3096 Bcond(label, kCondGE, rs, rt); 3097 } else if (Branch::IsUncond(kCondGE, rs, rt)) { 3098 B(label); 3099 } else { 3100 // Synthesize the instruction (not available on R2). 3101 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt); 3102 Beqz(AT, label); 3103 } 3104 } 3105 3106 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) { 3107 if (IsR6()) { 3108 Bcond(label, kCondLTU, rs, rt); 3109 } else if (!Branch::IsNop(kCondLTU, rs, rt)) { 3110 // Synthesize the instruction (not available on R2). 3111 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt); 3112 Bnez(AT, label); 3113 } 3114 } 3115 3116 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) { 3117 if (IsR6()) { 3118 Bcond(label, kCondGEU, rs, rt); 3119 } else if (Branch::IsUncond(kCondGEU, rs, rt)) { 3120 B(label); 3121 } else { 3122 // Synthesize the instruction (not available on R2). 3123 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt); 3124 Beqz(AT, label); 3125 } 3126 } 3127 3128 void MipsAssembler::Bc1f(MipsLabel* label) { 3129 Bc1f(0, label); 3130 } 3131 3132 void MipsAssembler::Bc1f(int cc, MipsLabel* label) { 3133 CHECK(IsUint<3>(cc)) << cc; 3134 Bcond(label, kCondF, static_cast<Register>(cc), ZERO); 3135 } 3136 3137 void MipsAssembler::Bc1t(MipsLabel* label) { 3138 Bc1t(0, label); 3139 } 3140 3141 void MipsAssembler::Bc1t(int cc, MipsLabel* label) { 3142 CHECK(IsUint<3>(cc)) << cc; 3143 Bcond(label, kCondT, static_cast<Register>(cc), ZERO); 3144 } 3145 3146 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) { 3147 Bcond(label, kCondF, static_cast<Register>(ft), ZERO); 3148 } 3149 3150 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) { 3151 Bcond(label, kCondT, static_cast<Register>(ft), ZERO); 3152 } 3153 3154 void MipsAssembler::AdjustBaseAndOffset(Register& base, 3155 int32_t& offset, 3156 bool is_doubleword, 3157 bool is_float) { 3158 // This method is used to adjust the base register and offset pair 3159 // for a load/store when the offset doesn't fit into int16_t. 3160 // It is assumed that `base + offset` is sufficiently aligned for memory 3161 // operands that are machine word in size or smaller. For doubleword-sized 3162 // operands it's assumed that `base` is a multiple of 8, while `offset` 3163 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments 3164 // and spilled variables on the stack accessed relative to the stack 3165 // pointer register). 3166 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8. 3167 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`. 3168 3169 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset); 3170 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned); 3171 3172 // IsInt<16> must be passed a signed value, hence the static cast below. 3173 if (IsInt<16>(offset) && 3174 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 3175 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t. 3176 return; 3177 } 3178 3179 // Remember the "(mis)alignment" of `offset`, it will be checked at the end. 3180 uint32_t misalignment = offset & (kMipsDoublewordSize - 1); 3181 3182 // Do not load the whole 32-bit `offset` if it can be represented as 3183 // a sum of two 16-bit signed offsets. This can save an instruction or two. 3184 // To simplify matters, only do this for a symmetric range of offsets from 3185 // about -64KB to about +64KB, allowing further addition of 4 when accessing 3186 // 64-bit variables with two 32-bit accesses. 3187 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8. 3188 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment; 3189 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) { 3190 Addiu(AT, base, kMinOffsetForSimpleAdjustment); 3191 offset -= kMinOffsetForSimpleAdjustment; 3192 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { 3193 Addiu(AT, base, -kMinOffsetForSimpleAdjustment); 3194 offset += kMinOffsetForSimpleAdjustment; 3195 } else if (IsR6()) { 3196 // On R6 take advantage of the aui instruction, e.g.: 3197 // aui AT, base, offset_high 3198 // lw reg_lo, offset_low(AT) 3199 // lw reg_hi, (offset_low+4)(AT) 3200 // or when offset_low+4 overflows int16_t: 3201 // aui AT, base, offset_high 3202 // addiu AT, AT, 8 3203 // lw reg_lo, (offset_low-8)(AT) 3204 // lw reg_hi, (offset_low-4)(AT) 3205 int16_t offset_high = High16Bits(offset); 3206 int16_t offset_low = Low16Bits(offset); 3207 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store. 3208 Aui(AT, base, offset_high); 3209 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) { 3210 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4. 3211 Addiu(AT, AT, kMipsDoublewordSize); 3212 offset_low -= kMipsDoublewordSize; 3213 } 3214 offset = offset_low; 3215 } else { 3216 // Do not load the whole 32-bit `offset` if it can be represented as 3217 // a sum of three 16-bit signed offsets. This can save an instruction. 3218 // To simplify matters, only do this for a symmetric range of offsets from 3219 // about -96KB to about +96KB, allowing further addition of 4 when accessing 3220 // 64-bit variables with two 32-bit accesses. 3221 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment; 3222 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment; 3223 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) { 3224 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2); 3225 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2); 3226 offset -= kMinOffsetForMediumAdjustment; 3227 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) { 3228 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2); 3229 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2); 3230 offset += kMinOffsetForMediumAdjustment; 3231 } else { 3232 // Now that all shorter options have been exhausted, load the full 32-bit offset. 3233 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize); 3234 LoadConst32(AT, loaded_offset); 3235 Addu(AT, AT, base); 3236 offset -= loaded_offset; 3237 } 3238 } 3239 base = AT; 3240 3241 CHECK(IsInt<16>(offset)); 3242 if (two_accesses) { 3243 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))); 3244 } 3245 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1)); 3246 } 3247 3248 void MipsAssembler::LoadFromOffset(LoadOperandType type, 3249 Register reg, 3250 Register base, 3251 int32_t offset) { 3252 LoadFromOffset<>(type, reg, base, offset); 3253 } 3254 3255 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { 3256 LoadSFromOffset<>(reg, base, offset); 3257 } 3258 3259 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) { 3260 LoadDFromOffset<>(reg, base, offset); 3261 } 3262 3263 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, 3264 size_t size) { 3265 MipsManagedRegister dst = m_dst.AsMips(); 3266 if (dst.IsNoRegister()) { 3267 CHECK_EQ(0u, size) << dst; 3268 } else if (dst.IsCoreRegister()) { 3269 CHECK_EQ(kMipsWordSize, size) << dst; 3270 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); 3271 } else if (dst.IsRegisterPair()) { 3272 CHECK_EQ(kMipsDoublewordSize, size) << dst; 3273 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset); 3274 } else if (dst.IsFRegister()) { 3275 if (size == kMipsWordSize) { 3276 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); 3277 } else { 3278 CHECK_EQ(kMipsDoublewordSize, size) << dst; 3279 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset); 3280 } 3281 } else if (dst.IsDRegister()) { 3282 CHECK_EQ(kMipsDoublewordSize, size) << dst; 3283 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset); 3284 } 3285 } 3286 3287 void MipsAssembler::StoreToOffset(StoreOperandType type, 3288 Register reg, 3289 Register base, 3290 int32_t offset) { 3291 StoreToOffset<>(type, reg, base, offset); 3292 } 3293 3294 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { 3295 StoreSToOffset<>(reg, base, offset); 3296 } 3297 3298 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) { 3299 StoreDToOffset<>(reg, base, offset); 3300 } 3301 3302 static dwarf::Reg DWARFReg(Register reg) { 3303 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 3304 } 3305 3306 constexpr size_t kFramePointerSize = 4; 3307 3308 void MipsAssembler::BuildFrame(size_t frame_size, 3309 ManagedRegister method_reg, 3310 ArrayRef<const ManagedRegister> callee_save_regs, 3311 const ManagedRegisterEntrySpills& entry_spills) { 3312 CHECK_ALIGNED(frame_size, kStackAlignment); 3313 DCHECK(!overwriting_); 3314 3315 // Increase frame to required size. 3316 IncreaseFrameSize(frame_size); 3317 3318 // Push callee saves and return address. 3319 int stack_offset = frame_size - kFramePointerSize; 3320 StoreToOffset(kStoreWord, RA, SP, stack_offset); 3321 cfi_.RelOffset(DWARFReg(RA), stack_offset); 3322 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 3323 stack_offset -= kFramePointerSize; 3324 Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); 3325 StoreToOffset(kStoreWord, reg, SP, stack_offset); 3326 cfi_.RelOffset(DWARFReg(reg), stack_offset); 3327 } 3328 3329 // Write out Method*. 3330 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); 3331 3332 // Write out entry spills. 3333 int32_t offset = frame_size + kFramePointerSize; 3334 for (size_t i = 0; i < entry_spills.size(); ++i) { 3335 MipsManagedRegister reg = entry_spills.at(i).AsMips(); 3336 if (reg.IsNoRegister()) { 3337 ManagedRegisterSpill spill = entry_spills.at(i); 3338 offset += spill.getSize(); 3339 } else if (reg.IsCoreRegister()) { 3340 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); 3341 offset += kMipsWordSize; 3342 } else if (reg.IsFRegister()) { 3343 StoreSToOffset(reg.AsFRegister(), SP, offset); 3344 offset += kMipsWordSize; 3345 } else if (reg.IsDRegister()) { 3346 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset); 3347 offset += kMipsDoublewordSize; 3348 } 3349 } 3350 } 3351 3352 void MipsAssembler::RemoveFrame(size_t frame_size, 3353 ArrayRef<const ManagedRegister> callee_save_regs) { 3354 CHECK_ALIGNED(frame_size, kStackAlignment); 3355 DCHECK(!overwriting_); 3356 cfi_.RememberState(); 3357 3358 // Pop callee saves and return address. 3359 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 3360 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 3361 Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); 3362 LoadFromOffset(kLoadWord, reg, SP, stack_offset); 3363 cfi_.Restore(DWARFReg(reg)); 3364 stack_offset += kFramePointerSize; 3365 } 3366 LoadFromOffset(kLoadWord, RA, SP, stack_offset); 3367 cfi_.Restore(DWARFReg(RA)); 3368 3369 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI. 3370 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size)); 3371 bool reordering = SetReorder(false); 3372 if (exchange) { 3373 // Jump to the return address. 3374 Jr(RA); 3375 // Decrease frame to required size. 3376 DecreaseFrameSize(frame_size); // Single instruction in delay slot. 3377 } else { 3378 // Decrease frame to required size. 3379 DecreaseFrameSize(frame_size); 3380 // Jump to the return address. 3381 Jr(RA); 3382 Nop(); // In delay slot. 3383 } 3384 SetReorder(reordering); 3385 3386 // The CFI should be restored for any code that follows the exit block. 3387 cfi_.RestoreState(); 3388 cfi_.DefCFAOffset(frame_size); 3389 } 3390 3391 void MipsAssembler::IncreaseFrameSize(size_t adjust) { 3392 CHECK_ALIGNED(adjust, kFramePointerSize); 3393 Addiu32(SP, SP, -adjust); 3394 cfi_.AdjustCFAOffset(adjust); 3395 if (overwriting_) { 3396 cfi_.OverrideDelayedPC(overwrite_location_); 3397 } 3398 } 3399 3400 void MipsAssembler::DecreaseFrameSize(size_t adjust) { 3401 CHECK_ALIGNED(adjust, kFramePointerSize); 3402 Addiu32(SP, SP, adjust); 3403 cfi_.AdjustCFAOffset(-adjust); 3404 if (overwriting_) { 3405 cfi_.OverrideDelayedPC(overwrite_location_); 3406 } 3407 } 3408 3409 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 3410 MipsManagedRegister src = msrc.AsMips(); 3411 if (src.IsNoRegister()) { 3412 CHECK_EQ(0u, size); 3413 } else if (src.IsCoreRegister()) { 3414 CHECK_EQ(kMipsWordSize, size); 3415 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 3416 } else if (src.IsRegisterPair()) { 3417 CHECK_EQ(kMipsDoublewordSize, size); 3418 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); 3419 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), 3420 SP, dest.Int32Value() + kMipsWordSize); 3421 } else if (src.IsFRegister()) { 3422 if (size == kMipsWordSize) { 3423 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); 3424 } else { 3425 CHECK_EQ(kMipsDoublewordSize, size); 3426 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value()); 3427 } 3428 } else if (src.IsDRegister()) { 3429 CHECK_EQ(kMipsDoublewordSize, size); 3430 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value()); 3431 } 3432 } 3433 3434 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 3435 MipsManagedRegister src = msrc.AsMips(); 3436 CHECK(src.IsCoreRegister()); 3437 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 3438 } 3439 3440 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 3441 MipsManagedRegister src = msrc.AsMips(); 3442 CHECK(src.IsCoreRegister()); 3443 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 3444 } 3445 3446 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 3447 ManagedRegister mscratch) { 3448 MipsManagedRegister scratch = mscratch.AsMips(); 3449 CHECK(scratch.IsCoreRegister()) << scratch; 3450 LoadConst32(scratch.AsCoreRegister(), imm); 3451 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 3452 } 3453 3454 void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs, 3455 FrameOffset fr_offs, 3456 ManagedRegister mscratch) { 3457 MipsManagedRegister scratch = mscratch.AsMips(); 3458 CHECK(scratch.IsCoreRegister()) << scratch; 3459 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); 3460 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 3461 S1, thr_offs.Int32Value()); 3462 } 3463 3464 void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) { 3465 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 3466 } 3467 3468 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 3469 FrameOffset in_off, ManagedRegister mscratch) { 3470 MipsManagedRegister src = msrc.AsMips(); 3471 MipsManagedRegister scratch = mscratch.AsMips(); 3472 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 3473 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); 3474 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 3475 } 3476 3477 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 3478 return EmitLoad(mdest, SP, src.Int32Value(), size); 3479 } 3480 3481 void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) { 3482 return EmitLoad(mdest, S1, src.Int32Value(), size); 3483 } 3484 3485 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 3486 MipsManagedRegister dest = mdest.AsMips(); 3487 CHECK(dest.IsCoreRegister()); 3488 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); 3489 } 3490 3491 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 3492 bool unpoison_reference) { 3493 MipsManagedRegister dest = mdest.AsMips(); 3494 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 3495 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 3496 base.AsMips().AsCoreRegister(), offs.Int32Value()); 3497 if (unpoison_reference) { 3498 MaybeUnpoisonHeapReference(dest.AsCoreRegister()); 3499 } 3500 } 3501 3502 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) { 3503 MipsManagedRegister dest = mdest.AsMips(); 3504 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 3505 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 3506 base.AsMips().AsCoreRegister(), offs.Int32Value()); 3507 } 3508 3509 void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) { 3510 MipsManagedRegister dest = mdest.AsMips(); 3511 CHECK(dest.IsCoreRegister()); 3512 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); 3513 } 3514 3515 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 3516 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 3517 } 3518 3519 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 3520 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 3521 } 3522 3523 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 3524 MipsManagedRegister dest = mdest.AsMips(); 3525 MipsManagedRegister src = msrc.AsMips(); 3526 if (!dest.Equals(src)) { 3527 if (dest.IsCoreRegister()) { 3528 CHECK(src.IsCoreRegister()) << src; 3529 Move(dest.AsCoreRegister(), src.AsCoreRegister()); 3530 } else if (dest.IsFRegister()) { 3531 CHECK(src.IsFRegister()) << src; 3532 if (size == kMipsWordSize) { 3533 MovS(dest.AsFRegister(), src.AsFRegister()); 3534 } else { 3535 CHECK_EQ(kMipsDoublewordSize, size); 3536 MovD(dest.AsFRegister(), src.AsFRegister()); 3537 } 3538 } else if (dest.IsDRegister()) { 3539 CHECK(src.IsDRegister()) << src; 3540 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow()); 3541 } else { 3542 CHECK(dest.IsRegisterPair()) << dest; 3543 CHECK(src.IsRegisterPair()) << src; 3544 // Ensure that the first move doesn't clobber the input of the second. 3545 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { 3546 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 3547 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 3548 } else { 3549 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 3550 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 3551 } 3552 } 3553 } 3554 } 3555 3556 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { 3557 MipsManagedRegister scratch = mscratch.AsMips(); 3558 CHECK(scratch.IsCoreRegister()) << scratch; 3559 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 3560 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 3561 } 3562 3563 void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs, 3564 ThreadOffset32 thr_offs, 3565 ManagedRegister mscratch) { 3566 MipsManagedRegister scratch = mscratch.AsMips(); 3567 CHECK(scratch.IsCoreRegister()) << scratch; 3568 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 3569 S1, thr_offs.Int32Value()); 3570 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 3571 SP, fr_offs.Int32Value()); 3572 } 3573 3574 void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs, 3575 FrameOffset fr_offs, 3576 ManagedRegister mscratch) { 3577 MipsManagedRegister scratch = mscratch.AsMips(); 3578 CHECK(scratch.IsCoreRegister()) << scratch; 3579 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 3580 SP, fr_offs.Int32Value()); 3581 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 3582 S1, thr_offs.Int32Value()); 3583 } 3584 3585 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) { 3586 MipsManagedRegister scratch = mscratch.AsMips(); 3587 CHECK(scratch.IsCoreRegister()) << scratch; 3588 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size; 3589 if (size == kMipsWordSize) { 3590 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 3591 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 3592 } else if (size == kMipsDoublewordSize) { 3593 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 3594 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 3595 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize); 3596 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 3597 } 3598 } 3599 3600 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 3601 ManagedRegister mscratch, size_t size) { 3602 Register scratch = mscratch.AsMips().AsCoreRegister(); 3603 CHECK_EQ(size, kMipsWordSize); 3604 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); 3605 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); 3606 } 3607 3608 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 3609 ManagedRegister mscratch, size_t size) { 3610 Register scratch = mscratch.AsMips().AsCoreRegister(); 3611 CHECK_EQ(size, kMipsWordSize); 3612 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 3613 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 3614 } 3615 3616 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 3617 FrameOffset src_base ATTRIBUTE_UNUSED, 3618 Offset src_offset ATTRIBUTE_UNUSED, 3619 ManagedRegister mscratch ATTRIBUTE_UNUSED, 3620 size_t size ATTRIBUTE_UNUSED) { 3621 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 3622 } 3623 3624 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, 3625 ManagedRegister src, Offset src_offset, 3626 ManagedRegister mscratch, size_t size) { 3627 CHECK_EQ(size, kMipsWordSize); 3628 Register scratch = mscratch.AsMips().AsCoreRegister(); 3629 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); 3630 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 3631 } 3632 3633 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 3634 Offset dest_offset ATTRIBUTE_UNUSED, 3635 FrameOffset src ATTRIBUTE_UNUSED, 3636 Offset src_offset ATTRIBUTE_UNUSED, 3637 ManagedRegister mscratch ATTRIBUTE_UNUSED, 3638 size_t size ATTRIBUTE_UNUSED) { 3639 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 3640 } 3641 3642 void MipsAssembler::MemoryBarrier(ManagedRegister) { 3643 // TODO: sync? 3644 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 3645 } 3646 3647 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 3648 FrameOffset handle_scope_offset, 3649 ManagedRegister min_reg, 3650 bool null_allowed) { 3651 MipsManagedRegister out_reg = mout_reg.AsMips(); 3652 MipsManagedRegister in_reg = min_reg.AsMips(); 3653 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; 3654 CHECK(out_reg.IsCoreRegister()) << out_reg; 3655 if (null_allowed) { 3656 MipsLabel null_arg; 3657 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 3658 // the address in the handle scope holding the reference. 3659 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset). 3660 if (in_reg.IsNoRegister()) { 3661 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 3662 SP, handle_scope_offset.Int32Value()); 3663 in_reg = out_reg; 3664 } 3665 if (!out_reg.Equals(in_reg)) { 3666 LoadConst32(out_reg.AsCoreRegister(), 0); 3667 } 3668 Beqz(in_reg.AsCoreRegister(), &null_arg); 3669 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 3670 Bind(&null_arg); 3671 } else { 3672 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 3673 } 3674 } 3675 3676 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, 3677 FrameOffset handle_scope_offset, 3678 ManagedRegister mscratch, 3679 bool null_allowed) { 3680 MipsManagedRegister scratch = mscratch.AsMips(); 3681 CHECK(scratch.IsCoreRegister()) << scratch; 3682 if (null_allowed) { 3683 MipsLabel null_arg; 3684 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 3685 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 3686 // the address in the handle scope holding the reference. 3687 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset). 3688 Beqz(scratch.AsCoreRegister(), &null_arg); 3689 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 3690 Bind(&null_arg); 3691 } else { 3692 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 3693 } 3694 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); 3695 } 3696 3697 // Given a handle scope entry, load the associated reference. 3698 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 3699 ManagedRegister min_reg) { 3700 MipsManagedRegister out_reg = mout_reg.AsMips(); 3701 MipsManagedRegister in_reg = min_reg.AsMips(); 3702 CHECK(out_reg.IsCoreRegister()) << out_reg; 3703 CHECK(in_reg.IsCoreRegister()) << in_reg; 3704 MipsLabel null_arg; 3705 if (!out_reg.Equals(in_reg)) { 3706 LoadConst32(out_reg.AsCoreRegister(), 0); 3707 } 3708 Beqz(in_reg.AsCoreRegister(), &null_arg); 3709 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 3710 in_reg.AsCoreRegister(), 0); 3711 Bind(&null_arg); 3712 } 3713 3714 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 3715 bool could_be_null ATTRIBUTE_UNUSED) { 3716 // TODO: not validating references. 3717 } 3718 3719 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 3720 bool could_be_null ATTRIBUTE_UNUSED) { 3721 // TODO: not validating references. 3722 } 3723 3724 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 3725 MipsManagedRegister base = mbase.AsMips(); 3726 MipsManagedRegister scratch = mscratch.AsMips(); 3727 CHECK(base.IsCoreRegister()) << base; 3728 CHECK(scratch.IsCoreRegister()) << scratch; 3729 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 3730 base.AsCoreRegister(), offset.Int32Value()); 3731 Jalr(scratch.AsCoreRegister()); 3732 NopIfNoReordering(); 3733 // TODO: place reference map on call. 3734 } 3735 3736 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 3737 MipsManagedRegister scratch = mscratch.AsMips(); 3738 CHECK(scratch.IsCoreRegister()) << scratch; 3739 // Call *(*(SP + base) + offset) 3740 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value()); 3741 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 3742 scratch.AsCoreRegister(), offset.Int32Value()); 3743 Jalr(scratch.AsCoreRegister()); 3744 NopIfNoReordering(); 3745 // TODO: place reference map on call. 3746 } 3747 3748 void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED, 3749 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 3750 UNIMPLEMENTED(FATAL) << "no mips implementation"; 3751 } 3752 3753 void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 3754 Move(tr.AsMips().AsCoreRegister(), S1); 3755 } 3756 3757 void MipsAssembler::GetCurrentThread(FrameOffset offset, 3758 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 3759 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 3760 } 3761 3762 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 3763 MipsManagedRegister scratch = mscratch.AsMips(); 3764 exception_blocks_.emplace_back(scratch, stack_adjust); 3765 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 3766 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value()); 3767 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry()); 3768 } 3769 3770 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) { 3771 Bind(exception->Entry()); 3772 if (exception->stack_adjust_ != 0) { // Fix up the frame. 3773 DecreaseFrameSize(exception->stack_adjust_); 3774 } 3775 // Pass exception object as argument. 3776 // Don't care about preserving A0 as this call won't return. 3777 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); 3778 Move(A0, exception->scratch_.AsCoreRegister()); 3779 // Set up call to Thread::Current()->pDeliverException. 3780 LoadFromOffset(kLoadWord, T9, S1, 3781 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value()); 3782 Jr(T9); 3783 NopIfNoReordering(); 3784 3785 // Call never returns. 3786 Break(); 3787 } 3788 3789 } // namespace mips 3790 } // namespace art 3791