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 patcher_label_(nullptr) {} 46 47 InOutRegMasks& MipsAssembler::DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label) { 48 if (!reordering_) { 49 CHECK_EQ(ds_fsm_state_, kExpectingLabel); 50 CHECK_EQ(delay_slot_.instruction_, 0u); 51 return delay_slot_.masks_; 52 } 53 switch (ds_fsm_state_) { 54 case kExpectingLabel: 55 break; 56 case kExpectingInstruction: 57 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); 58 // If the last instruction is not suitable for delay slots, drop 59 // the PC of the label preceding it so that no unconditional branch 60 // uses this instruction to fill its delay slot. 61 if (instruction == 0) { 62 DsFsmDropLabel(); // Sets ds_fsm_state_ = kExpectingLabel. 63 } else { 64 // Otherwise wait for another instruction or label before we can 65 // commit the label PC. The label PC will be dropped if instead 66 // of another instruction or label there's a call from the code 67 // generator to CodePosition() to record the buffer size. 68 // Instructions after which the buffer size is recorded cannot 69 // be moved into delay slots or anywhere else because they may 70 // trigger signals and the signal handlers expect these signals 71 // to be coming from the instructions immediately preceding the 72 // recorded buffer locations. 73 ds_fsm_state_ = kExpectingCommit; 74 } 75 break; 76 case kExpectingCommit: 77 CHECK_EQ(ds_fsm_target_pc_ + 2 * sizeof(uint32_t), buffer_.Size()); 78 DsFsmCommitLabel(); // Sets ds_fsm_state_ = kExpectingLabel. 79 break; 80 } 81 delay_slot_.instruction_ = instruction; 82 delay_slot_.masks_ = InOutRegMasks(); 83 delay_slot_.patcher_label_ = patcher_label; 84 return delay_slot_.masks_; 85 } 86 87 void MipsAssembler::DsFsmLabel() { 88 if (!reordering_) { 89 CHECK_EQ(ds_fsm_state_, kExpectingLabel); 90 CHECK_EQ(delay_slot_.instruction_, 0u); 91 return; 92 } 93 switch (ds_fsm_state_) { 94 case kExpectingLabel: 95 ds_fsm_target_pc_ = buffer_.Size(); 96 ds_fsm_state_ = kExpectingInstruction; 97 break; 98 case kExpectingInstruction: 99 // Allow consecutive labels. 100 CHECK_EQ(ds_fsm_target_pc_, buffer_.Size()); 101 break; 102 case kExpectingCommit: 103 CHECK_EQ(ds_fsm_target_pc_ + sizeof(uint32_t), buffer_.Size()); 104 DsFsmCommitLabel(); 105 ds_fsm_target_pc_ = buffer_.Size(); 106 ds_fsm_state_ = kExpectingInstruction; 107 break; 108 } 109 // We cannot move instructions into delay slots across labels. 110 delay_slot_.instruction_ = 0; 111 } 112 113 void MipsAssembler::DsFsmCommitLabel() { 114 if (ds_fsm_state_ == kExpectingCommit) { 115 ds_fsm_target_pcs_.emplace_back(ds_fsm_target_pc_); 116 } 117 ds_fsm_state_ = kExpectingLabel; 118 } 119 120 void MipsAssembler::DsFsmDropLabel() { 121 ds_fsm_state_ = kExpectingLabel; 122 } 123 124 bool MipsAssembler::SetReorder(bool enable) { 125 bool last_state = reordering_; 126 if (last_state != enable) { 127 DsFsmCommitLabel(); 128 DsFsmInstrNop(0); 129 } 130 reordering_ = enable; 131 return last_state; 132 } 133 134 size_t MipsAssembler::CodePosition() { 135 // The last instruction cannot be used in a delay slot, do not commit 136 // the label before it (if any) and clear the delay slot. 137 DsFsmDropLabel(); 138 DsFsmInstrNop(0); 139 size_t size = buffer_.Size(); 140 // In theory we can get the following sequence: 141 // label1: 142 // instr 143 // label2: # label1 gets committed when label2 is seen 144 // CodePosition() call 145 // and we need to uncommit label1. 146 if (ds_fsm_target_pcs_.size() != 0 && ds_fsm_target_pcs_.back() + sizeof(uint32_t) == size) { 147 ds_fsm_target_pcs_.pop_back(); 148 } 149 return size; 150 } 151 152 void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) { 153 DsFsmInstr(0); 154 } 155 156 void MipsAssembler::FinalizeCode() { 157 for (auto& exception_block : exception_blocks_) { 158 EmitExceptionPoll(&exception_block); 159 } 160 // Commit the last branch target label (if any) and disable instruction reordering. 161 DsFsmCommitLabel(); 162 SetReorder(false); 163 EmitLiterals(); 164 ReserveJumpTableSpace(); 165 PromoteBranches(); 166 } 167 168 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) { 169 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs(); 170 EmitBranches(); 171 EmitJumpTables(); 172 Assembler::FinalizeInstructions(region); 173 PatchCFI(number_of_delayed_adjust_pcs); 174 } 175 176 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) { 177 if (cfi().NumberOfDelayedAdvancePCs() == 0u) { 178 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u); 179 return; 180 } 181 182 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; 183 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); 184 const std::vector<uint8_t>& old_stream = data.first; 185 const std::vector<DelayedAdvancePC>& advances = data.second; 186 187 // PCs recorded before EmitBranches() need to be adjusted. 188 // PCs recorded during EmitBranches() are already adjusted. 189 // Both ranges are separately sorted but they may overlap. 190 if (kIsDebugBuild) { 191 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) { 192 return lhs.pc < rhs.pc; 193 }; 194 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp)); 195 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp)); 196 } 197 198 // Append initial CFI data if any. 199 size_t size = advances.size(); 200 DCHECK_NE(size, 0u); 201 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos); 202 // Emit PC adjustments interleaved with the old CFI stream. 203 size_t adjust_pos = 0u; 204 size_t late_emit_pos = number_of_delayed_adjust_pcs; 205 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) { 206 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs) 207 ? GetAdjustedPosition(advances[adjust_pos].pc) 208 : static_cast<size_t>(-1); 209 size_t late_emit_pc = (late_emit_pos != size) 210 ? advances[late_emit_pos].pc 211 : static_cast<size_t>(-1); 212 size_t advance_pc = std::min(adjusted_pc, late_emit_pc); 213 DCHECK_NE(advance_pc, static_cast<size_t>(-1)); 214 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos; 215 if (adjusted_pc <= late_emit_pc) { 216 ++adjust_pos; 217 } else { 218 ++late_emit_pos; 219 } 220 cfi().AdvancePC(advance_pc); 221 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos; 222 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos); 223 } 224 } 225 226 void MipsAssembler::EmitBranches() { 227 CHECK(!overwriting_); 228 CHECK(!reordering_); 229 // Now that everything has its final position in the buffer (the branches have 230 // been promoted), adjust the target label PCs. 231 for (size_t cnt = ds_fsm_target_pcs_.size(), i = 0; i < cnt; i++) { 232 ds_fsm_target_pcs_[i] = GetAdjustedPosition(ds_fsm_target_pcs_[i]); 233 } 234 // Switch from appending instructions at the end of the buffer to overwriting 235 // existing instructions (branch placeholders) in the buffer. 236 overwriting_ = true; 237 for (size_t id = 0; id < branches_.size(); id++) { 238 EmitBranch(id); 239 } 240 overwriting_ = false; 241 } 242 243 void MipsAssembler::Emit(uint32_t value) { 244 if (overwriting_) { 245 // Branches to labels are emitted into their placeholders here. 246 buffer_.Store<uint32_t>(overwrite_location_, value); 247 overwrite_location_ += sizeof(uint32_t); 248 } else { 249 // Other instructions are simply appended at the end here. 250 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 251 buffer_.Emit<uint32_t>(value); 252 } 253 } 254 255 uint32_t MipsAssembler::EmitR(int opcode, 256 Register rs, 257 Register rt, 258 Register rd, 259 int shamt, 260 int funct) { 261 CHECK_NE(rs, kNoRegister); 262 CHECK_NE(rt, kNoRegister); 263 CHECK_NE(rd, kNoRegister); 264 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 265 static_cast<uint32_t>(rs) << kRsShift | 266 static_cast<uint32_t>(rt) << kRtShift | 267 static_cast<uint32_t>(rd) << kRdShift | 268 shamt << kShamtShift | 269 funct; 270 Emit(encoding); 271 return encoding; 272 } 273 274 uint32_t MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) { 275 CHECK_NE(rs, kNoRegister); 276 CHECK_NE(rt, kNoRegister); 277 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 278 static_cast<uint32_t>(rs) << kRsShift | 279 static_cast<uint32_t>(rt) << kRtShift | 280 imm; 281 Emit(encoding); 282 return encoding; 283 } 284 285 uint32_t MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) { 286 CHECK_NE(rs, kNoRegister); 287 CHECK(IsUint<21>(imm21)) << imm21; 288 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 289 static_cast<uint32_t>(rs) << kRsShift | 290 imm21; 291 Emit(encoding); 292 return encoding; 293 } 294 295 uint32_t MipsAssembler::EmitI26(int opcode, uint32_t imm26) { 296 CHECK(IsUint<26>(imm26)) << imm26; 297 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; 298 Emit(encoding); 299 return encoding; 300 } 301 302 uint32_t MipsAssembler::EmitFR(int opcode, 303 int fmt, 304 FRegister ft, 305 FRegister fs, 306 FRegister fd, 307 int funct) { 308 CHECK_NE(ft, kNoFRegister); 309 CHECK_NE(fs, kNoFRegister); 310 CHECK_NE(fd, kNoFRegister); 311 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 312 fmt << kFmtShift | 313 static_cast<uint32_t>(ft) << kFtShift | 314 static_cast<uint32_t>(fs) << kFsShift | 315 static_cast<uint32_t>(fd) << kFdShift | 316 funct; 317 Emit(encoding); 318 return encoding; 319 } 320 321 uint32_t MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) { 322 CHECK_NE(ft, kNoFRegister); 323 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 324 fmt << kFmtShift | 325 static_cast<uint32_t>(ft) << kFtShift | 326 imm; 327 Emit(encoding); 328 return encoding; 329 } 330 331 uint32_t MipsAssembler::EmitMsa3R(int operation, 332 int df, 333 VectorRegister wt, 334 VectorRegister ws, 335 VectorRegister wd, 336 int minor_opcode) { 337 CHECK_NE(wt, kNoVectorRegister); 338 CHECK_NE(ws, kNoVectorRegister); 339 CHECK_NE(wd, kNoVectorRegister); 340 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 341 operation << kMsaOperationShift | 342 df << kDfShift | 343 static_cast<uint32_t>(wt) << kWtShift | 344 static_cast<uint32_t>(ws) << kWsShift | 345 static_cast<uint32_t>(wd) << kWdShift | 346 minor_opcode; 347 Emit(encoding); 348 return encoding; 349 } 350 351 uint32_t MipsAssembler::EmitMsaBIT(int operation, 352 int df_m, 353 VectorRegister ws, 354 VectorRegister wd, 355 int minor_opcode) { 356 CHECK_NE(ws, kNoVectorRegister); 357 CHECK_NE(wd, kNoVectorRegister); 358 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 359 operation << kMsaOperationShift | 360 df_m << kDfMShift | 361 static_cast<uint32_t>(ws) << kWsShift | 362 static_cast<uint32_t>(wd) << kWdShift | 363 minor_opcode; 364 Emit(encoding); 365 return encoding; 366 } 367 368 uint32_t MipsAssembler::EmitMsaELM(int operation, 369 int df_n, 370 VectorRegister ws, 371 VectorRegister wd, 372 int minor_opcode) { 373 CHECK_NE(ws, kNoVectorRegister); 374 CHECK_NE(wd, kNoVectorRegister); 375 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 376 operation << kMsaELMOperationShift | 377 df_n << kDfNShift | 378 static_cast<uint32_t>(ws) << kWsShift | 379 static_cast<uint32_t>(wd) << kWdShift | 380 minor_opcode; 381 Emit(encoding); 382 return encoding; 383 } 384 385 uint32_t MipsAssembler::EmitMsaMI10(int s10, 386 Register rs, 387 VectorRegister wd, 388 int minor_opcode, 389 int df) { 390 CHECK_NE(rs, kNoRegister); 391 CHECK_NE(wd, kNoVectorRegister); 392 CHECK(IsUint<10>(s10)) << s10; 393 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 394 s10 << kS10Shift | 395 static_cast<uint32_t>(rs) << kWsShift | 396 static_cast<uint32_t>(wd) << kWdShift | 397 minor_opcode << kS10MinorShift | 398 df; 399 Emit(encoding); 400 return encoding; 401 } 402 403 uint32_t MipsAssembler::EmitMsaI10(int operation, 404 int df, 405 int i10, 406 VectorRegister wd, 407 int minor_opcode) { 408 CHECK_NE(wd, kNoVectorRegister); 409 CHECK(IsUint<10>(i10)) << i10; 410 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 411 operation << kMsaOperationShift | 412 df << kDfShift | 413 i10 << kI10Shift | 414 static_cast<uint32_t>(wd) << kWdShift | 415 minor_opcode; 416 Emit(encoding); 417 return encoding; 418 } 419 420 uint32_t MipsAssembler::EmitMsa2R(int operation, 421 int df, 422 VectorRegister ws, 423 VectorRegister wd, 424 int minor_opcode) { 425 CHECK_NE(ws, kNoVectorRegister); 426 CHECK_NE(wd, kNoVectorRegister); 427 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 428 operation << kMsa2ROperationShift | 429 df << kDf2RShift | 430 static_cast<uint32_t>(ws) << kWsShift | 431 static_cast<uint32_t>(wd) << kWdShift | 432 minor_opcode; 433 Emit(encoding); 434 return encoding; 435 } 436 437 uint32_t MipsAssembler::EmitMsa2RF(int operation, 438 int df, 439 VectorRegister ws, 440 VectorRegister wd, 441 int minor_opcode) { 442 CHECK_NE(ws, kNoVectorRegister); 443 CHECK_NE(wd, kNoVectorRegister); 444 uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift | 445 operation << kMsa2RFOperationShift | 446 df << kDf2RShift | 447 static_cast<uint32_t>(ws) << kWsShift | 448 static_cast<uint32_t>(wd) << kWdShift | 449 minor_opcode; 450 Emit(encoding); 451 return encoding; 452 } 453 454 void MipsAssembler::Addu(Register rd, Register rs, Register rt) { 455 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x21)).GprOuts(rd).GprIns(rs, rt); 456 } 457 458 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { 459 if (patcher_label != nullptr) { 460 Bind(patcher_label); 461 } 462 DsFsmInstr(EmitI(0x9, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs); 463 } 464 465 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { 466 Addiu(rt, rs, imm16, /* patcher_label */ nullptr); 467 } 468 469 void MipsAssembler::Subu(Register rd, Register rs, Register rt) { 470 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x23)).GprOuts(rd).GprIns(rs, rt); 471 } 472 473 void MipsAssembler::MultR2(Register rs, Register rt) { 474 CHECK(!IsR6()); 475 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18)).GprIns(rs, rt); 476 } 477 478 void MipsAssembler::MultuR2(Register rs, Register rt) { 479 CHECK(!IsR6()); 480 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19)).GprIns(rs, rt); 481 } 482 483 void MipsAssembler::DivR2(Register rs, Register rt) { 484 CHECK(!IsR6()); 485 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a)).GprIns(rs, rt); 486 } 487 488 void MipsAssembler::DivuR2(Register rs, Register rt) { 489 CHECK(!IsR6()); 490 DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b)).GprIns(rs, rt); 491 } 492 493 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) { 494 CHECK(!IsR6()); 495 DsFsmInstr(EmitR(0x1c, rs, rt, rd, 0, 2)).GprOuts(rd).GprIns(rs, rt); 496 } 497 498 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) { 499 CHECK(!IsR6()); 500 DivR2(rs, rt); 501 Mflo(rd); 502 } 503 504 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) { 505 CHECK(!IsR6()); 506 DivR2(rs, rt); 507 Mfhi(rd); 508 } 509 510 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) { 511 CHECK(!IsR6()); 512 DivuR2(rs, rt); 513 Mflo(rd); 514 } 515 516 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) { 517 CHECK(!IsR6()); 518 DivuR2(rs, rt); 519 Mfhi(rd); 520 } 521 522 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) { 523 CHECK(IsR6()); 524 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x18)).GprOuts(rd).GprIns(rs, rt); 525 } 526 527 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) { 528 CHECK(IsR6()); 529 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x18)).GprOuts(rd).GprIns(rs, rt); 530 } 531 532 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) { 533 CHECK(IsR6()); 534 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x19)).GprOuts(rd).GprIns(rs, rt); 535 } 536 537 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) { 538 CHECK(IsR6()); 539 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1a)).GprOuts(rd).GprIns(rs, rt); 540 } 541 542 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) { 543 CHECK(IsR6()); 544 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1a)).GprOuts(rd).GprIns(rs, rt); 545 } 546 547 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) { 548 CHECK(IsR6()); 549 DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1b)).GprOuts(rd).GprIns(rs, rt); 550 } 551 552 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) { 553 CHECK(IsR6()); 554 DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1b)).GprOuts(rd).GprIns(rs, rt); 555 } 556 557 void MipsAssembler::And(Register rd, Register rs, Register rt) { 558 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x24)).GprOuts(rd).GprIns(rs, rt); 559 } 560 561 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { 562 DsFsmInstr(EmitI(0xc, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 563 } 564 565 void MipsAssembler::Or(Register rd, Register rs, Register rt) { 566 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x25)).GprOuts(rd).GprIns(rs, rt); 567 } 568 569 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { 570 DsFsmInstr(EmitI(0xd, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 571 } 572 573 void MipsAssembler::Xor(Register rd, Register rs, Register rt) { 574 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x26)).GprOuts(rd).GprIns(rs, rt); 575 } 576 577 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { 578 DsFsmInstr(EmitI(0xe, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 579 } 580 581 void MipsAssembler::Nor(Register rd, Register rs, Register rt) { 582 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x27)).GprOuts(rd).GprIns(rs, rt); 583 } 584 585 void MipsAssembler::Movz(Register rd, Register rs, Register rt) { 586 CHECK(!IsR6()); 587 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0A)).GprInOuts(rd).GprIns(rs, rt); 588 } 589 590 void MipsAssembler::Movn(Register rd, Register rs, Register rt) { 591 CHECK(!IsR6()); 592 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0B)).GprInOuts(rd).GprIns(rs, rt); 593 } 594 595 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { 596 CHECK(IsR6()); 597 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x35)).GprOuts(rd).GprIns(rs, rt); 598 } 599 600 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { 601 CHECK(IsR6()); 602 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x37)).GprOuts(rd).GprIns(rs, rt); 603 } 604 605 void MipsAssembler::ClzR6(Register rd, Register rs) { 606 CHECK(IsR6()); 607 DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10)).GprOuts(rd).GprIns(rs); 608 } 609 610 void MipsAssembler::ClzR2(Register rd, Register rs) { 611 CHECK(!IsR6()); 612 DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x20)).GprOuts(rd).GprIns(rs); 613 } 614 615 void MipsAssembler::CloR6(Register rd, Register rs) { 616 CHECK(IsR6()); 617 DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11)).GprOuts(rd).GprIns(rs); 618 } 619 620 void MipsAssembler::CloR2(Register rd, Register rs) { 621 CHECK(!IsR6()); 622 DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x21)).GprOuts(rd).GprIns(rs); 623 } 624 625 void MipsAssembler::Seb(Register rd, Register rt) { 626 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20)).GprOuts(rd).GprIns(rt); 627 } 628 629 void MipsAssembler::Seh(Register rd, Register rt) { 630 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20)).GprOuts(rd).GprIns(rt); 631 } 632 633 void MipsAssembler::Wsbh(Register rd, Register rt) { 634 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20)).GprOuts(rd).GprIns(rt); 635 } 636 637 void MipsAssembler::Bitswap(Register rd, Register rt) { 638 CHECK(IsR6()); 639 DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20)).GprOuts(rd).GprIns(rt); 640 } 641 642 void MipsAssembler::Sll(Register rd, Register rt, int shamt) { 643 CHECK(IsUint<5>(shamt)) << shamt; 644 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00)).GprOuts(rd).GprIns(rt); 645 } 646 647 void MipsAssembler::Srl(Register rd, Register rt, int shamt) { 648 CHECK(IsUint<5>(shamt)) << shamt; 649 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt); 650 } 651 652 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) { 653 CHECK(IsUint<5>(shamt)) << shamt; 654 DsFsmInstr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt); 655 } 656 657 void MipsAssembler::Sra(Register rd, Register rt, int shamt) { 658 CHECK(IsUint<5>(shamt)) << shamt; 659 DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03)).GprOuts(rd).GprIns(rt); 660 } 661 662 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) { 663 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x04)).GprOuts(rd).GprIns(rs, rt); 664 } 665 666 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { 667 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x06)).GprOuts(rd).GprIns(rs, rt); 668 } 669 670 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { 671 DsFsmInstr(EmitR(0, rs, rt, rd, 1, 0x06)).GprOuts(rd).GprIns(rs, rt); 672 } 673 674 void MipsAssembler::Srav(Register rd, Register rt, Register rs) { 675 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x07)).GprOuts(rd).GprIns(rs, rt); 676 } 677 678 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) { 679 CHECK(IsUint<5>(pos)) << pos; 680 CHECK(0 < size && size <= 32) << size; 681 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 682 DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00)) 683 .GprOuts(rd).GprIns(rt); 684 } 685 686 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) { 687 CHECK(IsUint<5>(pos)) << pos; 688 CHECK(0 < size && size <= 32) << size; 689 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 690 DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04)) 691 .GprInOuts(rd).GprIns(rt); 692 } 693 694 void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) { 695 CHECK(IsR6() || HasMsa()); 696 CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; 697 int sa = saPlusOne - 1; 698 DsFsmInstr(EmitR(0x0, rs, rt, rd, sa, 0x05)).GprOuts(rd).GprIns(rs, rt); 699 } 700 701 void MipsAssembler::ShiftAndAdd(Register dst, 702 Register src_idx, 703 Register src_base, 704 int shamt, 705 Register tmp) { 706 CHECK(0 <= shamt && shamt <= 4) << shamt; 707 CHECK_NE(src_base, tmp); 708 if (shamt == TIMES_1) { 709 // Catch the special case where the shift amount is zero (0). 710 Addu(dst, src_base, src_idx); 711 } else if (IsR6() || HasMsa()) { 712 Lsa(dst, src_idx, src_base, shamt); 713 } else { 714 Sll(tmp, src_idx, shamt); 715 Addu(dst, src_base, tmp); 716 } 717 } 718 719 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { 720 DsFsmInstr(EmitI(0x20, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 721 } 722 723 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { 724 DsFsmInstr(EmitI(0x21, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 725 } 726 727 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { 728 if (patcher_label != nullptr) { 729 Bind(patcher_label); 730 } 731 DsFsmInstr(EmitI(0x23, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs); 732 } 733 734 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { 735 Lw(rt, rs, imm16, /* patcher_label */ nullptr); 736 } 737 738 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) { 739 CHECK(!IsR6()); 740 DsFsmInstr(EmitI(0x22, rs, rt, imm16)).GprInOuts(rt).GprIns(rs); 741 } 742 743 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) { 744 CHECK(!IsR6()); 745 DsFsmInstr(EmitI(0x26, rs, rt, imm16)).GprInOuts(rt).GprIns(rs); 746 } 747 748 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { 749 DsFsmInstr(EmitI(0x24, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 750 } 751 752 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { 753 DsFsmInstr(EmitI(0x25, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 754 } 755 756 void MipsAssembler::Lwpc(Register rs, uint32_t imm19) { 757 CHECK(IsR6()); 758 CHECK(IsUint<19>(imm19)) << imm19; 759 DsFsmInstrNop(EmitI21(0x3B, rs, (0x01 << 19) | imm19)); 760 } 761 762 void MipsAssembler::Lui(Register rt, uint16_t imm16) { 763 DsFsmInstr(EmitI(0xf, static_cast<Register>(0), rt, imm16)).GprOuts(rt); 764 } 765 766 void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) { 767 CHECK(IsR6()); 768 DsFsmInstr(EmitI(0xf, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 769 } 770 771 void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) { 772 bool increment = (rs == rt); 773 if (increment) { 774 CHECK_NE(rs, tmp); 775 } 776 if (IsR6()) { 777 Aui(rt, rs, imm16); 778 } else if (increment) { 779 Lui(tmp, imm16); 780 Addu(rt, rs, tmp); 781 } else { 782 Lui(rt, imm16); 783 Addu(rt, rs, rt); 784 } 785 } 786 787 void MipsAssembler::Sync(uint32_t stype) { 788 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, stype & 0x1f, 0xf)); 789 } 790 791 void MipsAssembler::Mfhi(Register rd) { 792 CHECK(!IsR6()); 793 DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x10)).GprOuts(rd); 794 } 795 796 void MipsAssembler::Mflo(Register rd) { 797 CHECK(!IsR6()); 798 DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x12)).GprOuts(rd); 799 } 800 801 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { 802 DsFsmInstr(EmitI(0x28, rs, rt, imm16)).GprIns(rt, rs); 803 } 804 805 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { 806 DsFsmInstr(EmitI(0x29, rs, rt, imm16)).GprIns(rt, rs); 807 } 808 809 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) { 810 if (patcher_label != nullptr) { 811 Bind(patcher_label); 812 } 813 DsFsmInstr(EmitI(0x2b, rs, rt, imm16), patcher_label).GprIns(rt, rs); 814 } 815 816 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { 817 Sw(rt, rs, imm16, /* patcher_label */ nullptr); 818 } 819 820 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) { 821 CHECK(!IsR6()); 822 DsFsmInstr(EmitI(0x2a, rs, rt, imm16)).GprIns(rt, rs); 823 } 824 825 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { 826 CHECK(!IsR6()); 827 DsFsmInstr(EmitI(0x2e, rs, rt, imm16)).GprIns(rt, rs); 828 } 829 830 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) { 831 CHECK(!IsR6()); 832 DsFsmInstr(EmitI(0x30, base, rt, imm16)).GprOuts(rt).GprIns(base); 833 } 834 835 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) { 836 CHECK(!IsR6()); 837 DsFsmInstr(EmitI(0x38, base, rt, imm16)).GprInOuts(rt).GprIns(base); 838 } 839 840 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) { 841 CHECK(IsR6()); 842 CHECK(IsInt<9>(imm9)); 843 DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36)).GprOuts(rt).GprIns(base); 844 } 845 846 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) { 847 CHECK(IsR6()); 848 CHECK(IsInt<9>(imm9)); 849 DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26)).GprInOuts(rt).GprIns(base); 850 } 851 852 void MipsAssembler::Slt(Register rd, Register rs, Register rt) { 853 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2a)).GprOuts(rd).GprIns(rs, rt); 854 } 855 856 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 857 DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2b)).GprOuts(rd).GprIns(rs, rt); 858 } 859 860 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 861 DsFsmInstr(EmitI(0xa, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 862 } 863 864 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 865 DsFsmInstr(EmitI(0xb, rs, rt, imm16)).GprOuts(rt).GprIns(rs); 866 } 867 868 void MipsAssembler::B(uint16_t imm16) { 869 DsFsmInstrNop(EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16)); 870 } 871 872 void MipsAssembler::Bal(uint16_t imm16) { 873 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x11), imm16)); 874 } 875 876 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { 877 DsFsmInstrNop(EmitI(0x4, rs, rt, imm16)); 878 } 879 880 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { 881 DsFsmInstrNop(EmitI(0x5, rs, rt, imm16)); 882 } 883 884 void MipsAssembler::Beqz(Register rt, uint16_t imm16) { 885 Beq(rt, ZERO, imm16); 886 } 887 888 void MipsAssembler::Bnez(Register rt, uint16_t imm16) { 889 Bne(rt, ZERO, imm16); 890 } 891 892 void MipsAssembler::Bltz(Register rt, uint16_t imm16) { 893 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0), imm16)); 894 } 895 896 void MipsAssembler::Bgez(Register rt, uint16_t imm16) { 897 DsFsmInstrNop(EmitI(0x1, rt, static_cast<Register>(0x1), imm16)); 898 } 899 900 void MipsAssembler::Blez(Register rt, uint16_t imm16) { 901 DsFsmInstrNop(EmitI(0x6, rt, static_cast<Register>(0), imm16)); 902 } 903 904 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { 905 DsFsmInstrNop(EmitI(0x7, rt, static_cast<Register>(0), imm16)); 906 } 907 908 void MipsAssembler::Bc1f(uint16_t imm16) { 909 Bc1f(0, imm16); 910 } 911 912 void MipsAssembler::Bc1f(int cc, uint16_t imm16) { 913 CHECK(!IsR6()); 914 CHECK(IsUint<3>(cc)) << cc; 915 DsFsmInstrNop(EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16)); 916 } 917 918 void MipsAssembler::Bc1t(uint16_t imm16) { 919 Bc1t(0, imm16); 920 } 921 922 void MipsAssembler::Bc1t(int cc, uint16_t imm16) { 923 CHECK(!IsR6()); 924 CHECK(IsUint<3>(cc)) << cc; 925 DsFsmInstrNop(EmitI(0x11, 926 static_cast<Register>(0x8), 927 static_cast<Register>((cc << 2) | 1), 928 imm16)); 929 } 930 931 void MipsAssembler::J(uint32_t addr26) { 932 DsFsmInstrNop(EmitI26(0x2, addr26)); 933 } 934 935 void MipsAssembler::Jal(uint32_t addr26) { 936 DsFsmInstrNop(EmitI26(0x3, addr26)); 937 } 938 939 void MipsAssembler::Jalr(Register rd, Register rs) { 940 uint32_t last_instruction = delay_slot_.instruction_; 941 MipsLabel* patcher_label = delay_slot_.patcher_label_; 942 bool exchange = (last_instruction != 0 && 943 (delay_slot_.masks_.gpr_outs_ & (1u << rs)) == 0 && 944 ((delay_slot_.masks_.gpr_ins_ | delay_slot_.masks_.gpr_outs_) & (1u << rd)) == 0); 945 if (exchange) { 946 // The last instruction cannot be used in a different delay slot, 947 // do not commit the label before it (if any). 948 DsFsmDropLabel(); 949 } 950 DsFsmInstrNop(EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09)); 951 if (exchange) { 952 // Exchange the last two instructions in the assembler buffer. 953 size_t size = buffer_.Size(); 954 CHECK_GE(size, 2 * sizeof(uint32_t)); 955 size_t pos1 = size - 2 * sizeof(uint32_t); 956 size_t pos2 = size - sizeof(uint32_t); 957 uint32_t instr1 = buffer_.Load<uint32_t>(pos1); 958 uint32_t instr2 = buffer_.Load<uint32_t>(pos2); 959 CHECK_EQ(instr1, last_instruction); 960 buffer_.Store<uint32_t>(pos1, instr2); 961 buffer_.Store<uint32_t>(pos2, instr1); 962 // Move the patcher label along with the patched instruction. 963 if (patcher_label != nullptr) { 964 patcher_label->AdjustBoundPosition(sizeof(uint32_t)); 965 } 966 } else if (reordering_) { 967 Nop(); 968 } 969 } 970 971 void MipsAssembler::Jalr(Register rs) { 972 Jalr(RA, rs); 973 } 974 975 void MipsAssembler::Jr(Register rs) { 976 Jalr(ZERO, rs); 977 } 978 979 void MipsAssembler::Nal() { 980 DsFsmInstrNop(EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0)); 981 } 982 983 void MipsAssembler::Auipc(Register rs, uint16_t imm16) { 984 CHECK(IsR6()); 985 DsFsmInstrNop(EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16)); 986 } 987 988 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { 989 CHECK(IsR6()); 990 CHECK(IsUint<19>(imm19)) << imm19; 991 DsFsmInstrNop(EmitI21(0x3B, rs, imm19)); 992 } 993 994 void MipsAssembler::Bc(uint32_t imm26) { 995 CHECK(IsR6()); 996 DsFsmInstrNop(EmitI26(0x32, imm26)); 997 } 998 999 void MipsAssembler::Balc(uint32_t imm26) { 1000 CHECK(IsR6()); 1001 DsFsmInstrNop(EmitI26(0x3A, imm26)); 1002 } 1003 1004 void MipsAssembler::Jic(Register rt, uint16_t imm16) { 1005 CHECK(IsR6()); 1006 DsFsmInstrNop(EmitI(0x36, static_cast<Register>(0), rt, imm16)); 1007 } 1008 1009 void MipsAssembler::Jialc(Register rt, uint16_t imm16) { 1010 CHECK(IsR6()); 1011 DsFsmInstrNop(EmitI(0x3E, static_cast<Register>(0), rt, imm16)); 1012 } 1013 1014 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) { 1015 CHECK(IsR6()); 1016 CHECK_NE(rs, ZERO); 1017 CHECK_NE(rt, ZERO); 1018 CHECK_NE(rs, rt); 1019 DsFsmInstrNop(EmitI(0x17, rs, rt, imm16)); 1020 } 1021 1022 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { 1023 CHECK(IsR6()); 1024 CHECK_NE(rt, ZERO); 1025 DsFsmInstrNop(EmitI(0x17, rt, rt, imm16)); 1026 } 1027 1028 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) { 1029 CHECK(IsR6()); 1030 CHECK_NE(rt, ZERO); 1031 DsFsmInstrNop(EmitI(0x17, static_cast<Register>(0), rt, imm16)); 1032 } 1033 1034 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) { 1035 CHECK(IsR6()); 1036 CHECK_NE(rs, ZERO); 1037 CHECK_NE(rt, ZERO); 1038 CHECK_NE(rs, rt); 1039 DsFsmInstrNop(EmitI(0x16, rs, rt, imm16)); 1040 } 1041 1042 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { 1043 CHECK(IsR6()); 1044 CHECK_NE(rt, ZERO); 1045 DsFsmInstrNop(EmitI(0x16, rt, rt, imm16)); 1046 } 1047 1048 void MipsAssembler::Blezc(Register rt, uint16_t imm16) { 1049 CHECK(IsR6()); 1050 CHECK_NE(rt, ZERO); 1051 DsFsmInstrNop(EmitI(0x16, static_cast<Register>(0), rt, imm16)); 1052 } 1053 1054 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) { 1055 CHECK(IsR6()); 1056 CHECK_NE(rs, ZERO); 1057 CHECK_NE(rt, ZERO); 1058 CHECK_NE(rs, rt); 1059 DsFsmInstrNop(EmitI(0x7, rs, rt, imm16)); 1060 } 1061 1062 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) { 1063 CHECK(IsR6()); 1064 CHECK_NE(rs, ZERO); 1065 CHECK_NE(rt, ZERO); 1066 CHECK_NE(rs, rt); 1067 DsFsmInstrNop(EmitI(0x6, rs, rt, imm16)); 1068 } 1069 1070 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) { 1071 CHECK(IsR6()); 1072 CHECK_NE(rs, ZERO); 1073 CHECK_NE(rt, ZERO); 1074 CHECK_NE(rs, rt); 1075 DsFsmInstrNop(EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16)); 1076 } 1077 1078 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) { 1079 CHECK(IsR6()); 1080 CHECK_NE(rs, ZERO); 1081 CHECK_NE(rt, ZERO); 1082 CHECK_NE(rs, rt); 1083 DsFsmInstrNop(EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16)); 1084 } 1085 1086 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { 1087 CHECK(IsR6()); 1088 CHECK_NE(rs, ZERO); 1089 DsFsmInstrNop(EmitI21(0x36, rs, imm21)); 1090 } 1091 1092 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { 1093 CHECK(IsR6()); 1094 CHECK_NE(rs, ZERO); 1095 DsFsmInstrNop(EmitI21(0x3E, rs, imm21)); 1096 } 1097 1098 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { 1099 CHECK(IsR6()); 1100 DsFsmInstrNop(EmitFI(0x11, 0x9, ft, imm16)); 1101 } 1102 1103 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { 1104 CHECK(IsR6()); 1105 DsFsmInstrNop(EmitFI(0x11, 0xD, ft, imm16)); 1106 } 1107 1108 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { 1109 switch (cond) { 1110 case kCondLTZ: 1111 CHECK_EQ(rt, ZERO); 1112 Bltz(rs, imm16); 1113 break; 1114 case kCondGEZ: 1115 CHECK_EQ(rt, ZERO); 1116 Bgez(rs, imm16); 1117 break; 1118 case kCondLEZ: 1119 CHECK_EQ(rt, ZERO); 1120 Blez(rs, imm16); 1121 break; 1122 case kCondGTZ: 1123 CHECK_EQ(rt, ZERO); 1124 Bgtz(rs, imm16); 1125 break; 1126 case kCondEQ: 1127 Beq(rs, rt, imm16); 1128 break; 1129 case kCondNE: 1130 Bne(rs, rt, imm16); 1131 break; 1132 case kCondEQZ: 1133 CHECK_EQ(rt, ZERO); 1134 Beqz(rs, imm16); 1135 break; 1136 case kCondNEZ: 1137 CHECK_EQ(rt, ZERO); 1138 Bnez(rs, imm16); 1139 break; 1140 case kCondF: 1141 CHECK_EQ(rt, ZERO); 1142 Bc1f(static_cast<int>(rs), imm16); 1143 break; 1144 case kCondT: 1145 CHECK_EQ(rt, ZERO); 1146 Bc1t(static_cast<int>(rs), imm16); 1147 break; 1148 case kCondLT: 1149 case kCondGE: 1150 case kCondLE: 1151 case kCondGT: 1152 case kCondLTU: 1153 case kCondGEU: 1154 case kUncond: 1155 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 1156 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 1157 LOG(FATAL) << "Unexpected branch condition " << cond; 1158 UNREACHABLE(); 1159 } 1160 } 1161 1162 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { 1163 switch (cond) { 1164 case kCondLT: 1165 Bltc(rs, rt, imm16_21); 1166 break; 1167 case kCondGE: 1168 Bgec(rs, rt, imm16_21); 1169 break; 1170 case kCondLE: 1171 Bgec(rt, rs, imm16_21); 1172 break; 1173 case kCondGT: 1174 Bltc(rt, rs, imm16_21); 1175 break; 1176 case kCondLTZ: 1177 CHECK_EQ(rt, ZERO); 1178 Bltzc(rs, imm16_21); 1179 break; 1180 case kCondGEZ: 1181 CHECK_EQ(rt, ZERO); 1182 Bgezc(rs, imm16_21); 1183 break; 1184 case kCondLEZ: 1185 CHECK_EQ(rt, ZERO); 1186 Blezc(rs, imm16_21); 1187 break; 1188 case kCondGTZ: 1189 CHECK_EQ(rt, ZERO); 1190 Bgtzc(rs, imm16_21); 1191 break; 1192 case kCondEQ: 1193 Beqc(rs, rt, imm16_21); 1194 break; 1195 case kCondNE: 1196 Bnec(rs, rt, imm16_21); 1197 break; 1198 case kCondEQZ: 1199 CHECK_EQ(rt, ZERO); 1200 Beqzc(rs, imm16_21); 1201 break; 1202 case kCondNEZ: 1203 CHECK_EQ(rt, ZERO); 1204 Bnezc(rs, imm16_21); 1205 break; 1206 case kCondLTU: 1207 Bltuc(rs, rt, imm16_21); 1208 break; 1209 case kCondGEU: 1210 Bgeuc(rs, rt, imm16_21); 1211 break; 1212 case kCondF: 1213 CHECK_EQ(rt, ZERO); 1214 Bc1eqz(static_cast<FRegister>(rs), imm16_21); 1215 break; 1216 case kCondT: 1217 CHECK_EQ(rt, ZERO); 1218 Bc1nez(static_cast<FRegister>(rs), imm16_21); 1219 break; 1220 case kUncond: 1221 LOG(FATAL) << "Unexpected branch condition " << cond; 1222 UNREACHABLE(); 1223 } 1224 } 1225 1226 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 1227 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft); 1228 } 1229 1230 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 1231 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft); 1232 } 1233 1234 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 1235 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft); 1236 } 1237 1238 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 1239 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft); 1240 } 1241 1242 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { 1243 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft); 1244 } 1245 1246 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { 1247 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft); 1248 } 1249 1250 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { 1251 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft); 1252 } 1253 1254 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { 1255 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft); 1256 } 1257 1258 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) { 1259 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs); 1260 } 1261 1262 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) { 1263 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs); 1264 } 1265 1266 void MipsAssembler::AbsS(FRegister fd, FRegister fs) { 1267 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs); 1268 } 1269 1270 void MipsAssembler::AbsD(FRegister fd, FRegister fs) { 1271 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs); 1272 } 1273 1274 void MipsAssembler::MovS(FRegister fd, FRegister fs) { 1275 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs); 1276 } 1277 1278 void MipsAssembler::MovD(FRegister fd, FRegister fs) { 1279 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs); 1280 } 1281 1282 void MipsAssembler::NegS(FRegister fd, FRegister fs) { 1283 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs); 1284 } 1285 1286 void MipsAssembler::NegD(FRegister fd, FRegister fs) { 1287 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs); 1288 } 1289 1290 void MipsAssembler::CunS(FRegister fs, FRegister ft) { 1291 CunS(0, fs, ft); 1292 } 1293 1294 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { 1295 CHECK(!IsR6()); 1296 CHECK(IsUint<3>(cc)) << cc; 1297 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31)) 1298 .CcOuts(cc).FprIns(fs, ft); 1299 } 1300 1301 void MipsAssembler::CeqS(FRegister fs, FRegister ft) { 1302 CeqS(0, fs, ft); 1303 } 1304 1305 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { 1306 CHECK(!IsR6()); 1307 CHECK(IsUint<3>(cc)) << cc; 1308 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32)) 1309 .CcOuts(cc).FprIns(fs, ft); 1310 } 1311 1312 void MipsAssembler::CueqS(FRegister fs, FRegister ft) { 1313 CueqS(0, fs, ft); 1314 } 1315 1316 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { 1317 CHECK(!IsR6()); 1318 CHECK(IsUint<3>(cc)) << cc; 1319 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33)) 1320 .CcOuts(cc).FprIns(fs, ft); 1321 } 1322 1323 void MipsAssembler::ColtS(FRegister fs, FRegister ft) { 1324 ColtS(0, fs, ft); 1325 } 1326 1327 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { 1328 CHECK(!IsR6()); 1329 CHECK(IsUint<3>(cc)) << cc; 1330 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34)) 1331 .CcOuts(cc).FprIns(fs, ft); 1332 } 1333 1334 void MipsAssembler::CultS(FRegister fs, FRegister ft) { 1335 CultS(0, fs, ft); 1336 } 1337 1338 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { 1339 CHECK(!IsR6()); 1340 CHECK(IsUint<3>(cc)) << cc; 1341 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35)) 1342 .CcOuts(cc).FprIns(fs, ft); 1343 } 1344 1345 void MipsAssembler::ColeS(FRegister fs, FRegister ft) { 1346 ColeS(0, fs, ft); 1347 } 1348 1349 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { 1350 CHECK(!IsR6()); 1351 CHECK(IsUint<3>(cc)) << cc; 1352 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36)) 1353 .CcOuts(cc).FprIns(fs, ft); 1354 } 1355 1356 void MipsAssembler::CuleS(FRegister fs, FRegister ft) { 1357 CuleS(0, fs, ft); 1358 } 1359 1360 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { 1361 CHECK(!IsR6()); 1362 CHECK(IsUint<3>(cc)) << cc; 1363 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37)) 1364 .CcOuts(cc).FprIns(fs, ft); 1365 } 1366 1367 void MipsAssembler::CunD(FRegister fs, FRegister ft) { 1368 CunD(0, fs, ft); 1369 } 1370 1371 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { 1372 CHECK(!IsR6()); 1373 CHECK(IsUint<3>(cc)) << cc; 1374 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31)) 1375 .CcOuts(cc).FprIns(fs, ft); 1376 } 1377 1378 void MipsAssembler::CeqD(FRegister fs, FRegister ft) { 1379 CeqD(0, fs, ft); 1380 } 1381 1382 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { 1383 CHECK(!IsR6()); 1384 CHECK(IsUint<3>(cc)) << cc; 1385 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32)) 1386 .CcOuts(cc).FprIns(fs, ft); 1387 } 1388 1389 void MipsAssembler::CueqD(FRegister fs, FRegister ft) { 1390 CueqD(0, fs, ft); 1391 } 1392 1393 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { 1394 CHECK(!IsR6()); 1395 CHECK(IsUint<3>(cc)) << cc; 1396 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33)) 1397 .CcOuts(cc).FprIns(fs, ft); 1398 } 1399 1400 void MipsAssembler::ColtD(FRegister fs, FRegister ft) { 1401 ColtD(0, fs, ft); 1402 } 1403 1404 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { 1405 CHECK(!IsR6()); 1406 CHECK(IsUint<3>(cc)) << cc; 1407 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34)) 1408 .CcOuts(cc).FprIns(fs, ft); 1409 } 1410 1411 void MipsAssembler::CultD(FRegister fs, FRegister ft) { 1412 CultD(0, fs, ft); 1413 } 1414 1415 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { 1416 CHECK(!IsR6()); 1417 CHECK(IsUint<3>(cc)) << cc; 1418 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35)) 1419 .CcOuts(cc).FprIns(fs, ft); 1420 } 1421 1422 void MipsAssembler::ColeD(FRegister fs, FRegister ft) { 1423 ColeD(0, fs, ft); 1424 } 1425 1426 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { 1427 CHECK(!IsR6()); 1428 CHECK(IsUint<3>(cc)) << cc; 1429 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36)) 1430 .CcOuts(cc).FprIns(fs, ft); 1431 } 1432 1433 void MipsAssembler::CuleD(FRegister fs, FRegister ft) { 1434 CuleD(0, fs, ft); 1435 } 1436 1437 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { 1438 CHECK(!IsR6()); 1439 CHECK(IsUint<3>(cc)) << cc; 1440 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37)) 1441 .CcOuts(cc).FprIns(fs, ft); 1442 } 1443 1444 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { 1445 CHECK(IsR6()); 1446 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft); 1447 } 1448 1449 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { 1450 CHECK(IsR6()); 1451 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft); 1452 } 1453 1454 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { 1455 CHECK(IsR6()); 1456 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft); 1457 } 1458 1459 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { 1460 CHECK(IsR6()); 1461 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft); 1462 } 1463 1464 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { 1465 CHECK(IsR6()); 1466 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft); 1467 } 1468 1469 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { 1470 CHECK(IsR6()); 1471 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft); 1472 } 1473 1474 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { 1475 CHECK(IsR6()); 1476 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft); 1477 } 1478 1479 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { 1480 CHECK(IsR6()); 1481 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft); 1482 } 1483 1484 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { 1485 CHECK(IsR6()); 1486 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft); 1487 } 1488 1489 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { 1490 CHECK(IsR6()); 1491 DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft); 1492 } 1493 1494 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { 1495 CHECK(IsR6()); 1496 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft); 1497 } 1498 1499 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { 1500 CHECK(IsR6()); 1501 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft); 1502 } 1503 1504 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { 1505 CHECK(IsR6()); 1506 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft); 1507 } 1508 1509 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { 1510 CHECK(IsR6()); 1511 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft); 1512 } 1513 1514 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { 1515 CHECK(IsR6()); 1516 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft); 1517 } 1518 1519 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { 1520 CHECK(IsR6()); 1521 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft); 1522 } 1523 1524 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { 1525 CHECK(IsR6()); 1526 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft); 1527 } 1528 1529 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { 1530 CHECK(IsR6()); 1531 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft); 1532 } 1533 1534 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { 1535 CHECK(IsR6()); 1536 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft); 1537 } 1538 1539 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { 1540 CHECK(IsR6()); 1541 DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft); 1542 } 1543 1544 void MipsAssembler::Movf(Register rd, Register rs, int cc) { 1545 CHECK(!IsR6()); 1546 CHECK(IsUint<3>(cc)) << cc; 1547 DsFsmInstr(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01)) 1548 .GprInOuts(rd).GprIns(rs).CcIns(cc); 1549 } 1550 1551 void MipsAssembler::Movt(Register rd, Register rs, int cc) { 1552 CHECK(!IsR6()); 1553 CHECK(IsUint<3>(cc)) << cc; 1554 DsFsmInstr(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01)) 1555 .GprInOuts(rd).GprIns(rs).CcIns(cc); 1556 } 1557 1558 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) { 1559 CHECK(!IsR6()); 1560 CHECK(IsUint<3>(cc)) << cc; 1561 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11)) 1562 .FprInOuts(fd).FprIns(fs).CcIns(cc); 1563 } 1564 1565 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) { 1566 CHECK(!IsR6()); 1567 CHECK(IsUint<3>(cc)) << cc; 1568 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11)) 1569 .FprInOuts(fd).FprIns(fs).CcIns(cc); 1570 } 1571 1572 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) { 1573 CHECK(!IsR6()); 1574 CHECK(IsUint<3>(cc)) << cc; 1575 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11)) 1576 .FprInOuts(fd).FprIns(fs).CcIns(cc); 1577 } 1578 1579 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) { 1580 CHECK(!IsR6()); 1581 CHECK(IsUint<3>(cc)) << cc; 1582 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11)) 1583 .FprInOuts(fd).FprIns(fs).CcIns(cc); 1584 } 1585 1586 void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) { 1587 CHECK(!IsR6()); 1588 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12)) 1589 .FprInOuts(fd).FprIns(fs).GprIns(rt); 1590 } 1591 1592 void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) { 1593 CHECK(!IsR6()); 1594 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12)) 1595 .FprInOuts(fd).FprIns(fs).GprIns(rt); 1596 } 1597 1598 void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) { 1599 CHECK(!IsR6()); 1600 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13)) 1601 .FprInOuts(fd).FprIns(fs).GprIns(rt); 1602 } 1603 1604 void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) { 1605 CHECK(!IsR6()); 1606 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13)) 1607 .FprInOuts(fd).FprIns(fs).GprIns(rt); 1608 } 1609 1610 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) { 1611 CHECK(IsR6()); 1612 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft); 1613 } 1614 1615 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) { 1616 CHECK(IsR6()); 1617 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft); 1618 } 1619 1620 void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) { 1621 CHECK(IsR6()); 1622 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft); 1623 } 1624 1625 void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) { 1626 CHECK(IsR6()); 1627 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft); 1628 } 1629 1630 void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) { 1631 CHECK(IsR6()); 1632 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft); 1633 } 1634 1635 void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) { 1636 CHECK(IsR6()); 1637 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft); 1638 } 1639 1640 void MipsAssembler::ClassS(FRegister fd, FRegister fs) { 1641 CHECK(IsR6()); 1642 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs); 1643 } 1644 1645 void MipsAssembler::ClassD(FRegister fd, FRegister fs) { 1646 CHECK(IsR6()); 1647 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs); 1648 } 1649 1650 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) { 1651 CHECK(IsR6()); 1652 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft); 1653 } 1654 1655 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) { 1656 CHECK(IsR6()); 1657 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft); 1658 } 1659 1660 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) { 1661 CHECK(IsR6()); 1662 DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft); 1663 } 1664 1665 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) { 1666 CHECK(IsR6()); 1667 DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft); 1668 } 1669 1670 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { 1671 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs); 1672 } 1673 1674 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { 1675 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs); 1676 } 1677 1678 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { 1679 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs); 1680 } 1681 1682 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { 1683 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs); 1684 } 1685 1686 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { 1687 DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); 1688 } 1689 1690 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { 1691 DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); 1692 } 1693 1694 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { 1695 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); 1696 } 1697 1698 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { 1699 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); 1700 } 1701 1702 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { 1703 DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs); 1704 } 1705 1706 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { 1707 DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs); 1708 } 1709 1710 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) { 1711 DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs); 1712 } 1713 1714 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) { 1715 DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs); 1716 } 1717 1718 FRegister MipsAssembler::GetFpuRegLow(FRegister reg) { 1719 // If FPRs are 32-bit (and get paired to hold 64-bit values), accesses to 1720 // odd-numbered FPRs are reattributed to even-numbered FPRs. This lets us 1721 // use only even-numbered FPRs irrespective of whether we're doing single- 1722 // or double-precision arithmetic. (We don't use odd-numbered 32-bit FPRs 1723 // to hold single-precision values). 1724 return Is32BitFPU() ? static_cast<FRegister>(reg & ~1u) : reg; 1725 } 1726 1727 void MipsAssembler::Mfc1(Register rt, FRegister fs) { 1728 DsFsmInstr(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) 1729 .GprOuts(rt).FprIns(GetFpuRegLow(fs)); 1730 } 1731 1732 // Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs 1733 // when loading the value as 32-bit halves. 1734 void MipsAssembler::Mtc1(Register rt, FRegister fs) { 1735 uint32_t encoding = 1736 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1737 if (Is32BitFPU() && (fs % 2 != 0)) { 1738 // If mtc1 is used to simulate mthc1 by writing to the odd-numbered FPR in 1739 // a pair of 32-bit FPRs, the associated even-numbered FPR is an in/out. 1740 DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(fs)).GprIns(rt); 1741 } else { 1742 // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out. 1743 DsFsmInstr(encoding).FprOuts(fs).GprIns(rt); 1744 } 1745 } 1746 1747 void MipsAssembler::Mfhc1(Register rt, FRegister fs) { 1748 DsFsmInstr(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) 1749 .GprOuts(rt).FprIns(fs); 1750 } 1751 1752 // Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs 1753 // when loading the value as 32-bit halves. 1754 void MipsAssembler::Mthc1(Register rt, FRegister fs) { 1755 DsFsmInstr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0)) 1756 .FprInOuts(fs).GprIns(rt); 1757 } 1758 1759 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) { 1760 if (Is32BitFPU()) { 1761 CHECK_EQ(fs % 2, 0) << fs; 1762 Mfc1(rt, static_cast<FRegister>(fs + 1)); 1763 } else { 1764 Mfhc1(rt, fs); 1765 } 1766 } 1767 1768 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) { 1769 if (Is32BitFPU()) { 1770 CHECK_EQ(fs % 2, 0) << fs; 1771 Mtc1(rt, static_cast<FRegister>(fs + 1)); 1772 } else { 1773 Mthc1(rt, fs); 1774 } 1775 } 1776 1777 // Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs 1778 // when loading the value as 32-bit halves. 1779 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 1780 uint32_t encoding = EmitI(0x31, rs, static_cast<Register>(ft), imm16); 1781 if (Is32BitFPU() && (ft % 2 != 0)) { 1782 // If lwc1 is used to load the odd-numbered FPR in a pair of 32-bit FPRs, 1783 // the associated even-numbered FPR is an in/out. 1784 DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(ft)).GprIns(rs); 1785 } else { 1786 // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out. 1787 DsFsmInstr(encoding).FprOuts(ft).GprIns(rs); 1788 } 1789 } 1790 1791 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { 1792 DsFsmInstr(EmitI(0x35, rs, static_cast<Register>(ft), imm16)).FprOuts(ft).GprIns(rs); 1793 } 1794 1795 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 1796 DsFsmInstr(EmitI(0x39, rs, static_cast<Register>(ft), imm16)).FprIns(GetFpuRegLow(ft)).GprIns(rs); 1797 } 1798 1799 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { 1800 DsFsmInstr(EmitI(0x3d, rs, static_cast<Register>(ft), imm16)).FprIns(ft).GprIns(rs); 1801 } 1802 1803 void MipsAssembler::Break() { 1804 DsFsmInstrNop(EmitR(0, ZERO, ZERO, ZERO, 0, 0xD)); 1805 } 1806 1807 void MipsAssembler::Nop() { 1808 DsFsmInstrNop(EmitR(0x0, ZERO, ZERO, ZERO, 0, 0x0)); 1809 } 1810 1811 void MipsAssembler::NopIfNoReordering() { 1812 if (!reordering_) { 1813 Nop(); 1814 } 1815 } 1816 1817 void MipsAssembler::Move(Register rd, Register rs) { 1818 Or(rd, rs, ZERO); 1819 } 1820 1821 void MipsAssembler::Clear(Register rd) { 1822 Move(rd, ZERO); 1823 } 1824 1825 void MipsAssembler::Not(Register rd, Register rs) { 1826 Nor(rd, rs, ZERO); 1827 } 1828 1829 void MipsAssembler::Push(Register rs) { 1830 IncreaseFrameSize(kStackAlignment); 1831 Sw(rs, SP, 0); 1832 } 1833 1834 void MipsAssembler::Pop(Register rd) { 1835 Lw(rd, SP, 0); 1836 DecreaseFrameSize(kStackAlignment); 1837 } 1838 1839 void MipsAssembler::PopAndReturn(Register rd, Register rt) { 1840 bool reordering = SetReorder(false); 1841 Lw(rd, SP, 0); 1842 Jr(rt); 1843 DecreaseFrameSize(kStackAlignment); // Single instruction in delay slot. 1844 SetReorder(reordering); 1845 } 1846 1847 void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1848 CHECK(HasMsa()); 1849 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); 1850 } 1851 1852 void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1853 CHECK(HasMsa()); 1854 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); 1855 } 1856 1857 void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1858 CHECK(HasMsa()); 1859 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); 1860 } 1861 1862 void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1863 CHECK(HasMsa()); 1864 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt); 1865 } 1866 1867 void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1868 CHECK(HasMsa()); 1869 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1870 } 1871 1872 void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1873 CHECK(HasMsa()); 1874 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1875 } 1876 1877 void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1878 CHECK(HasMsa()); 1879 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1880 } 1881 1882 void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1883 CHECK(HasMsa()); 1884 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1885 } 1886 1887 void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1888 CHECK(HasMsa()); 1889 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1890 } 1891 1892 void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1893 CHECK(HasMsa()); 1894 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1895 } 1896 1897 void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1898 CHECK(HasMsa()); 1899 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1900 } 1901 1902 void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1903 CHECK(HasMsa()); 1904 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 1905 } 1906 1907 void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1908 CHECK(HasMsa()); 1909 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1910 } 1911 1912 void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1913 CHECK(HasMsa()); 1914 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1915 } 1916 1917 void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1918 CHECK(HasMsa()); 1919 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1920 } 1921 1922 void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1923 CHECK(HasMsa()); 1924 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1925 } 1926 1927 void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1928 CHECK(HasMsa()); 1929 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1930 } 1931 1932 void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1933 CHECK(HasMsa()); 1934 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1935 } 1936 1937 void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1938 CHECK(HasMsa()); 1939 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1940 } 1941 1942 void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1943 CHECK(HasMsa()); 1944 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1945 } 1946 1947 void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1948 CHECK(HasMsa()); 1949 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1950 } 1951 1952 void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1953 CHECK(HasMsa()); 1954 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1955 } 1956 1957 void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1958 CHECK(HasMsa()); 1959 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1960 } 1961 1962 void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1963 CHECK(HasMsa()); 1964 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1965 } 1966 1967 void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1968 CHECK(HasMsa()); 1969 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1970 } 1971 1972 void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1973 CHECK(HasMsa()); 1974 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1975 } 1976 1977 void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1978 CHECK(HasMsa()); 1979 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1980 } 1981 1982 void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1983 CHECK(HasMsa()); 1984 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1985 } 1986 1987 void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1988 CHECK(HasMsa()); 1989 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1990 } 1991 1992 void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1993 CHECK(HasMsa()); 1994 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 1995 } 1996 1997 void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 1998 CHECK(HasMsa()); 1999 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 2000 } 2001 2002 void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2003 CHECK(HasMsa()); 2004 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt); 2005 } 2006 2007 void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2008 CHECK(HasMsa()); 2009 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2010 } 2011 2012 void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2013 CHECK(HasMsa()); 2014 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2015 } 2016 2017 void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2018 CHECK(HasMsa()); 2019 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2020 } 2021 2022 void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2023 CHECK(HasMsa()); 2024 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2025 } 2026 2027 void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2028 CHECK(HasMsa()); 2029 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2030 } 2031 2032 void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2033 CHECK(HasMsa()); 2034 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2035 } 2036 2037 void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2038 CHECK(HasMsa()); 2039 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2040 } 2041 2042 void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2043 CHECK(HasMsa()); 2044 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2045 } 2046 2047 void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2048 CHECK(HasMsa()); 2049 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2050 } 2051 2052 void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2053 CHECK(HasMsa()); 2054 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2055 } 2056 2057 void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2058 CHECK(HasMsa()); 2059 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2060 } 2061 2062 void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2063 CHECK(HasMsa()); 2064 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2065 } 2066 2067 void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2068 CHECK(HasMsa()); 2069 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2070 } 2071 2072 void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2073 CHECK(HasMsa()); 2074 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2075 } 2076 2077 void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2078 CHECK(HasMsa()); 2079 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2080 } 2081 2082 void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2083 CHECK(HasMsa()); 2084 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2085 } 2086 2087 void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2088 CHECK(HasMsa()); 2089 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2090 } 2091 2092 void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2093 CHECK(HasMsa()); 2094 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2095 } 2096 2097 void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2098 CHECK(HasMsa()); 2099 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2100 } 2101 2102 void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2103 CHECK(HasMsa()); 2104 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt); 2105 } 2106 2107 void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2108 CHECK(HasMsa()); 2109 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2110 } 2111 2112 void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2113 CHECK(HasMsa()); 2114 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2115 } 2116 2117 void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2118 CHECK(HasMsa()); 2119 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2120 } 2121 2122 void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2123 CHECK(HasMsa()); 2124 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2125 } 2126 2127 void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2128 CHECK(HasMsa()); 2129 DsFsmInstr(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2130 } 2131 2132 void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2133 CHECK(HasMsa()); 2134 DsFsmInstr(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2135 } 2136 2137 void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2138 CHECK(HasMsa()); 2139 DsFsmInstr(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2140 } 2141 2142 void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2143 CHECK(HasMsa()); 2144 DsFsmInstr(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2145 } 2146 2147 void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2148 CHECK(HasMsa()); 2149 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2150 } 2151 2152 void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2153 CHECK(HasMsa()); 2154 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2155 } 2156 2157 void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2158 CHECK(HasMsa()); 2159 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2160 } 2161 2162 void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2163 CHECK(HasMsa()); 2164 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2165 } 2166 2167 void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2168 CHECK(HasMsa()); 2169 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2170 } 2171 2172 void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2173 CHECK(HasMsa()); 2174 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2175 } 2176 2177 void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2178 CHECK(HasMsa()); 2179 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2180 } 2181 2182 void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2183 CHECK(HasMsa()); 2184 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt); 2185 } 2186 2187 void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2188 CHECK(HasMsa()); 2189 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2190 } 2191 2192 void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2193 CHECK(HasMsa()); 2194 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2195 } 2196 2197 void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2198 CHECK(HasMsa()); 2199 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2200 } 2201 2202 void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2203 CHECK(HasMsa()); 2204 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2205 } 2206 2207 void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2208 CHECK(HasMsa()); 2209 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2210 } 2211 2212 void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2213 CHECK(HasMsa()); 2214 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2215 } 2216 2217 void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2218 CHECK(HasMsa()); 2219 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2220 } 2221 2222 void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2223 CHECK(HasMsa()); 2224 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2225 } 2226 2227 void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2228 CHECK(HasMsa()); 2229 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2230 } 2231 2232 void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2233 CHECK(HasMsa()); 2234 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2235 } 2236 2237 void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2238 CHECK(HasMsa()); 2239 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2240 } 2241 2242 void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2243 CHECK(HasMsa()); 2244 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt); 2245 } 2246 2247 void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) { 2248 CHECK(HasMsa()); 2249 DsFsmInstr(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); 2250 } 2251 2252 void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) { 2253 CHECK(HasMsa()); 2254 DsFsmInstr(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); 2255 } 2256 2257 void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) { 2258 CHECK(HasMsa()); 2259 DsFsmInstr(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); 2260 } 2261 2262 void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) { 2263 CHECK(HasMsa()); 2264 DsFsmInstr(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); 2265 } 2266 2267 void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2268 CHECK(HasMsa()); 2269 DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2270 } 2271 2272 void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2273 CHECK(HasMsa()); 2274 DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2275 } 2276 2277 void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2278 CHECK(HasMsa()); 2279 DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2280 } 2281 2282 void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2283 CHECK(HasMsa()); 2284 DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2285 } 2286 2287 void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2288 CHECK(HasMsa()); 2289 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2290 } 2291 2292 void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2293 CHECK(HasMsa()); 2294 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2295 } 2296 2297 void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2298 CHECK(HasMsa()); 2299 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2300 } 2301 2302 void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2303 CHECK(HasMsa()); 2304 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2305 } 2306 2307 void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2308 CHECK(HasMsa()); 2309 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2310 } 2311 2312 void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2313 CHECK(HasMsa()); 2314 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2315 } 2316 2317 void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2318 CHECK(HasMsa()); 2319 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2320 } 2321 2322 void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2323 CHECK(HasMsa()); 2324 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt); 2325 } 2326 2327 void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) { 2328 CHECK(HasMsa()); 2329 CHECK(IsUint<3>(shamt3)) << shamt3; 2330 DsFsmInstr(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2331 } 2332 2333 void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) { 2334 CHECK(HasMsa()); 2335 CHECK(IsUint<4>(shamt4)) << shamt4; 2336 DsFsmInstr(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2337 } 2338 2339 void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) { 2340 CHECK(HasMsa()); 2341 CHECK(IsUint<5>(shamt5)) << shamt5; 2342 DsFsmInstr(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2343 } 2344 2345 void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) { 2346 CHECK(HasMsa()); 2347 CHECK(IsUint<6>(shamt6)) << shamt6; 2348 DsFsmInstr(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2349 } 2350 2351 void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) { 2352 CHECK(HasMsa()); 2353 CHECK(IsUint<3>(shamt3)) << shamt3; 2354 DsFsmInstr(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2355 } 2356 2357 void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) { 2358 CHECK(HasMsa()); 2359 CHECK(IsUint<4>(shamt4)) << shamt4; 2360 DsFsmInstr(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2361 } 2362 2363 void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) { 2364 CHECK(HasMsa()); 2365 CHECK(IsUint<5>(shamt5)) << shamt5; 2366 DsFsmInstr(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2367 } 2368 2369 void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) { 2370 CHECK(HasMsa()); 2371 CHECK(IsUint<6>(shamt6)) << shamt6; 2372 DsFsmInstr(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2373 } 2374 2375 void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) { 2376 CHECK(HasMsa()); 2377 CHECK(IsUint<3>(shamt3)) << shamt3; 2378 DsFsmInstr(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2379 } 2380 2381 void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) { 2382 CHECK(HasMsa()); 2383 CHECK(IsUint<4>(shamt4)) << shamt4; 2384 DsFsmInstr(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2385 } 2386 2387 void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) { 2388 CHECK(HasMsa()); 2389 CHECK(IsUint<5>(shamt5)) << shamt5; 2390 DsFsmInstr(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2391 } 2392 2393 void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) { 2394 CHECK(HasMsa()); 2395 CHECK(IsUint<6>(shamt6)) << shamt6; 2396 DsFsmInstr(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws); 2397 } 2398 2399 void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) { 2400 CHECK(HasMsa()); 2401 DsFsmInstr(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); 2402 } 2403 2404 void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) { 2405 CHECK(HasMsa()); 2406 CHECK(IsUint<4>(n4)) << n4; 2407 DsFsmInstr(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); 2408 } 2409 2410 void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) { 2411 CHECK(HasMsa()); 2412 CHECK(IsUint<3>(n3)) << n3; 2413 DsFsmInstr(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); 2414 } 2415 2416 void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) { 2417 CHECK(HasMsa()); 2418 CHECK(IsUint<2>(n2)) << n2; 2419 DsFsmInstr(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); 2420 } 2421 2422 void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) { 2423 CHECK(HasMsa()); 2424 CHECK(IsUint<1>(n1)) << n1; 2425 DsFsmInstr(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws); 2426 } 2427 2428 void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) { 2429 CHECK(HasMsa()); 2430 CHECK(IsUint<4>(n4)) << n4; 2431 DsFsmInstr(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19)) 2432 .GprOuts(rd).FprIns(ws); 2433 } 2434 2435 void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) { 2436 CHECK(HasMsa()); 2437 CHECK(IsUint<3>(n3)) << n3; 2438 DsFsmInstr(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19)) 2439 .GprOuts(rd).FprIns(ws); 2440 } 2441 2442 void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) { 2443 CHECK(HasMsa()); 2444 CHECK(IsUint<2>(n2)) << n2; 2445 DsFsmInstr(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19)) 2446 .GprOuts(rd).FprIns(ws); 2447 } 2448 2449 void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) { 2450 CHECK(HasMsa()); 2451 CHECK(IsUint<4>(n4)) << n4; 2452 DsFsmInstr(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19)) 2453 .GprOuts(rd).FprIns(ws); 2454 } 2455 2456 void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) { 2457 CHECK(HasMsa()); 2458 CHECK(IsUint<3>(n3)) << n3; 2459 DsFsmInstr(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19)) 2460 .GprOuts(rd).FprIns(ws); 2461 } 2462 2463 void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) { 2464 CHECK(HasMsa()); 2465 CHECK(IsUint<4>(n4)) << n4; 2466 DsFsmInstr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19)) 2467 .FprInOuts(wd).GprIns(rs); 2468 } 2469 2470 void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) { 2471 CHECK(HasMsa()); 2472 CHECK(IsUint<3>(n3)) << n3; 2473 DsFsmInstr(EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19)) 2474 .FprInOuts(wd).GprIns(rs); 2475 } 2476 2477 void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) { 2478 CHECK(HasMsa()); 2479 CHECK(IsUint<2>(n2)) << n2; 2480 DsFsmInstr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19)) 2481 .FprInOuts(wd).GprIns(rs); 2482 } 2483 2484 void MipsAssembler::FillB(VectorRegister wd, Register rs) { 2485 CHECK(HasMsa()); 2486 DsFsmInstr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e)) 2487 .FprOuts(wd).GprIns(rs); 2488 } 2489 2490 void MipsAssembler::FillH(VectorRegister wd, Register rs) { 2491 CHECK(HasMsa()); 2492 DsFsmInstr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e)) 2493 .FprOuts(wd).GprIns(rs); 2494 } 2495 2496 void MipsAssembler::FillW(VectorRegister wd, Register rs) { 2497 CHECK(HasMsa()); 2498 DsFsmInstr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e)) 2499 .FprOuts(wd).GprIns(rs); 2500 } 2501 2502 void MipsAssembler::LdiB(VectorRegister wd, int imm8) { 2503 CHECK(HasMsa()); 2504 CHECK(IsInt<8>(imm8)) << imm8; 2505 DsFsmInstr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); 2506 } 2507 2508 void MipsAssembler::LdiH(VectorRegister wd, int imm10) { 2509 CHECK(HasMsa()); 2510 CHECK(IsInt<10>(imm10)) << imm10; 2511 DsFsmInstr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); 2512 } 2513 2514 void MipsAssembler::LdiW(VectorRegister wd, int imm10) { 2515 CHECK(HasMsa()); 2516 CHECK(IsInt<10>(imm10)) << imm10; 2517 DsFsmInstr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); 2518 } 2519 2520 void MipsAssembler::LdiD(VectorRegister wd, int imm10) { 2521 CHECK(HasMsa()); 2522 CHECK(IsInt<10>(imm10)) << imm10; 2523 DsFsmInstr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd); 2524 } 2525 2526 void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) { 2527 CHECK(HasMsa()); 2528 CHECK(IsInt<10>(offset)) << offset; 2529 DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0)).FprOuts(wd).GprIns(rs); 2530 } 2531 2532 void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) { 2533 CHECK(HasMsa()); 2534 CHECK(IsInt<11>(offset)) << offset; 2535 CHECK_ALIGNED(offset, kMipsHalfwordSize); 2536 DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1)) 2537 .FprOuts(wd).GprIns(rs); 2538 } 2539 2540 void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) { 2541 CHECK(HasMsa()); 2542 CHECK(IsInt<12>(offset)) << offset; 2543 CHECK_ALIGNED(offset, kMipsWordSize); 2544 DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2)) 2545 .FprOuts(wd).GprIns(rs); 2546 } 2547 2548 void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) { 2549 CHECK(HasMsa()); 2550 CHECK(IsInt<13>(offset)) << offset; 2551 CHECK_ALIGNED(offset, kMipsDoublewordSize); 2552 DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3)) 2553 .FprOuts(wd).GprIns(rs); 2554 } 2555 2556 void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) { 2557 CHECK(HasMsa()); 2558 CHECK(IsInt<10>(offset)) << offset; 2559 DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0)).FprIns(wd).GprIns(rs); 2560 } 2561 2562 void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) { 2563 CHECK(HasMsa()); 2564 CHECK(IsInt<11>(offset)) << offset; 2565 CHECK_ALIGNED(offset, kMipsHalfwordSize); 2566 DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1)) 2567 .FprIns(wd).GprIns(rs); 2568 } 2569 2570 void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) { 2571 CHECK(HasMsa()); 2572 CHECK(IsInt<12>(offset)) << offset; 2573 CHECK_ALIGNED(offset, kMipsWordSize); 2574 DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2)) 2575 .FprIns(wd).GprIns(rs); 2576 } 2577 2578 void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) { 2579 CHECK(HasMsa()); 2580 CHECK(IsInt<13>(offset)) << offset; 2581 CHECK_ALIGNED(offset, kMipsDoublewordSize); 2582 DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3)) 2583 .FprIns(wd).GprIns(rs); 2584 } 2585 2586 void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2587 CHECK(HasMsa()); 2588 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2589 } 2590 2591 void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2592 CHECK(HasMsa()); 2593 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2594 } 2595 2596 void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2597 CHECK(HasMsa()); 2598 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2599 } 2600 2601 void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2602 CHECK(HasMsa()); 2603 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2604 } 2605 2606 void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2607 CHECK(HasMsa()); 2608 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2609 } 2610 2611 void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2612 CHECK(HasMsa()); 2613 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2614 } 2615 2616 void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2617 CHECK(HasMsa()); 2618 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2619 } 2620 2621 void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2622 CHECK(HasMsa()); 2623 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2624 } 2625 2626 void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2627 CHECK(HasMsa()); 2628 DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2629 } 2630 2631 void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2632 CHECK(HasMsa()); 2633 DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2634 } 2635 2636 void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2637 CHECK(HasMsa()); 2638 DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2639 } 2640 2641 void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2642 CHECK(HasMsa()); 2643 DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2644 } 2645 2646 void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2647 CHECK(HasMsa()); 2648 DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2649 } 2650 2651 void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2652 CHECK(HasMsa()); 2653 DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2654 } 2655 2656 void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2657 CHECK(HasMsa()); 2658 DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2659 } 2660 2661 void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2662 CHECK(HasMsa()); 2663 DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt); 2664 } 2665 2666 void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2667 CHECK(HasMsa()); 2668 DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2669 } 2670 2671 void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2672 CHECK(HasMsa()); 2673 DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2674 } 2675 2676 void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2677 CHECK(HasMsa()); 2678 DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2679 } 2680 2681 void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2682 CHECK(HasMsa()); 2683 DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2684 } 2685 2686 void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2687 CHECK(HasMsa()); 2688 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2689 } 2690 2691 void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2692 CHECK(HasMsa()); 2693 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2694 } 2695 2696 void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2697 CHECK(HasMsa()); 2698 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2699 } 2700 2701 void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2702 CHECK(HasMsa()); 2703 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt); 2704 } 2705 2706 void MipsAssembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2707 CHECK(HasMsa()); 2708 DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2709 } 2710 2711 void MipsAssembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2712 CHECK(HasMsa()); 2713 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2714 } 2715 2716 void MipsAssembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2717 CHECK(HasMsa()); 2718 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2719 } 2720 2721 void MipsAssembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2722 CHECK(HasMsa()); 2723 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2724 } 2725 2726 void MipsAssembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2727 CHECK(HasMsa()); 2728 DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2729 } 2730 2731 void MipsAssembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2732 CHECK(HasMsa()); 2733 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2734 } 2735 2736 void MipsAssembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2737 CHECK(HasMsa()); 2738 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2739 } 2740 2741 void MipsAssembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2742 CHECK(HasMsa()); 2743 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt); 2744 } 2745 2746 void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2747 CHECK(HasMsa()); 2748 DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); 2749 } 2750 2751 void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2752 CHECK(HasMsa()); 2753 DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); 2754 } 2755 2756 void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2757 CHECK(HasMsa()); 2758 DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); 2759 } 2760 2761 void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2762 CHECK(HasMsa()); 2763 DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt); 2764 } 2765 2766 void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2767 CHECK(HasMsa()); 2768 DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2769 } 2770 2771 void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2772 CHECK(HasMsa()); 2773 DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2774 } 2775 2776 void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2777 CHECK(HasMsa()); 2778 DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2779 } 2780 2781 void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2782 CHECK(HasMsa()); 2783 DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2784 } 2785 2786 void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2787 CHECK(HasMsa()); 2788 DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2789 } 2790 2791 void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) { 2792 CHECK(HasMsa()); 2793 DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); 2794 } 2795 2796 void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst, 2797 FRegister src, 2798 bool is_double) { 2799 // Float or double in FPU register Fx can be considered as 0th element in vector register Wx. 2800 if (is_double) { 2801 SplatiD(dst, static_cast<VectorRegister>(src), 0); 2802 } else { 2803 SplatiW(dst, static_cast<VectorRegister>(src), 0); 2804 } 2805 } 2806 2807 void MipsAssembler::LoadConst32(Register rd, int32_t value) { 2808 if (IsUint<16>(value)) { 2809 // Use OR with (unsigned) immediate to encode 16b unsigned int. 2810 Ori(rd, ZERO, value); 2811 } else if (IsInt<16>(value)) { 2812 // Use ADD with (signed) immediate to encode 16b signed int. 2813 Addiu(rd, ZERO, value); 2814 } else { 2815 Lui(rd, High16Bits(value)); 2816 if (value & 0xFFFF) 2817 Ori(rd, rd, Low16Bits(value)); 2818 } 2819 } 2820 2821 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) { 2822 uint32_t low = Low32Bits(value); 2823 uint32_t high = High32Bits(value); 2824 LoadConst32(reg_lo, low); 2825 if (high != low) { 2826 LoadConst32(reg_hi, high); 2827 } else { 2828 Move(reg_hi, reg_lo); 2829 } 2830 } 2831 2832 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) { 2833 if (value == 0) { 2834 temp = ZERO; 2835 } else { 2836 LoadConst32(temp, value); 2837 } 2838 Mtc1(temp, r); 2839 } 2840 2841 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) { 2842 uint32_t low = Low32Bits(value); 2843 uint32_t high = High32Bits(value); 2844 if (low == 0) { 2845 Mtc1(ZERO, rd); 2846 } else { 2847 LoadConst32(temp, low); 2848 Mtc1(temp, rd); 2849 } 2850 if (high == 0) { 2851 MoveToFpuHigh(ZERO, rd); 2852 } else { 2853 LoadConst32(temp, high); 2854 MoveToFpuHigh(temp, rd); 2855 } 2856 } 2857 2858 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) { 2859 CHECK_NE(rs, temp); // Must not overwrite the register `rs` while loading `value`. 2860 if (IsInt<16>(value)) { 2861 Addiu(rt, rs, value); 2862 } else if (IsR6()) { 2863 int16_t high = High16Bits(value); 2864 int16_t low = Low16Bits(value); 2865 high += (low < 0) ? 1 : 0; // Account for sign extension in addiu. 2866 if (low != 0) { 2867 Aui(temp, rs, high); 2868 Addiu(rt, temp, low); 2869 } else { 2870 Aui(rt, rs, high); 2871 } 2872 } else { 2873 // Do not load the whole 32-bit `value` if it can be represented as 2874 // a sum of two 16-bit signed values. This can save an instruction. 2875 constexpr int32_t kMinValueForSimpleAdjustment = std::numeric_limits<int16_t>::min() * 2; 2876 constexpr int32_t kMaxValueForSimpleAdjustment = std::numeric_limits<int16_t>::max() * 2; 2877 if (0 <= value && value <= kMaxValueForSimpleAdjustment) { 2878 Addiu(temp, rs, kMaxValueForSimpleAdjustment / 2); 2879 Addiu(rt, temp, value - kMaxValueForSimpleAdjustment / 2); 2880 } else if (kMinValueForSimpleAdjustment <= value && value < 0) { 2881 Addiu(temp, rs, kMinValueForSimpleAdjustment / 2); 2882 Addiu(rt, temp, value - kMinValueForSimpleAdjustment / 2); 2883 } else { 2884 // Now that all shorter options have been exhausted, load the full 32-bit value. 2885 LoadConst32(temp, value); 2886 Addu(rt, rs, temp); 2887 } 2888 } 2889 } 2890 2891 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size, 2892 MipsAssembler::Branch::Type short_type, 2893 MipsAssembler::Branch::Type long_type) { 2894 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; 2895 } 2896 2897 void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) { 2898 OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_); 2899 if (is_r6) { 2900 // R6 2901 switch (initial_type) { 2902 case kLabel: 2903 CHECK(!IsResolved()); 2904 type_ = kR6Label; 2905 break; 2906 case kLiteral: 2907 CHECK(!IsResolved()); 2908 type_ = kR6Literal; 2909 break; 2910 case kCall: 2911 InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall); 2912 break; 2913 case kCondBranch: 2914 switch (condition_) { 2915 case kUncond: 2916 InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch); 2917 break; 2918 case kCondEQZ: 2919 case kCondNEZ: 2920 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. 2921 type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch; 2922 break; 2923 default: 2924 InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch); 2925 break; 2926 } 2927 break; 2928 case kBareCall: 2929 type_ = kR6BareCall; 2930 CHECK_LE(offset_size_needed, GetOffsetSize()); 2931 break; 2932 case kBareCondBranch: 2933 type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch; 2934 CHECK_LE(offset_size_needed, GetOffsetSize()); 2935 break; 2936 default: 2937 LOG(FATAL) << "Unexpected branch type " << initial_type; 2938 UNREACHABLE(); 2939 } 2940 } else { 2941 // R2 2942 switch (initial_type) { 2943 case kLabel: 2944 CHECK(!IsResolved()); 2945 type_ = kLabel; 2946 break; 2947 case kLiteral: 2948 CHECK(!IsResolved()); 2949 type_ = kLiteral; 2950 break; 2951 case kCall: 2952 InitShortOrLong(offset_size_needed, kCall, kLongCall); 2953 break; 2954 case kCondBranch: 2955 switch (condition_) { 2956 case kUncond: 2957 InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch); 2958 break; 2959 default: 2960 InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch); 2961 break; 2962 } 2963 break; 2964 case kBareCall: 2965 type_ = kBareCall; 2966 CHECK_LE(offset_size_needed, GetOffsetSize()); 2967 break; 2968 case kBareCondBranch: 2969 type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch; 2970 CHECK_LE(offset_size_needed, GetOffsetSize()); 2971 break; 2972 default: 2973 LOG(FATAL) << "Unexpected branch type " << initial_type; 2974 UNREACHABLE(); 2975 } 2976 } 2977 old_type_ = type_; 2978 } 2979 2980 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) { 2981 switch (condition) { 2982 case kCondLT: 2983 case kCondGT: 2984 case kCondNE: 2985 case kCondLTU: 2986 return lhs == rhs; 2987 default: 2988 return false; 2989 } 2990 } 2991 2992 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) { 2993 switch (condition) { 2994 case kUncond: 2995 return true; 2996 case kCondGE: 2997 case kCondLE: 2998 case kCondEQ: 2999 case kCondGEU: 3000 return lhs == rhs; 3001 default: 3002 return false; 3003 } 3004 } 3005 3006 MipsAssembler::Branch::Branch(bool is_r6, 3007 uint32_t location, 3008 uint32_t target, 3009 bool is_call, 3010 bool is_bare) 3011 : old_location_(location), 3012 location_(location), 3013 target_(target), 3014 lhs_reg_(0), 3015 rhs_reg_(0), 3016 condition_(kUncond), 3017 delayed_instruction_(kUnfilledDelaySlot), 3018 patcher_label_(nullptr) { 3019 InitializeType( 3020 (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)), 3021 is_r6); 3022 } 3023 3024 MipsAssembler::Branch::Branch(bool is_r6, 3025 uint32_t location, 3026 uint32_t target, 3027 MipsAssembler::BranchCondition condition, 3028 Register lhs_reg, 3029 Register rhs_reg, 3030 bool is_bare) 3031 : old_location_(location), 3032 location_(location), 3033 target_(target), 3034 lhs_reg_(lhs_reg), 3035 rhs_reg_(rhs_reg), 3036 condition_(condition), 3037 delayed_instruction_(kUnfilledDelaySlot), 3038 patcher_label_(nullptr) { 3039 CHECK_NE(condition, kUncond); 3040 switch (condition) { 3041 case kCondLT: 3042 case kCondGE: 3043 case kCondLE: 3044 case kCondGT: 3045 case kCondLTU: 3046 case kCondGEU: 3047 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 3048 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 3049 // We leave this up to the caller. 3050 CHECK(is_r6); 3051 FALLTHROUGH_INTENDED; 3052 case kCondEQ: 3053 case kCondNE: 3054 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 3055 // To compare with 0, use dedicated kCond*Z conditions. 3056 CHECK_NE(lhs_reg, ZERO); 3057 CHECK_NE(rhs_reg, ZERO); 3058 break; 3059 case kCondLTZ: 3060 case kCondGEZ: 3061 case kCondLEZ: 3062 case kCondGTZ: 3063 case kCondEQZ: 3064 case kCondNEZ: 3065 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 3066 CHECK_NE(lhs_reg, ZERO); 3067 CHECK_EQ(rhs_reg, ZERO); 3068 break; 3069 case kCondF: 3070 case kCondT: 3071 CHECK_EQ(rhs_reg, ZERO); 3072 break; 3073 case kUncond: 3074 UNREACHABLE(); 3075 } 3076 CHECK(!IsNop(condition, lhs_reg, rhs_reg)); 3077 if (IsUncond(condition, lhs_reg, rhs_reg)) { 3078 // Branch condition is always true, make the branch unconditional. 3079 condition_ = kUncond; 3080 } 3081 InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6); 3082 } 3083 3084 MipsAssembler::Branch::Branch(bool is_r6, 3085 uint32_t location, 3086 Register dest_reg, 3087 Register base_reg, 3088 Type label_or_literal_type) 3089 : old_location_(location), 3090 location_(location), 3091 target_(kUnresolved), 3092 lhs_reg_(dest_reg), 3093 rhs_reg_(base_reg), 3094 condition_(kUncond), 3095 delayed_instruction_(kUnfilledDelaySlot), 3096 patcher_label_(nullptr) { 3097 CHECK_NE(dest_reg, ZERO); 3098 if (is_r6) { 3099 CHECK_EQ(base_reg, ZERO); 3100 } 3101 InitializeType(label_or_literal_type, is_r6); 3102 } 3103 3104 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( 3105 MipsAssembler::BranchCondition cond) { 3106 switch (cond) { 3107 case kCondLT: 3108 return kCondGE; 3109 case kCondGE: 3110 return kCondLT; 3111 case kCondLE: 3112 return kCondGT; 3113 case kCondGT: 3114 return kCondLE; 3115 case kCondLTZ: 3116 return kCondGEZ; 3117 case kCondGEZ: 3118 return kCondLTZ; 3119 case kCondLEZ: 3120 return kCondGTZ; 3121 case kCondGTZ: 3122 return kCondLEZ; 3123 case kCondEQ: 3124 return kCondNE; 3125 case kCondNE: 3126 return kCondEQ; 3127 case kCondEQZ: 3128 return kCondNEZ; 3129 case kCondNEZ: 3130 return kCondEQZ; 3131 case kCondLTU: 3132 return kCondGEU; 3133 case kCondGEU: 3134 return kCondLTU; 3135 case kCondF: 3136 return kCondT; 3137 case kCondT: 3138 return kCondF; 3139 case kUncond: 3140 LOG(FATAL) << "Unexpected branch condition " << cond; 3141 } 3142 UNREACHABLE(); 3143 } 3144 3145 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { 3146 return type_; 3147 } 3148 3149 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { 3150 return condition_; 3151 } 3152 3153 Register MipsAssembler::Branch::GetLeftRegister() const { 3154 return static_cast<Register>(lhs_reg_); 3155 } 3156 3157 Register MipsAssembler::Branch::GetRightRegister() const { 3158 return static_cast<Register>(rhs_reg_); 3159 } 3160 3161 uint32_t MipsAssembler::Branch::GetTarget() const { 3162 return target_; 3163 } 3164 3165 uint32_t MipsAssembler::Branch::GetLocation() const { 3166 return location_; 3167 } 3168 3169 uint32_t MipsAssembler::Branch::GetOldLocation() const { 3170 return old_location_; 3171 } 3172 3173 uint32_t MipsAssembler::Branch::GetPrecedingInstructionLength(Type type) const { 3174 // Short branches with delay slots always consist of two instructions, the branch 3175 // and the delay slot, irrespective of whether the delay slot is filled with a 3176 // useful instruction or not. 3177 // Long composite branches may have a length longer by one instruction than 3178 // specified in branch_info_[].length. This happens when an instruction is taken 3179 // to fill the short branch delay slot, but the branch eventually becomes long 3180 // and formally has no delay slot to fill. This instruction is placed at the 3181 // beginning of the long composite branch and this needs to be accounted for in 3182 // the branch length and the location of the offset encoded in the branch. 3183 switch (type) { 3184 case kLongUncondBranch: 3185 case kLongCondBranch: 3186 case kLongCall: 3187 case kR6LongCondBranch: 3188 return (delayed_instruction_ != kUnfilledDelaySlot && 3189 delayed_instruction_ != kUnfillableDelaySlot) ? 1 : 0; 3190 default: 3191 return 0; 3192 } 3193 } 3194 3195 uint32_t MipsAssembler::Branch::GetPrecedingInstructionSize(Type type) const { 3196 return GetPrecedingInstructionLength(type) * sizeof(uint32_t); 3197 } 3198 3199 uint32_t MipsAssembler::Branch::GetLength() const { 3200 return GetPrecedingInstructionLength(type_) + branch_info_[type_].length; 3201 } 3202 3203 uint32_t MipsAssembler::Branch::GetOldLength() const { 3204 return GetPrecedingInstructionLength(old_type_) + branch_info_[old_type_].length; 3205 } 3206 3207 uint32_t MipsAssembler::Branch::GetSize() const { 3208 return GetLength() * sizeof(uint32_t); 3209 } 3210 3211 uint32_t MipsAssembler::Branch::GetOldSize() const { 3212 return GetOldLength() * sizeof(uint32_t); 3213 } 3214 3215 uint32_t MipsAssembler::Branch::GetEndLocation() const { 3216 return GetLocation() + GetSize(); 3217 } 3218 3219 uint32_t MipsAssembler::Branch::GetOldEndLocation() const { 3220 return GetOldLocation() + GetOldSize(); 3221 } 3222 3223 bool MipsAssembler::Branch::IsBare() const { 3224 switch (type_) { 3225 // R2 short branches (can't be promoted to long), delay slots filled manually. 3226 case kBareUncondBranch: 3227 case kBareCondBranch: 3228 case kBareCall: 3229 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. 3230 case kR6BareUncondBranch: 3231 case kR6BareCondBranch: 3232 case kR6BareCall: 3233 return true; 3234 default: 3235 return false; 3236 } 3237 } 3238 3239 bool MipsAssembler::Branch::IsLong() const { 3240 switch (type_) { 3241 // R2 short branches (can be promoted to long). 3242 case kUncondBranch: 3243 case kCondBranch: 3244 case kCall: 3245 // R2 short branches (can't be promoted to long), delay slots filled manually. 3246 case kBareUncondBranch: 3247 case kBareCondBranch: 3248 case kBareCall: 3249 // R2 near label. 3250 case kLabel: 3251 // R2 near literal. 3252 case kLiteral: 3253 // R6 short branches (can be promoted to long). 3254 case kR6UncondBranch: 3255 case kR6CondBranch: 3256 case kR6Call: 3257 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. 3258 case kR6BareUncondBranch: 3259 case kR6BareCondBranch: 3260 case kR6BareCall: 3261 // R6 near label. 3262 case kR6Label: 3263 // R6 near literal. 3264 case kR6Literal: 3265 return false; 3266 // R2 long branches. 3267 case kLongUncondBranch: 3268 case kLongCondBranch: 3269 case kLongCall: 3270 // R2 far label. 3271 case kFarLabel: 3272 // R2 far literal. 3273 case kFarLiteral: 3274 // R6 long branches. 3275 case kR6LongUncondBranch: 3276 case kR6LongCondBranch: 3277 case kR6LongCall: 3278 // R6 far label. 3279 case kR6FarLabel: 3280 // R6 far literal. 3281 case kR6FarLiteral: 3282 return true; 3283 } 3284 UNREACHABLE(); 3285 } 3286 3287 bool MipsAssembler::Branch::IsResolved() const { 3288 return target_ != kUnresolved; 3289 } 3290 3291 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const { 3292 bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch); 3293 OffsetBits offset_size = 3294 (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) 3295 ? kOffset23 3296 : branch_info_[type_].offset_size; 3297 return offset_size; 3298 } 3299 3300 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location, 3301 uint32_t target) { 3302 // For unresolved targets assume the shortest encoding 3303 // (later it will be made longer if needed). 3304 if (target == kUnresolved) 3305 return kOffset16; 3306 int64_t distance = static_cast<int64_t>(target) - location; 3307 // To simplify calculations in composite branches consisting of multiple instructions 3308 // bump up the distance by a value larger than the max byte size of a composite branch. 3309 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; 3310 if (IsInt<kOffset16>(distance)) 3311 return kOffset16; 3312 else if (IsInt<kOffset18>(distance)) 3313 return kOffset18; 3314 else if (IsInt<kOffset21>(distance)) 3315 return kOffset21; 3316 else if (IsInt<kOffset23>(distance)) 3317 return kOffset23; 3318 else if (IsInt<kOffset28>(distance)) 3319 return kOffset28; 3320 return kOffset32; 3321 } 3322 3323 void MipsAssembler::Branch::Resolve(uint32_t target) { 3324 target_ = target; 3325 } 3326 3327 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { 3328 if (location_ > expand_location) { 3329 location_ += delta; 3330 } 3331 if (!IsResolved()) { 3332 return; // Don't know the target yet. 3333 } 3334 if (target_ > expand_location) { 3335 target_ += delta; 3336 } 3337 } 3338 3339 void MipsAssembler::Branch::PromoteToLong() { 3340 CHECK(!IsBare()); // Bare branches do not promote. 3341 switch (type_) { 3342 // R2 short branches (can be promoted to long). 3343 case kUncondBranch: 3344 type_ = kLongUncondBranch; 3345 break; 3346 case kCondBranch: 3347 type_ = kLongCondBranch; 3348 break; 3349 case kCall: 3350 type_ = kLongCall; 3351 break; 3352 // R2 near label. 3353 case kLabel: 3354 type_ = kFarLabel; 3355 break; 3356 // R2 near literal. 3357 case kLiteral: 3358 type_ = kFarLiteral; 3359 break; 3360 // R6 short branches (can be promoted to long). 3361 case kR6UncondBranch: 3362 type_ = kR6LongUncondBranch; 3363 break; 3364 case kR6CondBranch: 3365 type_ = kR6LongCondBranch; 3366 break; 3367 case kR6Call: 3368 type_ = kR6LongCall; 3369 break; 3370 // R6 near label. 3371 case kR6Label: 3372 type_ = kR6FarLabel; 3373 break; 3374 // R6 near literal. 3375 case kR6Literal: 3376 type_ = kR6FarLiteral; 3377 break; 3378 default: 3379 // Note: 'type_' is already long. 3380 break; 3381 } 3382 CHECK(IsLong()); 3383 } 3384 3385 uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const { 3386 switch (branch->GetType()) { 3387 case Branch::kLabel: 3388 case Branch::kFarLabel: 3389 case Branch::kLiteral: 3390 case Branch::kFarLiteral: 3391 if (branch->GetRightRegister() != ZERO) { 3392 return GetLabelLocation(&pc_rel_base_label_); 3393 } 3394 // For those label/literal loads which come with their own NAL instruction 3395 // and don't depend on `pc_rel_base_label_` we can simply use the location 3396 // of the "branch" (the NAL precedes the "branch" immediately). The location 3397 // is close enough for the user of the returned location, PromoteIfNeeded(), 3398 // to not miss needed promotion to a far load. 3399 // (GetOffsetSizeNeeded() provides a little leeway by means of kMaxBranchSize, 3400 // which is larger than all composite branches and label/literal loads: it's 3401 // OK to promote a bit earlier than strictly necessary, it makes things 3402 // simpler.) 3403 FALLTHROUGH_INTENDED; 3404 default: 3405 return branch->GetLocation(); 3406 } 3407 } 3408 3409 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) { 3410 // `location` comes from GetBranchLocationOrPcRelBase() and is either the location 3411 // of the PC-relative branch or (for some R2 label and literal loads) the location 3412 // of `pc_rel_base_label_`. The PC-relative offset of the branch/load is relative 3413 // to this location. 3414 // If the branch is still unresolved or already long, nothing to do. 3415 if (IsLong() || !IsResolved()) { 3416 return 0; 3417 } 3418 // Promote the short branch to long if the offset size is too small 3419 // to hold the distance between location and target_. 3420 if (GetOffsetSizeNeeded(location, target_) > GetOffsetSize()) { 3421 PromoteToLong(); 3422 uint32_t old_size = GetOldSize(); 3423 uint32_t new_size = GetSize(); 3424 CHECK_GT(new_size, old_size); 3425 return new_size - old_size; 3426 } 3427 // The following logic is for debugging/testing purposes. 3428 // Promote some short branches to long when it's not really required. 3429 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) { 3430 int64_t distance = static_cast<int64_t>(target_) - location; 3431 distance = (distance >= 0) ? distance : -distance; 3432 if (distance >= max_short_distance) { 3433 PromoteToLong(); 3434 uint32_t old_size = GetOldSize(); 3435 uint32_t new_size = GetSize(); 3436 CHECK_GT(new_size, old_size); 3437 return new_size - old_size; 3438 } 3439 } 3440 return 0; 3441 } 3442 3443 uint32_t MipsAssembler::Branch::GetOffsetLocation() const { 3444 return location_ + GetPrecedingInstructionSize(type_) + 3445 branch_info_[type_].instr_offset * sizeof(uint32_t); 3446 } 3447 3448 uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const { 3449 switch (branch->GetType()) { 3450 case Branch::kLabel: 3451 case Branch::kFarLabel: 3452 case Branch::kLiteral: 3453 case Branch::kFarLiteral: 3454 if (branch->GetRightRegister() == ZERO) { 3455 // These loads don't use `pc_rel_base_label_` and instead rely on their own 3456 // NAL instruction (it immediately precedes the "branch"). Therefore the 3457 // effective PC-relative base register is RA and it corresponds to the 2nd 3458 // instruction after the NAL. 3459 return branch->GetLocation() + sizeof(uint32_t); 3460 } else { 3461 return GetLabelLocation(&pc_rel_base_label_); 3462 } 3463 default: 3464 return branch->GetOffsetLocation() + 3465 Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t); 3466 } 3467 } 3468 3469 uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const { 3470 // `location` comes from GetBranchOrPcRelBaseForEncoding() and is either a location 3471 // within/near the PC-relative branch or (for some R2 label and literal loads) the 3472 // location of `pc_rel_base_label_`. The PC-relative offset of the branch/load is 3473 // relative to this location. 3474 CHECK(IsResolved()); 3475 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); 3476 // Calculate the byte distance between instructions and also account for 3477 // different PC-relative origins. 3478 uint32_t offset = target_ - location; 3479 // Prepare the offset for encoding into the instruction(s). 3480 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; 3481 return offset; 3482 } 3483 3484 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { 3485 CHECK_LT(branch_id, branches_.size()); 3486 return &branches_[branch_id]; 3487 } 3488 3489 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { 3490 CHECK_LT(branch_id, branches_.size()); 3491 return &branches_[branch_id]; 3492 } 3493 3494 void MipsAssembler::BindRelativeToPrecedingBranch(MipsLabel* label, 3495 uint32_t prev_branch_id_plus_one, 3496 uint32_t position) { 3497 if (prev_branch_id_plus_one != 0) { 3498 const Branch* branch = GetBranch(prev_branch_id_plus_one - 1); 3499 position -= branch->GetEndLocation(); 3500 } 3501 label->prev_branch_id_plus_one_ = prev_branch_id_plus_one; 3502 label->BindTo(position); 3503 } 3504 3505 void MipsAssembler::Bind(MipsLabel* label) { 3506 CHECK(!label->IsBound()); 3507 uint32_t bound_pc = buffer_.Size(); 3508 3509 // Make the delay slot FSM aware of the new label. 3510 DsFsmLabel(); 3511 3512 // Walk the list of branches referring to and preceding this label. 3513 // Store the previously unknown target addresses in them. 3514 while (label->IsLinked()) { 3515 uint32_t branch_id = label->Position(); 3516 Branch* branch = GetBranch(branch_id); 3517 branch->Resolve(bound_pc); 3518 3519 uint32_t branch_location = branch->GetLocation(); 3520 // Extract the location of the previous branch in the list (walking the list backwards; 3521 // the previous branch ID was stored in the space reserved for this branch). 3522 uint32_t prev = buffer_.Load<uint32_t>(branch_location); 3523 3524 // On to the previous branch in the list... 3525 label->position_ = prev; 3526 } 3527 3528 // Now make the label object contain its own location (relative to the end of the preceding 3529 // branch, if any; it will be used by the branches referring to and following this label). 3530 BindRelativeToPrecedingBranch(label, branches_.size(), bound_pc); 3531 } 3532 3533 uint32_t MipsAssembler::GetLabelLocation(const MipsLabel* label) const { 3534 CHECK(label->IsBound()); 3535 uint32_t target = label->Position(); 3536 if (label->prev_branch_id_plus_one_ != 0) { 3537 // Get label location based on the branch preceding it. 3538 const Branch* branch = GetBranch(label->prev_branch_id_plus_one_ - 1); 3539 target += branch->GetEndLocation(); 3540 } 3541 return target; 3542 } 3543 3544 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) { 3545 // We can reconstruct the adjustment by going through all the branches from the beginning 3546 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop 3547 // with increasing old_position, we can use the data from last AdjustedPosition() to 3548 // continue where we left off and the whole loop should be O(m+n) where m is the number 3549 // of positions to adjust and n is the number of branches. 3550 if (old_position < last_old_position_) { 3551 last_position_adjustment_ = 0; 3552 last_old_position_ = 0; 3553 last_branch_id_ = 0; 3554 } 3555 while (last_branch_id_ != branches_.size()) { 3556 const Branch* branch = GetBranch(last_branch_id_); 3557 if (branch->GetLocation() >= old_position + last_position_adjustment_) { 3558 break; 3559 } 3560 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); 3561 ++last_branch_id_; 3562 } 3563 last_old_position_ = old_position; 3564 return old_position + last_position_adjustment_; 3565 } 3566 3567 void MipsAssembler::BindPcRelBaseLabel() { 3568 Bind(&pc_rel_base_label_); 3569 } 3570 3571 uint32_t MipsAssembler::GetPcRelBaseLabelLocation() const { 3572 return GetLabelLocation(&pc_rel_base_label_); 3573 } 3574 3575 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) { 3576 uint32_t length = branches_.back().GetLength(); 3577 // Commit the last branch target label (if any). 3578 DsFsmCommitLabel(); 3579 if (!label->IsBound()) { 3580 // Branch forward (to a following label), distance is unknown. 3581 // The first branch forward will contain 0, serving as the terminator of 3582 // the list of forward-reaching branches. 3583 Emit(label->position_); 3584 // Nothing for the delay slot (yet). 3585 DsFsmInstrNop(0); 3586 length--; 3587 // Now make the label object point to this branch 3588 // (this forms a linked list of branches preceding this label). 3589 uint32_t branch_id = branches_.size() - 1; 3590 label->LinkTo(branch_id); 3591 } 3592 // Reserve space for the branch. 3593 while (length--) { 3594 Nop(); 3595 } 3596 } 3597 3598 bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slot) const { 3599 if (delay_slot.instruction_ == 0) { 3600 // NOP or no instruction for the delay slot. 3601 return false; 3602 } 3603 switch (type_) { 3604 // R2 unconditional branches. 3605 case kUncondBranch: 3606 case kLongUncondBranch: 3607 // There are no register interdependencies. 3608 return true; 3609 3610 // R2 calls. 3611 case kCall: 3612 case kLongCall: 3613 // Instructions depending on or modifying RA should not be moved into delay slots 3614 // of branches modifying RA. 3615 return ((delay_slot.masks_.gpr_ins_ | delay_slot.masks_.gpr_outs_) & (1u << RA)) == 0; 3616 3617 // R2 conditional branches. 3618 case kCondBranch: 3619 case kLongCondBranch: 3620 switch (condition_) { 3621 // Branches with one GPR source. 3622 case kCondLTZ: 3623 case kCondGEZ: 3624 case kCondLEZ: 3625 case kCondGTZ: 3626 case kCondEQZ: 3627 case kCondNEZ: 3628 return (delay_slot.masks_.gpr_outs_ & (1u << lhs_reg_)) == 0; 3629 3630 // Branches with two GPR sources. 3631 case kCondEQ: 3632 case kCondNE: 3633 return (delay_slot.masks_.gpr_outs_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0; 3634 3635 // Branches with one FPU condition code source. 3636 case kCondF: 3637 case kCondT: 3638 return (delay_slot.masks_.cc_outs_ & (1u << lhs_reg_)) == 0; 3639 3640 default: 3641 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 3642 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 3643 LOG(FATAL) << "Unexpected branch condition " << condition_; 3644 UNREACHABLE(); 3645 } 3646 3647 // R6 unconditional branches. 3648 case kR6UncondBranch: 3649 case kR6LongUncondBranch: 3650 // R6 calls. 3651 case kR6Call: 3652 case kR6LongCall: 3653 // There are no delay slots. 3654 return false; 3655 3656 // R6 conditional branches. 3657 case kR6CondBranch: 3658 case kR6LongCondBranch: 3659 switch (condition_) { 3660 // Branches with one FPU register source. 3661 case kCondF: 3662 case kCondT: 3663 return (delay_slot.masks_.fpr_outs_ & (1u << lhs_reg_)) == 0; 3664 // Others have a forbidden slot instead of a delay slot. 3665 default: 3666 return false; 3667 } 3668 3669 // Literals. 3670 default: 3671 LOG(FATAL) << "Unexpected branch type " << type_; 3672 UNREACHABLE(); 3673 } 3674 } 3675 3676 uint32_t MipsAssembler::Branch::GetDelayedInstruction() const { 3677 return delayed_instruction_; 3678 } 3679 3680 MipsLabel* MipsAssembler::Branch::GetPatcherLabel() const { 3681 return patcher_label_; 3682 } 3683 3684 void MipsAssembler::Branch::SetDelayedInstruction(uint32_t instruction, MipsLabel* patcher_label) { 3685 CHECK_NE(instruction, kUnfilledDelaySlot); 3686 CHECK_EQ(delayed_instruction_, kUnfilledDelaySlot); 3687 delayed_instruction_ = instruction; 3688 patcher_label_ = patcher_label; 3689 } 3690 3691 void MipsAssembler::Branch::DecrementLocations() { 3692 // We first create a branch object, which gets its type and locations initialized, 3693 // and then we check if the branch can actually have the preceding instruction moved 3694 // into its delay slot. If it can, the branch locations need to be decremented. 3695 // 3696 // We could make the check before creating the branch object and avoid the location 3697 // adjustment, but the check is cleaner when performed on an initialized branch 3698 // object. 3699 // 3700 // If the branch is backwards (to a previously bound label), reducing the locations 3701 // cannot cause a short branch to exceed its offset range because the offset reduces. 3702 // And this is not at all a problem for a long branch backwards. 3703 // 3704 // If the branch is forward (not linked to any label yet), reducing the locations 3705 // is harmless. The branch will be promoted to long if needed when the target is known. 3706 CHECK_EQ(location_, old_location_); 3707 CHECK_GE(old_location_, sizeof(uint32_t)); 3708 old_location_ -= sizeof(uint32_t); 3709 location_ = old_location_; 3710 } 3711 3712 void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) { 3713 if (branch.IsBare()) { 3714 // Delay slots are filled manually in bare branches. 3715 return; 3716 } 3717 if (branch.CanHaveDelayedInstruction(delay_slot_)) { 3718 // The last instruction cannot be used in a different delay slot, 3719 // do not commit the label before it (if any). 3720 DsFsmDropLabel(); 3721 // Remove the last emitted instruction. 3722 size_t size = buffer_.Size(); 3723 CHECK_GE(size, sizeof(uint32_t)); 3724 size -= sizeof(uint32_t); 3725 CHECK_EQ(buffer_.Load<uint32_t>(size), delay_slot_.instruction_); 3726 buffer_.Resize(size); 3727 // Attach it to the branch and adjust the branch locations. 3728 branch.DecrementLocations(); 3729 branch.SetDelayedInstruction(delay_slot_.instruction_, delay_slot_.patcher_label_); 3730 } else if (!reordering_ && branch.GetType() == Branch::kUncondBranch) { 3731 // If reordefing is disabled, prevent absorption of the target instruction. 3732 branch.SetDelayedInstruction(Branch::kUnfillableDelaySlot); 3733 } 3734 } 3735 3736 void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) { 3737 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 3738 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ false, is_bare); 3739 MoveInstructionToDelaySlot(branches_.back()); 3740 FinalizeLabeledBranch(label); 3741 } 3742 3743 void MipsAssembler::Bcond(MipsLabel* label, 3744 bool is_r6, 3745 bool is_bare, 3746 BranchCondition condition, 3747 Register lhs, 3748 Register rhs) { 3749 // If lhs = rhs, this can be a NOP. 3750 if (Branch::IsNop(condition, lhs, rhs)) { 3751 return; 3752 } 3753 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 3754 branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare); 3755 MoveInstructionToDelaySlot(branches_.back()); 3756 FinalizeLabeledBranch(label); 3757 } 3758 3759 void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) { 3760 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 3761 branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ true, is_bare); 3762 MoveInstructionToDelaySlot(branches_.back()); 3763 FinalizeLabeledBranch(label); 3764 } 3765 3766 void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) { 3767 // Label address loads are treated as pseudo branches since they require very similar handling. 3768 DCHECK(!label->IsBound()); 3769 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we 3770 // may generate an individual NAL instruction to simulate PC-relative addressing on R2 3771 // by specifying `base_reg` of `ZERO`. Check for it. 3772 if (base_reg == ZERO && !IsR6()) { 3773 Nal(); 3774 } 3775 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel); 3776 FinalizeLabeledBranch(label); 3777 } 3778 3779 Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) { 3780 DCHECK(size == 4u || size == 8u) << size; 3781 literals_.emplace_back(size, data); 3782 return &literals_.back(); 3783 } 3784 3785 void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* literal) { 3786 // Literal loads are treated as pseudo branches since they require very similar handling. 3787 DCHECK_EQ(literal->GetSize(), 4u); 3788 MipsLabel* label = literal->GetLabel(); 3789 DCHECK(!label->IsBound()); 3790 // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we 3791 // may generate an individual NAL instruction to simulate PC-relative addressing on R2 3792 // by specifying `base_reg` of `ZERO`. Check for it. 3793 if (base_reg == ZERO && !IsR6()) { 3794 Nal(); 3795 } 3796 branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral); 3797 FinalizeLabeledBranch(label); 3798 } 3799 3800 JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) { 3801 jump_tables_.emplace_back(std::move(labels)); 3802 JumpTable* table = &jump_tables_.back(); 3803 DCHECK(!table->GetLabel()->IsBound()); 3804 return table; 3805 } 3806 3807 void MipsAssembler::EmitLiterals() { 3808 if (!literals_.empty()) { 3809 // We don't support byte and half-word literals. 3810 // TODO: proper alignment for 64-bit literals when they're implemented. 3811 for (Literal& literal : literals_) { 3812 MipsLabel* label = literal.GetLabel(); 3813 Bind(label); 3814 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 3815 DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u); 3816 for (size_t i = 0, size = literal.GetSize(); i != size; ++i) { 3817 buffer_.Emit<uint8_t>(literal.GetData()[i]); 3818 } 3819 } 3820 } 3821 } 3822 3823 void MipsAssembler::ReserveJumpTableSpace() { 3824 if (!jump_tables_.empty()) { 3825 for (JumpTable& table : jump_tables_) { 3826 MipsLabel* label = table.GetLabel(); 3827 Bind(label); 3828 3829 // Bulk ensure capacity, as this may be large. 3830 size_t orig_size = buffer_.Size(); 3831 size_t required_capacity = orig_size + table.GetSize(); 3832 if (required_capacity > buffer_.Capacity()) { 3833 buffer_.ExtendCapacity(required_capacity); 3834 } 3835 #ifndef NDEBUG 3836 buffer_.has_ensured_capacity_ = true; 3837 #endif 3838 3839 // Fill the space with dummy data as the data is not final 3840 // until the branches have been promoted. And we shouldn't 3841 // be moving uninitialized data during branch promotion. 3842 for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) { 3843 buffer_.Emit<uint32_t>(0x1abe1234u); 3844 } 3845 3846 #ifndef NDEBUG 3847 buffer_.has_ensured_capacity_ = false; 3848 #endif 3849 } 3850 } 3851 } 3852 3853 void MipsAssembler::EmitJumpTables() { 3854 if (!jump_tables_.empty()) { 3855 CHECK(!overwriting_); 3856 // Switch from appending instructions at the end of the buffer to overwriting 3857 // existing instructions (here, jump tables) in the buffer. 3858 overwriting_ = true; 3859 3860 for (JumpTable& table : jump_tables_) { 3861 MipsLabel* table_label = table.GetLabel(); 3862 uint32_t start = GetLabelLocation(table_label); 3863 overwrite_location_ = start; 3864 3865 for (MipsLabel* target : table.GetData()) { 3866 CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u); 3867 // The table will contain target addresses relative to the table start. 3868 uint32_t offset = GetLabelLocation(target) - start; 3869 Emit(offset); 3870 } 3871 } 3872 3873 overwriting_ = false; 3874 } 3875 } 3876 3877 void MipsAssembler::PromoteBranches() { 3878 // Promote short branches to long as necessary. 3879 bool changed; 3880 do { 3881 changed = false; 3882 for (auto& branch : branches_) { 3883 CHECK(branch.IsResolved()); 3884 uint32_t base = GetBranchLocationOrPcRelBase(&branch); 3885 uint32_t delta = branch.PromoteIfNeeded(base); 3886 // If this branch has been promoted and needs to expand in size, 3887 // relocate all branches by the expansion size. 3888 if (delta) { 3889 changed = true; 3890 uint32_t expand_location = branch.GetLocation(); 3891 for (auto& branch2 : branches_) { 3892 branch2.Relocate(expand_location, delta); 3893 } 3894 } 3895 } 3896 } while (changed); 3897 3898 // Account for branch expansion by resizing the code buffer 3899 // and moving the code in it to its final location. 3900 size_t branch_count = branches_.size(); 3901 if (branch_count > 0) { 3902 // Resize. 3903 Branch& last_branch = branches_[branch_count - 1]; 3904 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); 3905 uint32_t old_size = buffer_.Size(); 3906 buffer_.Resize(old_size + size_delta); 3907 // Move the code residing between branch placeholders. 3908 uint32_t end = old_size; 3909 for (size_t i = branch_count; i > 0; ) { 3910 Branch& branch = branches_[--i]; 3911 CHECK_GE(end, branch.GetOldEndLocation()); 3912 uint32_t size = end - branch.GetOldEndLocation(); 3913 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); 3914 end = branch.GetOldLocation(); 3915 } 3916 } 3917 } 3918 3919 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 3920 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = { 3921 // R2 short branches (can be promoted to long). 3922 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch 3923 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch 3924 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall 3925 // R2 short branches (can't be promoted to long), delay slots filled manually. 3926 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch 3927 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch 3928 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall 3929 // R2 near label. 3930 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel 3931 // R2 near literal. 3932 { 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLiteral 3933 // R2 long branches. 3934 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch 3935 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch 3936 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall 3937 // R2 far label. 3938 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel 3939 // R2 far literal. 3940 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral 3941 // R6 short branches (can be promoted to long). 3942 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch 3943 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch 3944 // Exception: kOffset23 for beqzc/bnezc. 3945 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call 3946 // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually. 3947 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch 3948 { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch 3949 // Exception: kOffset23 for beqzc/bnezc. 3950 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall 3951 // R6 near label. 3952 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label 3953 // R6 near literal. 3954 { 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Literal 3955 // R6 long branches. 3956 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch 3957 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch 3958 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall 3959 // R6 far label. 3960 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLabel 3961 // R6 far literal. 3962 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6FarLiteral 3963 }; 3964 3965 static inline bool IsAbsorbableInstruction(uint32_t instruction) { 3966 // The relative patcher patches addiu, lw and sw with an immediate operand of 0x5678. 3967 // We want to make sure that these instructions do not get absorbed into delay slots 3968 // of unconditional branches on R2. Absorption would otherwise make copies of 3969 // unpatched instructions. 3970 if ((instruction & 0xFFFF) != 0x5678) { 3971 return true; 3972 } 3973 switch (instruction >> kOpcodeShift) { 3974 case 0x09: // Addiu. 3975 case 0x23: // Lw. 3976 case 0x2B: // Sw. 3977 return false; 3978 default: 3979 return true; 3980 } 3981 } 3982 3983 static inline Register GetR2PcRelBaseRegister(Register reg) { 3984 // LoadLabelAddress() and LoadLiteral() generate individual NAL 3985 // instructions on R2 when the specified base register is ZERO 3986 // and so the effective PC-relative base register is RA, not ZERO. 3987 return (reg == ZERO) ? RA : reg; 3988 } 3989 3990 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 3991 void MipsAssembler::EmitBranch(uint32_t branch_id) { 3992 CHECK_EQ(overwriting_, true); 3993 Branch* branch = GetBranch(branch_id); 3994 overwrite_location_ = branch->GetLocation(); 3995 uint32_t offset = branch->GetOffset(GetBranchOrPcRelBaseForEncoding(branch)); 3996 BranchCondition condition = branch->GetCondition(); 3997 Register lhs = branch->GetLeftRegister(); 3998 Register rhs = branch->GetRightRegister(); 3999 uint32_t delayed_instruction = branch->GetDelayedInstruction(); 4000 MipsLabel* patcher_label = branch->GetPatcherLabel(); 4001 if (patcher_label != nullptr) { 4002 // Update the patcher label location to account for branch promotion and 4003 // delay slot filling. 4004 CHECK(patcher_label->IsBound()); 4005 uint32_t bound_pc = branch->GetLocation(); 4006 if (!branch->IsLong()) { 4007 // Short branches precede delay slots. 4008 // Long branches follow "delay slots". 4009 bound_pc += sizeof(uint32_t); 4010 } 4011 // Rebind the label. 4012 patcher_label->Reinitialize(); 4013 BindRelativeToPrecedingBranch(patcher_label, branch_id, bound_pc); 4014 } 4015 switch (branch->GetType()) { 4016 // R2 short branches. 4017 case Branch::kUncondBranch: 4018 if (delayed_instruction == Branch::kUnfillableDelaySlot) { 4019 // The branch was created when reordering was disabled, do not absorb the target 4020 // instruction. 4021 delayed_instruction = 0; // NOP. 4022 } else if (delayed_instruction == Branch::kUnfilledDelaySlot) { 4023 // Try to absorb the target instruction into the delay slot. 4024 delayed_instruction = 0; // NOP. 4025 // Incrementing the signed 16-bit offset past the target instruction must not 4026 // cause overflow into the negative subrange, check for the max offset. 4027 if (offset != 0x7FFF) { 4028 uint32_t target = branch->GetTarget(); 4029 if (std::binary_search(ds_fsm_target_pcs_.begin(), ds_fsm_target_pcs_.end(), target)) { 4030 uint32_t target_instruction = buffer_.Load<uint32_t>(target); 4031 if (IsAbsorbableInstruction(target_instruction)) { 4032 delayed_instruction = target_instruction; 4033 offset++; 4034 } 4035 } 4036 } 4037 } 4038 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4039 B(offset); 4040 Emit(delayed_instruction); 4041 break; 4042 case Branch::kCondBranch: 4043 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4044 if (delayed_instruction == Branch::kUnfilledDelaySlot) { 4045 delayed_instruction = 0; // NOP. 4046 } 4047 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4048 EmitBcondR2(condition, lhs, rhs, offset); 4049 Emit(delayed_instruction); 4050 break; 4051 case Branch::kCall: 4052 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4053 if (delayed_instruction == Branch::kUnfilledDelaySlot) { 4054 delayed_instruction = 0; // NOP. 4055 } 4056 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4057 Bal(offset); 4058 Emit(delayed_instruction); 4059 break; 4060 case Branch::kBareUncondBranch: 4061 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4062 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4063 B(offset); 4064 break; 4065 case Branch::kBareCondBranch: 4066 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4067 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4068 EmitBcondR2(condition, lhs, rhs, offset); 4069 break; 4070 case Branch::kBareCall: 4071 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4072 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4073 Bal(offset); 4074 break; 4075 4076 // R2 near label. 4077 case Branch::kLabel: 4078 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4079 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4080 Addiu(lhs, GetR2PcRelBaseRegister(rhs), offset); 4081 break; 4082 // R2 near literal. 4083 case Branch::kLiteral: 4084 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4085 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4086 Lw(lhs, GetR2PcRelBaseRegister(rhs), offset); 4087 break; 4088 4089 // R2 long branches. 4090 case Branch::kLongUncondBranch: 4091 // To get the value of the PC register we need to use the NAL instruction. 4092 // NAL clobbers the RA register. However, RA must be preserved if the 4093 // method is compiled without the entry/exit sequences that would take care 4094 // of preserving RA (typically, leaf methods don't preserve RA explicitly). 4095 // So, we need to preserve RA in some temporary storage ourselves. The AT 4096 // register can't be used for this because we need it to load a constant 4097 // which will be added to the value that NAL stores in RA. And we can't 4098 // use T9 for this in the context of the JNI compiler, which uses it 4099 // as a scratch register (see InterproceduralScratchRegister()). 4100 // If we were to add a 32-bit constant to RA using two ADDIU instructions, 4101 // we'd also need to use the ROTR instruction, which requires no less than 4102 // MIPSR2. 4103 // Perhaps, we could use T8 or one of R2's multiplier/divider registers 4104 // (LO or HI) or even a floating-point register, but that doesn't seem 4105 // like a nice solution. We may want this to work on both R6 and pre-R6. 4106 // For now simply use the stack for RA. This should be OK since for the 4107 // vast majority of code a short PC-relative branch is sufficient. 4108 // TODO: can this be improved? 4109 // TODO: consider generation of a shorter sequence when we know that RA 4110 // is explicitly preserved by the method entry/exit code. 4111 if (delayed_instruction != Branch::kUnfilledDelaySlot && 4112 delayed_instruction != Branch::kUnfillableDelaySlot) { 4113 Emit(delayed_instruction); 4114 } 4115 Push(RA); 4116 Nal(); 4117 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4118 Lui(AT, High16Bits(offset)); 4119 Ori(AT, AT, Low16Bits(offset)); 4120 Addu(AT, AT, RA); 4121 Lw(RA, SP, 0); 4122 Jr(AT); 4123 DecreaseFrameSize(kStackAlignment); 4124 break; 4125 case Branch::kLongCondBranch: 4126 // The comment on case 'Branch::kLongUncondBranch' applies here as well. 4127 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4128 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 4129 Emit(delayed_instruction); 4130 } 4131 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the 4132 // number of instructions skipped: 4133 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). 4134 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); 4135 Push(RA); 4136 Nal(); 4137 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4138 Lui(AT, High16Bits(offset)); 4139 Ori(AT, AT, Low16Bits(offset)); 4140 Addu(AT, AT, RA); 4141 Lw(RA, SP, 0); 4142 Jr(AT); 4143 DecreaseFrameSize(kStackAlignment); 4144 break; 4145 case Branch::kLongCall: 4146 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4147 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 4148 Emit(delayed_instruction); 4149 } 4150 Nal(); 4151 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4152 Lui(AT, High16Bits(offset)); 4153 Ori(AT, AT, Low16Bits(offset)); 4154 Addu(AT, AT, RA); 4155 Jalr(AT); 4156 Nop(); 4157 break; 4158 4159 // R2 far label. 4160 case Branch::kFarLabel: 4161 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4162 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4163 Lui(AT, High16Bits(offset)); 4164 Ori(AT, AT, Low16Bits(offset)); 4165 Addu(lhs, AT, GetR2PcRelBaseRegister(rhs)); 4166 break; 4167 // R2 far literal. 4168 case Branch::kFarLiteral: 4169 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4170 offset += (offset & 0x8000) << 1; // Account for sign extension in lw. 4171 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4172 Lui(AT, High16Bits(offset)); 4173 Addu(AT, AT, GetR2PcRelBaseRegister(rhs)); 4174 Lw(lhs, AT, Low16Bits(offset)); 4175 break; 4176 4177 // R6 short branches. 4178 case Branch::kR6UncondBranch: 4179 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4180 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4181 Bc(offset); 4182 break; 4183 case Branch::kR6CondBranch: 4184 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4185 EmitBcondR6(condition, lhs, rhs, offset); 4186 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4187 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 4188 Emit(delayed_instruction); 4189 } else { 4190 // TODO: improve by filling the forbidden slot (IFF this is 4191 // a forbidden and not a delay slot). 4192 Nop(); 4193 } 4194 break; 4195 case Branch::kR6Call: 4196 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4197 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4198 Balc(offset); 4199 break; 4200 case Branch::kR6BareUncondBranch: 4201 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4202 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4203 Bc(offset); 4204 break; 4205 case Branch::kR6BareCondBranch: 4206 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4207 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4208 EmitBcondR6(condition, lhs, rhs, offset); 4209 break; 4210 case Branch::kR6BareCall: 4211 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4212 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4213 Balc(offset); 4214 break; 4215 4216 // R6 near label. 4217 case Branch::kR6Label: 4218 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4219 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4220 Addiupc(lhs, offset); 4221 break; 4222 // R6 near literal. 4223 case Branch::kR6Literal: 4224 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4225 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4226 Lwpc(lhs, offset); 4227 break; 4228 4229 // R6 long branches. 4230 case Branch::kR6LongUncondBranch: 4231 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4232 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 4233 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4234 Auipc(AT, High16Bits(offset)); 4235 Jic(AT, Low16Bits(offset)); 4236 break; 4237 case Branch::kR6LongCondBranch: 4238 DCHECK_NE(delayed_instruction, Branch::kUnfillableDelaySlot); 4239 if (delayed_instruction != Branch::kUnfilledDelaySlot) { 4240 Emit(delayed_instruction); 4241 } 4242 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); 4243 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 4244 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4245 Auipc(AT, High16Bits(offset)); 4246 Jic(AT, Low16Bits(offset)); 4247 break; 4248 case Branch::kR6LongCall: 4249 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4250 offset += (offset & 0x8000) << 1; // Account for sign extension in jialc. 4251 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4252 Auipc(AT, High16Bits(offset)); 4253 Jialc(AT, Low16Bits(offset)); 4254 break; 4255 4256 // R6 far label. 4257 case Branch::kR6FarLabel: 4258 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4259 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu. 4260 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4261 Auipc(AT, High16Bits(offset)); 4262 Addiu(lhs, AT, Low16Bits(offset)); 4263 break; 4264 // R6 far literal. 4265 case Branch::kR6FarLiteral: 4266 DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot); 4267 offset += (offset & 0x8000) << 1; // Account for sign extension in lw. 4268 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 4269 Auipc(AT, High16Bits(offset)); 4270 Lw(lhs, AT, Low16Bits(offset)); 4271 break; 4272 } 4273 CHECK_EQ(overwrite_location_, branch->GetEndLocation()); 4274 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); 4275 if (patcher_label != nullptr) { 4276 // The patched instruction should look like one. 4277 uint32_t patched_instruction = buffer_.Load<uint32_t>(GetLabelLocation(patcher_label)); 4278 CHECK(!IsAbsorbableInstruction(patched_instruction)); 4279 } 4280 } 4281 4282 void MipsAssembler::B(MipsLabel* label, bool is_bare) { 4283 Buncond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare); 4284 } 4285 4286 void MipsAssembler::Bal(MipsLabel* label, bool is_bare) { 4287 Call(label, /* is_r6 */ (IsR6() && !is_bare), is_bare); 4288 } 4289 4290 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4291 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt); 4292 } 4293 4294 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4295 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt); 4296 } 4297 4298 void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) { 4299 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt); 4300 } 4301 4302 void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) { 4303 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt); 4304 } 4305 4306 void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) { 4307 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt); 4308 } 4309 4310 void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) { 4311 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt); 4312 } 4313 4314 void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) { 4315 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt); 4316 } 4317 4318 void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) { 4319 Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt); 4320 } 4321 4322 bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const { 4323 // If the instruction modifies AT, `rs` or `rt`, it can't be exchanged with the slt[u] 4324 // instruction because either slt[u] depends on `rs` or `rt` or the following 4325 // conditional branch depends on AT set by slt[u]. 4326 // Likewise, if the instruction depends on AT, it can't be exchanged with slt[u] 4327 // because slt[u] changes AT. 4328 return (delay_slot_.instruction_ != 0 && 4329 (delay_slot_.masks_.gpr_outs_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 && 4330 (delay_slot_.masks_.gpr_ins_ & (1u << AT)) == 0); 4331 } 4332 4333 void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) { 4334 // Exchange the last two instructions in the assembler buffer. 4335 size_t size = buffer_.Size(); 4336 CHECK_GE(size, 2 * sizeof(uint32_t)); 4337 size_t pos1 = size - 2 * sizeof(uint32_t); 4338 size_t pos2 = size - sizeof(uint32_t); 4339 uint32_t instr1 = buffer_.Load<uint32_t>(pos1); 4340 uint32_t instr2 = buffer_.Load<uint32_t>(pos2); 4341 CHECK_EQ(instr1, forwarded_slot.instruction_); 4342 CHECK_EQ(instr2, delay_slot_.instruction_); 4343 buffer_.Store<uint32_t>(pos1, instr2); 4344 buffer_.Store<uint32_t>(pos2, instr1); 4345 // Set the current delay slot information to that of the last instruction 4346 // in the buffer. 4347 delay_slot_ = forwarded_slot; 4348 } 4349 4350 void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Register rt) { 4351 // If possible, exchange the slt[u] instruction with the preceding instruction, 4352 // so it can fill the delay slot. 4353 DelaySlot forwarded_slot = delay_slot_; 4354 bool exchange = CanExchangeWithSlt(rs, rt); 4355 if (exchange) { 4356 // The last instruction cannot be used in a different delay slot, 4357 // do not commit the label before it (if any). 4358 DsFsmDropLabel(); 4359 } 4360 if (unsigned_slt) { 4361 Sltu(AT, rs, rt); 4362 } else { 4363 Slt(AT, rs, rt); 4364 } 4365 if (exchange) { 4366 ExchangeWithSlt(forwarded_slot); 4367 } 4368 } 4369 4370 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4371 if (IsR6() && !is_bare) { 4372 Bcond(label, IsR6(), is_bare, kCondLT, rs, rt); 4373 } else if (!Branch::IsNop(kCondLT, rs, rt)) { 4374 // Synthesize the instruction (not available on R2). 4375 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt); 4376 Bnez(AT, label, is_bare); 4377 } 4378 } 4379 4380 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4381 if (IsR6() && !is_bare) { 4382 Bcond(label, IsR6(), is_bare, kCondGE, rs, rt); 4383 } else if (Branch::IsUncond(kCondGE, rs, rt)) { 4384 B(label, is_bare); 4385 } else { 4386 // Synthesize the instruction (not available on R2). 4387 GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt); 4388 Beqz(AT, label, is_bare); 4389 } 4390 } 4391 4392 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4393 if (IsR6() && !is_bare) { 4394 Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt); 4395 } else if (!Branch::IsNop(kCondLTU, rs, rt)) { 4396 // Synthesize the instruction (not available on R2). 4397 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt); 4398 Bnez(AT, label, is_bare); 4399 } 4400 } 4401 4402 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4403 if (IsR6() && !is_bare) { 4404 Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt); 4405 } else if (Branch::IsUncond(kCondGEU, rs, rt)) { 4406 B(label, is_bare); 4407 } else { 4408 // Synthesize the instruction (not available on R2). 4409 GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt); 4410 Beqz(AT, label, is_bare); 4411 } 4412 } 4413 4414 void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) { 4415 Bc1f(0, label, is_bare); 4416 } 4417 4418 void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) { 4419 CHECK(IsUint<3>(cc)) << cc; 4420 Bcond(label, /* is_r6 */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO); 4421 } 4422 4423 void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) { 4424 Bc1t(0, label, is_bare); 4425 } 4426 4427 void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) { 4428 CHECK(IsUint<3>(cc)) << cc; 4429 Bcond(label, /* is_r6 */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO); 4430 } 4431 4432 void MipsAssembler::Bc(MipsLabel* label, bool is_bare) { 4433 Buncond(label, /* is_r6 */ true, is_bare); 4434 } 4435 4436 void MipsAssembler::Balc(MipsLabel* label, bool is_bare) { 4437 Call(label, /* is_r6 */ true, is_bare); 4438 } 4439 4440 void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4441 Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt); 4442 } 4443 4444 void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4445 Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt); 4446 } 4447 4448 void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) { 4449 Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rt); 4450 } 4451 4452 void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) { 4453 Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rt); 4454 } 4455 4456 void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) { 4457 Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt); 4458 } 4459 4460 void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) { 4461 Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt); 4462 } 4463 4464 void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) { 4465 Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt); 4466 } 4467 4468 void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) { 4469 Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt); 4470 } 4471 4472 void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4473 Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt); 4474 } 4475 4476 void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4477 Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt); 4478 } 4479 4480 void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4481 Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt); 4482 } 4483 4484 void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) { 4485 Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt); 4486 } 4487 4488 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) { 4489 Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO); 4490 } 4491 4492 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) { 4493 Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO); 4494 } 4495 4496 void MipsAssembler::AdjustBaseAndOffset(Register& base, 4497 int32_t& offset, 4498 bool is_doubleword, 4499 bool is_float) { 4500 // This method is used to adjust the base register and offset pair 4501 // for a load/store when the offset doesn't fit into int16_t. 4502 // It is assumed that `base + offset` is sufficiently aligned for memory 4503 // operands that are machine word in size or smaller. For doubleword-sized 4504 // operands it's assumed that `base` is a multiple of 8, while `offset` 4505 // may be a multiple of 4 (e.g. 4-byte-aligned long and double arguments 4506 // and spilled variables on the stack accessed relative to the stack 4507 // pointer register). 4508 // We preserve the "alignment" of `offset` by adjusting it by a multiple of 8. 4509 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`. 4510 4511 bool doubleword_aligned = IsAligned<kMipsDoublewordSize>(offset); 4512 bool two_accesses = is_doubleword && (!is_float || !doubleword_aligned); 4513 4514 // IsInt<16> must be passed a signed value, hence the static cast below. 4515 if (IsInt<16>(offset) && 4516 (!two_accesses || IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 4517 // Nothing to do: `offset` (and, if needed, `offset + 4`) fits into int16_t. 4518 return; 4519 } 4520 4521 // Remember the "(mis)alignment" of `offset`, it will be checked at the end. 4522 uint32_t misalignment = offset & (kMipsDoublewordSize - 1); 4523 4524 // Do not load the whole 32-bit `offset` if it can be represented as 4525 // a sum of two 16-bit signed offsets. This can save an instruction or two. 4526 // To simplify matters, only do this for a symmetric range of offsets from 4527 // about -64KB to about +64KB, allowing further addition of 4 when accessing 4528 // 64-bit variables with two 32-bit accesses. 4529 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7ff8; // Max int16_t that's a multiple of 8. 4530 constexpr int32_t kMaxOffsetForSimpleAdjustment = 2 * kMinOffsetForSimpleAdjustment; 4531 if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) { 4532 Addiu(AT, base, kMinOffsetForSimpleAdjustment); 4533 offset -= kMinOffsetForSimpleAdjustment; 4534 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { 4535 Addiu(AT, base, -kMinOffsetForSimpleAdjustment); 4536 offset += kMinOffsetForSimpleAdjustment; 4537 } else if (IsR6()) { 4538 // On R6 take advantage of the aui instruction, e.g.: 4539 // aui AT, base, offset_high 4540 // lw reg_lo, offset_low(AT) 4541 // lw reg_hi, (offset_low+4)(AT) 4542 // or when offset_low+4 overflows int16_t: 4543 // aui AT, base, offset_high 4544 // addiu AT, AT, 8 4545 // lw reg_lo, (offset_low-8)(AT) 4546 // lw reg_hi, (offset_low-4)(AT) 4547 int16_t offset_high = High16Bits(offset); 4548 int16_t offset_low = Low16Bits(offset); 4549 offset_high += (offset_low < 0) ? 1 : 0; // Account for offset sign extension in load/store. 4550 Aui(AT, base, offset_high); 4551 if (two_accesses && !IsInt<16>(static_cast<int32_t>(offset_low + kMipsWordSize))) { 4552 // Avoid overflow in the 16-bit offset of the load/store instruction when adding 4. 4553 Addiu(AT, AT, kMipsDoublewordSize); 4554 offset_low -= kMipsDoublewordSize; 4555 } 4556 offset = offset_low; 4557 } else { 4558 // Do not load the whole 32-bit `offset` if it can be represented as 4559 // a sum of three 16-bit signed offsets. This can save an instruction. 4560 // To simplify matters, only do this for a symmetric range of offsets from 4561 // about -96KB to about +96KB, allowing further addition of 4 when accessing 4562 // 64-bit variables with two 32-bit accesses. 4563 constexpr int32_t kMinOffsetForMediumAdjustment = 2 * kMinOffsetForSimpleAdjustment; 4564 constexpr int32_t kMaxOffsetForMediumAdjustment = 3 * kMinOffsetForSimpleAdjustment; 4565 if (0 <= offset && offset <= kMaxOffsetForMediumAdjustment) { 4566 Addiu(AT, base, kMinOffsetForMediumAdjustment / 2); 4567 Addiu(AT, AT, kMinOffsetForMediumAdjustment / 2); 4568 offset -= kMinOffsetForMediumAdjustment; 4569 } else if (-kMaxOffsetForMediumAdjustment <= offset && offset < 0) { 4570 Addiu(AT, base, -kMinOffsetForMediumAdjustment / 2); 4571 Addiu(AT, AT, -kMinOffsetForMediumAdjustment / 2); 4572 offset += kMinOffsetForMediumAdjustment; 4573 } else { 4574 // Now that all shorter options have been exhausted, load the full 32-bit offset. 4575 int32_t loaded_offset = RoundDown(offset, kMipsDoublewordSize); 4576 LoadConst32(AT, loaded_offset); 4577 Addu(AT, AT, base); 4578 offset -= loaded_offset; 4579 } 4580 } 4581 base = AT; 4582 4583 CHECK(IsInt<16>(offset)); 4584 if (two_accesses) { 4585 CHECK(IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))); 4586 } 4587 CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1)); 4588 } 4589 4590 void MipsAssembler::AdjustBaseOffsetAndElementSizeShift(Register& base, 4591 int32_t& offset, 4592 int& element_size_shift) { 4593 // This method is used to adjust the base register, offset and element_size_shift 4594 // for a vector load/store when the offset doesn't fit into allowed number of bits. 4595 // MSA ld.df and st.df instructions take signed offsets as arguments, but maximum 4596 // offset is dependant on the size of the data format df (10-bit offsets for ld.b, 4597 // 11-bit for ld.h, 12-bit for ld.w and 13-bit for ld.d). 4598 // If element_size_shift is non-negative at entry, it won't be changed, but offset 4599 // will be checked for appropriate alignment. If negative at entry, it will be 4600 // adjusted based on offset for maximum fit. 4601 // It's assumed that `base` is a multiple of 8. 4602 CHECK_NE(base, AT); // Must not overwrite the register `base` while loading `offset`. 4603 4604 if (element_size_shift >= 0) { 4605 CHECK_LE(element_size_shift, TIMES_8); 4606 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); 4607 } else if (IsAligned<kMipsDoublewordSize>(offset)) { 4608 element_size_shift = TIMES_8; 4609 } else if (IsAligned<kMipsWordSize>(offset)) { 4610 element_size_shift = TIMES_4; 4611 } else if (IsAligned<kMipsHalfwordSize>(offset)) { 4612 element_size_shift = TIMES_2; 4613 } else { 4614 element_size_shift = TIMES_1; 4615 } 4616 4617 const int low_len = 10 + element_size_shift; // How many low bits of `offset` ld.df/st.df 4618 // will take. 4619 int16_t low = offset & ((1 << low_len) - 1); // Isolate these bits. 4620 low -= (low & (1 << (low_len - 1))) << 1; // Sign-extend these bits. 4621 if (low == offset) { 4622 return; // `offset` fits into ld.df/st.df. 4623 } 4624 4625 // First, see if `offset` can be represented as a sum of two or three signed offsets. 4626 // This can save an instruction or two. 4627 4628 // Max int16_t that's a multiple of element size. 4629 const int32_t kMaxDeltaForSimpleAdjustment = 0x8000 - (1 << element_size_shift); 4630 // Max ld.df/st.df offset that's a multiple of element size. 4631 const int32_t kMaxLoadStoreOffset = 0x1ff << element_size_shift; 4632 const int32_t kMaxOffsetForSimpleAdjustment = kMaxDeltaForSimpleAdjustment + kMaxLoadStoreOffset; 4633 const int32_t kMinOffsetForMediumAdjustment = 2 * kMaxDeltaForSimpleAdjustment; 4634 const int32_t kMaxOffsetForMediumAdjustment = kMinOffsetForMediumAdjustment + kMaxLoadStoreOffset; 4635 4636 if (IsInt<16>(offset)) { 4637 Addiu(AT, base, offset); 4638 offset = 0; 4639 } else if (0 <= offset && offset <= kMaxOffsetForSimpleAdjustment) { 4640 Addiu(AT, base, kMaxDeltaForSimpleAdjustment); 4641 offset -= kMaxDeltaForSimpleAdjustment; 4642 } else if (-kMaxOffsetForSimpleAdjustment <= offset && offset < 0) { 4643 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment); 4644 offset += kMaxDeltaForSimpleAdjustment; 4645 } else if (!IsR6() && 0 <= offset && offset <= kMaxOffsetForMediumAdjustment) { 4646 Addiu(AT, base, kMaxDeltaForSimpleAdjustment); 4647 if (offset <= kMinOffsetForMediumAdjustment) { 4648 Addiu(AT, AT, offset - kMaxDeltaForSimpleAdjustment); 4649 offset = 0; 4650 } else { 4651 Addiu(AT, AT, kMaxDeltaForSimpleAdjustment); 4652 offset -= kMinOffsetForMediumAdjustment; 4653 } 4654 } else if (!IsR6() && -kMaxOffsetForMediumAdjustment <= offset && offset < 0) { 4655 Addiu(AT, base, -kMaxDeltaForSimpleAdjustment); 4656 if (-kMinOffsetForMediumAdjustment <= offset) { 4657 Addiu(AT, AT, offset + kMaxDeltaForSimpleAdjustment); 4658 offset = 0; 4659 } else { 4660 Addiu(AT, AT, -kMaxDeltaForSimpleAdjustment); 4661 offset += kMinOffsetForMediumAdjustment; 4662 } 4663 } else { 4664 // 16-bit or smaller parts of `offset`: 4665 // |31 hi 16|15 mid 13-10|12-9 low 0| 4666 // 4667 // Instructions that supply each part as a signed integer addend: 4668 // |aui |addiu |ld.df/st.df | 4669 uint32_t tmp = static_cast<uint32_t>(offset) - low; // Exclude `low` from the rest of `offset` 4670 // (accounts for sign of `low`). 4671 tmp += (tmp & (UINT32_C(1) << 15)) << 1; // Account for sign extension in addiu. 4672 int16_t mid = Low16Bits(tmp); 4673 int16_t hi = High16Bits(tmp); 4674 if (IsR6()) { 4675 Aui(AT, base, hi); 4676 } else { 4677 Lui(AT, hi); 4678 Addu(AT, AT, base); 4679 } 4680 if (mid != 0) { 4681 Addiu(AT, AT, mid); 4682 } 4683 offset = low; 4684 } 4685 base = AT; 4686 CHECK_GE(JAVASTYLE_CTZ(offset), element_size_shift); 4687 CHECK(IsInt<10>(offset >> element_size_shift)); 4688 } 4689 4690 void MipsAssembler::LoadFromOffset(LoadOperandType type, 4691 Register reg, 4692 Register base, 4693 int32_t offset) { 4694 LoadFromOffset<>(type, reg, base, offset); 4695 } 4696 4697 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { 4698 LoadSFromOffset<>(reg, base, offset); 4699 } 4700 4701 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) { 4702 LoadDFromOffset<>(reg, base, offset); 4703 } 4704 4705 void MipsAssembler::LoadQFromOffset(FRegister reg, Register base, int32_t offset) { 4706 LoadQFromOffset<>(reg, base, offset); 4707 } 4708 4709 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, 4710 size_t size) { 4711 MipsManagedRegister dst = m_dst.AsMips(); 4712 if (dst.IsNoRegister()) { 4713 CHECK_EQ(0u, size) << dst; 4714 } else if (dst.IsCoreRegister()) { 4715 CHECK_EQ(kMipsWordSize, size) << dst; 4716 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); 4717 } else if (dst.IsRegisterPair()) { 4718 CHECK_EQ(kMipsDoublewordSize, size) << dst; 4719 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset); 4720 } else if (dst.IsFRegister()) { 4721 if (size == kMipsWordSize) { 4722 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); 4723 } else { 4724 CHECK_EQ(kMipsDoublewordSize, size) << dst; 4725 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset); 4726 } 4727 } else if (dst.IsDRegister()) { 4728 CHECK_EQ(kMipsDoublewordSize, size) << dst; 4729 LoadDFromOffset(dst.AsOverlappingDRegisterLow(), src_register, src_offset); 4730 } 4731 } 4732 4733 void MipsAssembler::StoreToOffset(StoreOperandType type, 4734 Register reg, 4735 Register base, 4736 int32_t offset) { 4737 StoreToOffset<>(type, reg, base, offset); 4738 } 4739 4740 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { 4741 StoreSToOffset<>(reg, base, offset); 4742 } 4743 4744 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) { 4745 StoreDToOffset<>(reg, base, offset); 4746 } 4747 4748 void MipsAssembler::StoreQToOffset(FRegister reg, Register base, int32_t offset) { 4749 StoreQToOffset<>(reg, base, offset); 4750 } 4751 4752 static dwarf::Reg DWARFReg(Register reg) { 4753 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 4754 } 4755 4756 constexpr size_t kFramePointerSize = 4; 4757 4758 void MipsAssembler::BuildFrame(size_t frame_size, 4759 ManagedRegister method_reg, 4760 ArrayRef<const ManagedRegister> callee_save_regs, 4761 const ManagedRegisterEntrySpills& entry_spills) { 4762 CHECK_ALIGNED(frame_size, kStackAlignment); 4763 DCHECK(!overwriting_); 4764 4765 // Increase frame to required size. 4766 IncreaseFrameSize(frame_size); 4767 4768 // Push callee saves and return address. 4769 int stack_offset = frame_size - kFramePointerSize; 4770 StoreToOffset(kStoreWord, RA, SP, stack_offset); 4771 cfi_.RelOffset(DWARFReg(RA), stack_offset); 4772 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 4773 stack_offset -= kFramePointerSize; 4774 Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); 4775 StoreToOffset(kStoreWord, reg, SP, stack_offset); 4776 cfi_.RelOffset(DWARFReg(reg), stack_offset); 4777 } 4778 4779 // Write out Method*. 4780 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); 4781 4782 // Write out entry spills. 4783 int32_t offset = frame_size + kFramePointerSize; 4784 for (size_t i = 0; i < entry_spills.size(); ++i) { 4785 MipsManagedRegister reg = entry_spills.at(i).AsMips(); 4786 if (reg.IsNoRegister()) { 4787 ManagedRegisterSpill spill = entry_spills.at(i); 4788 offset += spill.getSize(); 4789 } else if (reg.IsCoreRegister()) { 4790 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); 4791 offset += kMipsWordSize; 4792 } else if (reg.IsFRegister()) { 4793 StoreSToOffset(reg.AsFRegister(), SP, offset); 4794 offset += kMipsWordSize; 4795 } else if (reg.IsDRegister()) { 4796 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset); 4797 offset += kMipsDoublewordSize; 4798 } 4799 } 4800 } 4801 4802 void MipsAssembler::RemoveFrame(size_t frame_size, 4803 ArrayRef<const ManagedRegister> callee_save_regs, 4804 bool may_suspend ATTRIBUTE_UNUSED) { 4805 CHECK_ALIGNED(frame_size, kStackAlignment); 4806 DCHECK(!overwriting_); 4807 cfi_.RememberState(); 4808 4809 // Pop callee saves and return address. 4810 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 4811 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 4812 Register reg = callee_save_regs[i].AsMips().AsCoreRegister(); 4813 LoadFromOffset(kLoadWord, reg, SP, stack_offset); 4814 cfi_.Restore(DWARFReg(reg)); 4815 stack_offset += kFramePointerSize; 4816 } 4817 LoadFromOffset(kLoadWord, RA, SP, stack_offset); 4818 cfi_.Restore(DWARFReg(RA)); 4819 4820 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI. 4821 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size)); 4822 bool reordering = SetReorder(false); 4823 if (exchange) { 4824 // Jump to the return address. 4825 Jr(RA); 4826 // Decrease frame to required size. 4827 DecreaseFrameSize(frame_size); // Single instruction in delay slot. 4828 } else { 4829 // Decrease frame to required size. 4830 DecreaseFrameSize(frame_size); 4831 // Jump to the return address. 4832 Jr(RA); 4833 Nop(); // In delay slot. 4834 } 4835 SetReorder(reordering); 4836 4837 // The CFI should be restored for any code that follows the exit block. 4838 cfi_.RestoreState(); 4839 cfi_.DefCFAOffset(frame_size); 4840 } 4841 4842 void MipsAssembler::IncreaseFrameSize(size_t adjust) { 4843 CHECK_ALIGNED(adjust, kFramePointerSize); 4844 Addiu32(SP, SP, -adjust); 4845 cfi_.AdjustCFAOffset(adjust); 4846 if (overwriting_) { 4847 cfi_.OverrideDelayedPC(overwrite_location_); 4848 } 4849 } 4850 4851 void MipsAssembler::DecreaseFrameSize(size_t adjust) { 4852 CHECK_ALIGNED(adjust, kFramePointerSize); 4853 Addiu32(SP, SP, adjust); 4854 cfi_.AdjustCFAOffset(-adjust); 4855 if (overwriting_) { 4856 cfi_.OverrideDelayedPC(overwrite_location_); 4857 } 4858 } 4859 4860 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 4861 MipsManagedRegister src = msrc.AsMips(); 4862 if (src.IsNoRegister()) { 4863 CHECK_EQ(0u, size); 4864 } else if (src.IsCoreRegister()) { 4865 CHECK_EQ(kMipsWordSize, size); 4866 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 4867 } else if (src.IsRegisterPair()) { 4868 CHECK_EQ(kMipsDoublewordSize, size); 4869 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); 4870 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), 4871 SP, dest.Int32Value() + kMipsWordSize); 4872 } else if (src.IsFRegister()) { 4873 if (size == kMipsWordSize) { 4874 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); 4875 } else { 4876 CHECK_EQ(kMipsDoublewordSize, size); 4877 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value()); 4878 } 4879 } else if (src.IsDRegister()) { 4880 CHECK_EQ(kMipsDoublewordSize, size); 4881 StoreDToOffset(src.AsOverlappingDRegisterLow(), SP, dest.Int32Value()); 4882 } 4883 } 4884 4885 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 4886 MipsManagedRegister src = msrc.AsMips(); 4887 CHECK(src.IsCoreRegister()); 4888 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 4889 } 4890 4891 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 4892 MipsManagedRegister src = msrc.AsMips(); 4893 CHECK(src.IsCoreRegister()); 4894 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 4895 } 4896 4897 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 4898 ManagedRegister mscratch) { 4899 MipsManagedRegister scratch = mscratch.AsMips(); 4900 CHECK(scratch.IsCoreRegister()) << scratch; 4901 LoadConst32(scratch.AsCoreRegister(), imm); 4902 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 4903 } 4904 4905 void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs, 4906 FrameOffset fr_offs, 4907 ManagedRegister mscratch) { 4908 MipsManagedRegister scratch = mscratch.AsMips(); 4909 CHECK(scratch.IsCoreRegister()) << scratch; 4910 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); 4911 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 4912 S1, thr_offs.Int32Value()); 4913 } 4914 4915 void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) { 4916 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 4917 } 4918 4919 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 4920 FrameOffset in_off, ManagedRegister mscratch) { 4921 MipsManagedRegister src = msrc.AsMips(); 4922 MipsManagedRegister scratch = mscratch.AsMips(); 4923 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 4924 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); 4925 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 4926 } 4927 4928 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 4929 return EmitLoad(mdest, SP, src.Int32Value(), size); 4930 } 4931 4932 void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) { 4933 return EmitLoad(mdest, S1, src.Int32Value(), size); 4934 } 4935 4936 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 4937 MipsManagedRegister dest = mdest.AsMips(); 4938 CHECK(dest.IsCoreRegister()); 4939 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); 4940 } 4941 4942 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 4943 bool unpoison_reference) { 4944 MipsManagedRegister dest = mdest.AsMips(); 4945 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 4946 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 4947 base.AsMips().AsCoreRegister(), offs.Int32Value()); 4948 if (unpoison_reference) { 4949 MaybeUnpoisonHeapReference(dest.AsCoreRegister()); 4950 } 4951 } 4952 4953 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) { 4954 MipsManagedRegister dest = mdest.AsMips(); 4955 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 4956 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 4957 base.AsMips().AsCoreRegister(), offs.Int32Value()); 4958 } 4959 4960 void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) { 4961 MipsManagedRegister dest = mdest.AsMips(); 4962 CHECK(dest.IsCoreRegister()); 4963 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); 4964 } 4965 4966 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 4967 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 4968 } 4969 4970 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 4971 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 4972 } 4973 4974 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 4975 MipsManagedRegister dest = mdest.AsMips(); 4976 MipsManagedRegister src = msrc.AsMips(); 4977 if (!dest.Equals(src)) { 4978 if (dest.IsCoreRegister()) { 4979 CHECK(src.IsCoreRegister()) << src; 4980 Move(dest.AsCoreRegister(), src.AsCoreRegister()); 4981 } else if (dest.IsFRegister()) { 4982 CHECK(src.IsFRegister()) << src; 4983 if (size == kMipsWordSize) { 4984 MovS(dest.AsFRegister(), src.AsFRegister()); 4985 } else { 4986 CHECK_EQ(kMipsDoublewordSize, size); 4987 MovD(dest.AsFRegister(), src.AsFRegister()); 4988 } 4989 } else if (dest.IsDRegister()) { 4990 CHECK(src.IsDRegister()) << src; 4991 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow()); 4992 } else { 4993 CHECK(dest.IsRegisterPair()) << dest; 4994 CHECK(src.IsRegisterPair()) << src; 4995 // Ensure that the first move doesn't clobber the input of the second. 4996 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { 4997 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 4998 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 4999 } else { 5000 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 5001 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 5002 } 5003 } 5004 } 5005 } 5006 5007 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { 5008 MipsManagedRegister scratch = mscratch.AsMips(); 5009 CHECK(scratch.IsCoreRegister()) << scratch; 5010 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 5011 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 5012 } 5013 5014 void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs, 5015 ThreadOffset32 thr_offs, 5016 ManagedRegister mscratch) { 5017 MipsManagedRegister scratch = mscratch.AsMips(); 5018 CHECK(scratch.IsCoreRegister()) << scratch; 5019 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 5020 S1, thr_offs.Int32Value()); 5021 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 5022 SP, fr_offs.Int32Value()); 5023 } 5024 5025 void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs, 5026 FrameOffset fr_offs, 5027 ManagedRegister mscratch) { 5028 MipsManagedRegister scratch = mscratch.AsMips(); 5029 CHECK(scratch.IsCoreRegister()) << scratch; 5030 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 5031 SP, fr_offs.Int32Value()); 5032 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 5033 S1, thr_offs.Int32Value()); 5034 } 5035 5036 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) { 5037 MipsManagedRegister scratch = mscratch.AsMips(); 5038 CHECK(scratch.IsCoreRegister()) << scratch; 5039 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size; 5040 if (size == kMipsWordSize) { 5041 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 5042 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 5043 } else if (size == kMipsDoublewordSize) { 5044 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 5045 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 5046 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize); 5047 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 5048 } 5049 } 5050 5051 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 5052 ManagedRegister mscratch, size_t size) { 5053 Register scratch = mscratch.AsMips().AsCoreRegister(); 5054 CHECK_EQ(size, kMipsWordSize); 5055 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); 5056 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); 5057 } 5058 5059 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 5060 ManagedRegister mscratch, size_t size) { 5061 Register scratch = mscratch.AsMips().AsCoreRegister(); 5062 CHECK_EQ(size, kMipsWordSize); 5063 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 5064 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 5065 } 5066 5067 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 5068 FrameOffset src_base ATTRIBUTE_UNUSED, 5069 Offset src_offset ATTRIBUTE_UNUSED, 5070 ManagedRegister mscratch ATTRIBUTE_UNUSED, 5071 size_t size ATTRIBUTE_UNUSED) { 5072 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 5073 } 5074 5075 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, 5076 ManagedRegister src, Offset src_offset, 5077 ManagedRegister mscratch, size_t size) { 5078 CHECK_EQ(size, kMipsWordSize); 5079 Register scratch = mscratch.AsMips().AsCoreRegister(); 5080 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); 5081 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 5082 } 5083 5084 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 5085 Offset dest_offset ATTRIBUTE_UNUSED, 5086 FrameOffset src ATTRIBUTE_UNUSED, 5087 Offset src_offset ATTRIBUTE_UNUSED, 5088 ManagedRegister mscratch ATTRIBUTE_UNUSED, 5089 size_t size ATTRIBUTE_UNUSED) { 5090 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 5091 } 5092 5093 void MipsAssembler::MemoryBarrier(ManagedRegister) { 5094 // TODO: sync? 5095 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 5096 } 5097 5098 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 5099 FrameOffset handle_scope_offset, 5100 ManagedRegister min_reg, 5101 bool null_allowed) { 5102 MipsManagedRegister out_reg = mout_reg.AsMips(); 5103 MipsManagedRegister in_reg = min_reg.AsMips(); 5104 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; 5105 CHECK(out_reg.IsCoreRegister()) << out_reg; 5106 if (null_allowed) { 5107 MipsLabel null_arg; 5108 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 5109 // the address in the handle scope holding the reference. 5110 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset). 5111 if (in_reg.IsNoRegister()) { 5112 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 5113 SP, handle_scope_offset.Int32Value()); 5114 in_reg = out_reg; 5115 } 5116 if (!out_reg.Equals(in_reg)) { 5117 LoadConst32(out_reg.AsCoreRegister(), 0); 5118 } 5119 Beqz(in_reg.AsCoreRegister(), &null_arg); 5120 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 5121 Bind(&null_arg); 5122 } else { 5123 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 5124 } 5125 } 5126 5127 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, 5128 FrameOffset handle_scope_offset, 5129 ManagedRegister mscratch, 5130 bool null_allowed) { 5131 MipsManagedRegister scratch = mscratch.AsMips(); 5132 CHECK(scratch.IsCoreRegister()) << scratch; 5133 if (null_allowed) { 5134 MipsLabel null_arg; 5135 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 5136 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 5137 // the address in the handle scope holding the reference. 5138 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset). 5139 Beqz(scratch.AsCoreRegister(), &null_arg); 5140 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 5141 Bind(&null_arg); 5142 } else { 5143 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 5144 } 5145 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); 5146 } 5147 5148 // Given a handle scope entry, load the associated reference. 5149 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 5150 ManagedRegister min_reg) { 5151 MipsManagedRegister out_reg = mout_reg.AsMips(); 5152 MipsManagedRegister in_reg = min_reg.AsMips(); 5153 CHECK(out_reg.IsCoreRegister()) << out_reg; 5154 CHECK(in_reg.IsCoreRegister()) << in_reg; 5155 MipsLabel null_arg; 5156 if (!out_reg.Equals(in_reg)) { 5157 LoadConst32(out_reg.AsCoreRegister(), 0); 5158 } 5159 Beqz(in_reg.AsCoreRegister(), &null_arg); 5160 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 5161 in_reg.AsCoreRegister(), 0); 5162 Bind(&null_arg); 5163 } 5164 5165 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 5166 bool could_be_null ATTRIBUTE_UNUSED) { 5167 // TODO: not validating references. 5168 } 5169 5170 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 5171 bool could_be_null ATTRIBUTE_UNUSED) { 5172 // TODO: not validating references. 5173 } 5174 5175 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 5176 MipsManagedRegister base = mbase.AsMips(); 5177 MipsManagedRegister scratch = mscratch.AsMips(); 5178 CHECK(base.IsCoreRegister()) << base; 5179 CHECK(scratch.IsCoreRegister()) << scratch; 5180 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 5181 base.AsCoreRegister(), offset.Int32Value()); 5182 Jalr(scratch.AsCoreRegister()); 5183 NopIfNoReordering(); 5184 // TODO: place reference map on call. 5185 } 5186 5187 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 5188 MipsManagedRegister scratch = mscratch.AsMips(); 5189 CHECK(scratch.IsCoreRegister()) << scratch; 5190 // Call *(*(SP + base) + offset) 5191 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value()); 5192 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 5193 scratch.AsCoreRegister(), offset.Int32Value()); 5194 Jalr(scratch.AsCoreRegister()); 5195 NopIfNoReordering(); 5196 // TODO: place reference map on call. 5197 } 5198 5199 void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED, 5200 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 5201 UNIMPLEMENTED(FATAL) << "no mips implementation"; 5202 } 5203 5204 void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 5205 Move(tr.AsMips().AsCoreRegister(), S1); 5206 } 5207 5208 void MipsAssembler::GetCurrentThread(FrameOffset offset, 5209 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 5210 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 5211 } 5212 5213 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 5214 MipsManagedRegister scratch = mscratch.AsMips(); 5215 exception_blocks_.emplace_back(scratch, stack_adjust); 5216 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 5217 S1, Thread::ExceptionOffset<kMipsPointerSize>().Int32Value()); 5218 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry()); 5219 } 5220 5221 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) { 5222 Bind(exception->Entry()); 5223 if (exception->stack_adjust_ != 0) { // Fix up the frame. 5224 DecreaseFrameSize(exception->stack_adjust_); 5225 } 5226 // Pass exception object as argument. 5227 // Don't care about preserving A0 as this call won't return. 5228 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); 5229 Move(A0, exception->scratch_.AsCoreRegister()); 5230 // Set up call to Thread::Current()->pDeliverException. 5231 LoadFromOffset(kLoadWord, T9, S1, 5232 QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, pDeliverException).Int32Value()); 5233 Jr(T9); 5234 NopIfNoReordering(); 5235 5236 // Call never returns. 5237 Break(); 5238 } 5239 5240 } // namespace mips 5241 } // namespace art 5242