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 std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { 30 if (rhs >= D0 && rhs < kNumberOfDRegisters) { 31 os << "d" << static_cast<int>(rhs); 32 } else { 33 os << "DRegister[" << static_cast<int>(rhs) << "]"; 34 } 35 return os; 36 } 37 38 void MipsAssembler::FinalizeCode() { 39 for (auto& exception_block : exception_blocks_) { 40 EmitExceptionPoll(&exception_block); 41 } 42 PromoteBranches(); 43 } 44 45 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) { 46 size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs(); 47 EmitBranches(); 48 Assembler::FinalizeInstructions(region); 49 PatchCFI(number_of_delayed_adjust_pcs); 50 } 51 52 void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) { 53 if (cfi().NumberOfDelayedAdvancePCs() == 0u) { 54 DCHECK_EQ(number_of_delayed_adjust_pcs, 0u); 55 return; 56 } 57 58 typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; 59 const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); 60 const std::vector<uint8_t>& old_stream = data.first; 61 const std::vector<DelayedAdvancePC>& advances = data.second; 62 63 // PCs recorded before EmitBranches() need to be adjusted. 64 // PCs recorded during EmitBranches() are already adjusted. 65 // Both ranges are separately sorted but they may overlap. 66 if (kIsDebugBuild) { 67 auto cmp = [](const DelayedAdvancePC& lhs, const DelayedAdvancePC& rhs) { 68 return lhs.pc < rhs.pc; 69 }; 70 CHECK(std::is_sorted(advances.begin(), advances.begin() + number_of_delayed_adjust_pcs, cmp)); 71 CHECK(std::is_sorted(advances.begin() + number_of_delayed_adjust_pcs, advances.end(), cmp)); 72 } 73 74 // Append initial CFI data if any. 75 size_t size = advances.size(); 76 DCHECK_NE(size, 0u); 77 cfi().AppendRawData(old_stream, 0u, advances[0].stream_pos); 78 // Emit PC adjustments interleaved with the old CFI stream. 79 size_t adjust_pos = 0u; 80 size_t late_emit_pos = number_of_delayed_adjust_pcs; 81 while (adjust_pos != number_of_delayed_adjust_pcs || late_emit_pos != size) { 82 size_t adjusted_pc = (adjust_pos != number_of_delayed_adjust_pcs) 83 ? GetAdjustedPosition(advances[adjust_pos].pc) 84 : static_cast<size_t>(-1); 85 size_t late_emit_pc = (late_emit_pos != size) 86 ? advances[late_emit_pos].pc 87 : static_cast<size_t>(-1); 88 size_t advance_pc = std::min(adjusted_pc, late_emit_pc); 89 DCHECK_NE(advance_pc, static_cast<size_t>(-1)); 90 size_t entry = (adjusted_pc <= late_emit_pc) ? adjust_pos : late_emit_pos; 91 if (adjusted_pc <= late_emit_pc) { 92 ++adjust_pos; 93 } else { 94 ++late_emit_pos; 95 } 96 cfi().AdvancePC(advance_pc); 97 size_t end_pos = (entry + 1u == size) ? old_stream.size() : advances[entry + 1u].stream_pos; 98 cfi().AppendRawData(old_stream, advances[entry].stream_pos, end_pos); 99 } 100 } 101 102 void MipsAssembler::EmitBranches() { 103 CHECK(!overwriting_); 104 // Switch from appending instructions at the end of the buffer to overwriting 105 // existing instructions (branch placeholders) in the buffer. 106 overwriting_ = true; 107 for (auto& branch : branches_) { 108 EmitBranch(&branch); 109 } 110 overwriting_ = false; 111 } 112 113 void MipsAssembler::Emit(uint32_t value) { 114 if (overwriting_) { 115 // Branches to labels are emitted into their placeholders here. 116 buffer_.Store<uint32_t>(overwrite_location_, value); 117 overwrite_location_ += sizeof(uint32_t); 118 } else { 119 // Other instructions are simply appended at the end here. 120 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 121 buffer_.Emit<uint32_t>(value); 122 } 123 } 124 125 void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) { 126 CHECK_NE(rs, kNoRegister); 127 CHECK_NE(rt, kNoRegister); 128 CHECK_NE(rd, kNoRegister); 129 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 130 static_cast<uint32_t>(rs) << kRsShift | 131 static_cast<uint32_t>(rt) << kRtShift | 132 static_cast<uint32_t>(rd) << kRdShift | 133 shamt << kShamtShift | 134 funct; 135 Emit(encoding); 136 } 137 138 void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) { 139 CHECK_NE(rs, kNoRegister); 140 CHECK_NE(rt, kNoRegister); 141 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 142 static_cast<uint32_t>(rs) << kRsShift | 143 static_cast<uint32_t>(rt) << kRtShift | 144 imm; 145 Emit(encoding); 146 } 147 148 void MipsAssembler::EmitI21(int opcode, Register rs, uint32_t imm21) { 149 CHECK_NE(rs, kNoRegister); 150 CHECK(IsUint<21>(imm21)) << imm21; 151 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 152 static_cast<uint32_t>(rs) << kRsShift | 153 imm21; 154 Emit(encoding); 155 } 156 157 void MipsAssembler::EmitI26(int opcode, uint32_t imm26) { 158 CHECK(IsUint<26>(imm26)) << imm26; 159 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | imm26; 160 Emit(encoding); 161 } 162 163 void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, 164 int funct) { 165 CHECK_NE(ft, kNoFRegister); 166 CHECK_NE(fs, kNoFRegister); 167 CHECK_NE(fd, kNoFRegister); 168 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 169 fmt << kFmtShift | 170 static_cast<uint32_t>(ft) << kFtShift | 171 static_cast<uint32_t>(fs) << kFsShift | 172 static_cast<uint32_t>(fd) << kFdShift | 173 funct; 174 Emit(encoding); 175 } 176 177 void MipsAssembler::EmitFI(int opcode, int fmt, FRegister ft, uint16_t imm) { 178 CHECK_NE(ft, kNoFRegister); 179 uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift | 180 fmt << kFmtShift | 181 static_cast<uint32_t>(ft) << kFtShift | 182 imm; 183 Emit(encoding); 184 } 185 186 void MipsAssembler::Addu(Register rd, Register rs, Register rt) { 187 EmitR(0, rs, rt, rd, 0, 0x21); 188 } 189 190 void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { 191 EmitI(0x9, rs, rt, imm16); 192 } 193 194 void MipsAssembler::Subu(Register rd, Register rs, Register rt) { 195 EmitR(0, rs, rt, rd, 0, 0x23); 196 } 197 198 void MipsAssembler::MultR2(Register rs, Register rt) { 199 CHECK(!IsR6()); 200 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18); 201 } 202 203 void MipsAssembler::MultuR2(Register rs, Register rt) { 204 CHECK(!IsR6()); 205 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19); 206 } 207 208 void MipsAssembler::DivR2(Register rs, Register rt) { 209 CHECK(!IsR6()); 210 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a); 211 } 212 213 void MipsAssembler::DivuR2(Register rs, Register rt) { 214 CHECK(!IsR6()); 215 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b); 216 } 217 218 void MipsAssembler::MulR2(Register rd, Register rs, Register rt) { 219 CHECK(!IsR6()); 220 EmitR(0x1c, rs, rt, rd, 0, 2); 221 } 222 223 void MipsAssembler::DivR2(Register rd, Register rs, Register rt) { 224 CHECK(!IsR6()); 225 DivR2(rs, rt); 226 Mflo(rd); 227 } 228 229 void MipsAssembler::ModR2(Register rd, Register rs, Register rt) { 230 CHECK(!IsR6()); 231 DivR2(rs, rt); 232 Mfhi(rd); 233 } 234 235 void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) { 236 CHECK(!IsR6()); 237 DivuR2(rs, rt); 238 Mflo(rd); 239 } 240 241 void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) { 242 CHECK(!IsR6()); 243 DivuR2(rs, rt); 244 Mfhi(rd); 245 } 246 247 void MipsAssembler::MulR6(Register rd, Register rs, Register rt) { 248 CHECK(IsR6()); 249 EmitR(0, rs, rt, rd, 2, 0x18); 250 } 251 252 void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) { 253 CHECK(IsR6()); 254 EmitR(0, rs, rt, rd, 3, 0x18); 255 } 256 257 void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) { 258 CHECK(IsR6()); 259 EmitR(0, rs, rt, rd, 3, 0x19); 260 } 261 262 void MipsAssembler::DivR6(Register rd, Register rs, Register rt) { 263 CHECK(IsR6()); 264 EmitR(0, rs, rt, rd, 2, 0x1a); 265 } 266 267 void MipsAssembler::ModR6(Register rd, Register rs, Register rt) { 268 CHECK(IsR6()); 269 EmitR(0, rs, rt, rd, 3, 0x1a); 270 } 271 272 void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) { 273 CHECK(IsR6()); 274 EmitR(0, rs, rt, rd, 2, 0x1b); 275 } 276 277 void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) { 278 CHECK(IsR6()); 279 EmitR(0, rs, rt, rd, 3, 0x1b); 280 } 281 282 void MipsAssembler::And(Register rd, Register rs, Register rt) { 283 EmitR(0, rs, rt, rd, 0, 0x24); 284 } 285 286 void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { 287 EmitI(0xc, rs, rt, imm16); 288 } 289 290 void MipsAssembler::Or(Register rd, Register rs, Register rt) { 291 EmitR(0, rs, rt, rd, 0, 0x25); 292 } 293 294 void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { 295 EmitI(0xd, rs, rt, imm16); 296 } 297 298 void MipsAssembler::Xor(Register rd, Register rs, Register rt) { 299 EmitR(0, rs, rt, rd, 0, 0x26); 300 } 301 302 void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { 303 EmitI(0xe, rs, rt, imm16); 304 } 305 306 void MipsAssembler::Nor(Register rd, Register rs, Register rt) { 307 EmitR(0, rs, rt, rd, 0, 0x27); 308 } 309 310 void MipsAssembler::Movz(Register rd, Register rs, Register rt) { 311 CHECK(!IsR6()); 312 EmitR(0, rs, rt, rd, 0, 0x0A); 313 } 314 315 void MipsAssembler::Movn(Register rd, Register rs, Register rt) { 316 CHECK(!IsR6()); 317 EmitR(0, rs, rt, rd, 0, 0x0B); 318 } 319 320 void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { 321 CHECK(IsR6()); 322 EmitR(0, rs, rt, rd, 0, 0x35); 323 } 324 325 void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { 326 CHECK(IsR6()); 327 EmitR(0, rs, rt, rd, 0, 0x37); 328 } 329 330 void MipsAssembler::ClzR6(Register rd, Register rs) { 331 CHECK(IsR6()); 332 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10); 333 } 334 335 void MipsAssembler::ClzR2(Register rd, Register rs) { 336 CHECK(!IsR6()); 337 EmitR(0x1C, rs, rd, rd, 0, 0x20); 338 } 339 340 void MipsAssembler::CloR6(Register rd, Register rs) { 341 CHECK(IsR6()); 342 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11); 343 } 344 345 void MipsAssembler::CloR2(Register rd, Register rs) { 346 CHECK(!IsR6()); 347 EmitR(0x1C, rs, rd, rd, 0, 0x21); 348 } 349 350 void MipsAssembler::Seb(Register rd, Register rt) { 351 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20); 352 } 353 354 void MipsAssembler::Seh(Register rd, Register rt) { 355 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20); 356 } 357 358 void MipsAssembler::Wsbh(Register rd, Register rt) { 359 EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20); 360 } 361 362 void MipsAssembler::Bitswap(Register rd, Register rt) { 363 CHECK(IsR6()); 364 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20); 365 } 366 367 void MipsAssembler::Sll(Register rd, Register rt, int shamt) { 368 CHECK(IsUint<5>(shamt)) << shamt; 369 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00); 370 } 371 372 void MipsAssembler::Srl(Register rd, Register rt, int shamt) { 373 CHECK(IsUint<5>(shamt)) << shamt; 374 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02); 375 } 376 377 void MipsAssembler::Rotr(Register rd, Register rt, int shamt) { 378 CHECK(IsUint<5>(shamt)) << shamt; 379 EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02); 380 } 381 382 void MipsAssembler::Sra(Register rd, Register rt, int shamt) { 383 CHECK(IsUint<5>(shamt)) << shamt; 384 EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03); 385 } 386 387 void MipsAssembler::Sllv(Register rd, Register rt, Register rs) { 388 EmitR(0, rs, rt, rd, 0, 0x04); 389 } 390 391 void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { 392 EmitR(0, rs, rt, rd, 0, 0x06); 393 } 394 395 void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { 396 EmitR(0, rs, rt, rd, 1, 0x06); 397 } 398 399 void MipsAssembler::Srav(Register rd, Register rt, Register rs) { 400 EmitR(0, rs, rt, rd, 0, 0x07); 401 } 402 403 void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) { 404 CHECK(IsUint<5>(pos)) << pos; 405 CHECK(0 < size && size <= 32) << size; 406 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 407 EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00); 408 } 409 410 void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) { 411 CHECK(IsUint<5>(pos)) << pos; 412 CHECK(0 < size && size <= 32) << size; 413 CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size; 414 EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04); 415 } 416 417 void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { 418 EmitI(0x20, rs, rt, imm16); 419 } 420 421 void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { 422 EmitI(0x21, rs, rt, imm16); 423 } 424 425 void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { 426 EmitI(0x23, rs, rt, imm16); 427 } 428 429 void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) { 430 CHECK(!IsR6()); 431 EmitI(0x22, rs, rt, imm16); 432 } 433 434 void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) { 435 CHECK(!IsR6()); 436 EmitI(0x26, rs, rt, imm16); 437 } 438 439 void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { 440 EmitI(0x24, rs, rt, imm16); 441 } 442 443 void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { 444 EmitI(0x25, rs, rt, imm16); 445 } 446 447 void MipsAssembler::Lui(Register rt, uint16_t imm16) { 448 EmitI(0xf, static_cast<Register>(0), rt, imm16); 449 } 450 451 void MipsAssembler::Sync(uint32_t stype) { 452 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 453 stype & 0x1f, 0xf); 454 } 455 456 void MipsAssembler::Mfhi(Register rd) { 457 CHECK(!IsR6()); 458 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10); 459 } 460 461 void MipsAssembler::Mflo(Register rd) { 462 CHECK(!IsR6()); 463 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12); 464 } 465 466 void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { 467 EmitI(0x28, rs, rt, imm16); 468 } 469 470 void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { 471 EmitI(0x29, rs, rt, imm16); 472 } 473 474 void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { 475 EmitI(0x2b, rs, rt, imm16); 476 } 477 478 void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) { 479 CHECK(!IsR6()); 480 EmitI(0x2a, rs, rt, imm16); 481 } 482 483 void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { 484 CHECK(!IsR6()); 485 EmitI(0x2e, rs, rt, imm16); 486 } 487 488 void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) { 489 CHECK(!IsR6()); 490 EmitI(0x30, base, rt, imm16); 491 } 492 493 void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) { 494 CHECK(!IsR6()); 495 EmitI(0x38, base, rt, imm16); 496 } 497 498 void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) { 499 CHECK(IsR6()); 500 CHECK(IsInt<9>(imm9)); 501 EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36); 502 } 503 504 void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) { 505 CHECK(IsR6()); 506 CHECK(IsInt<9>(imm9)); 507 EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26); 508 } 509 510 void MipsAssembler::Slt(Register rd, Register rs, Register rt) { 511 EmitR(0, rs, rt, rd, 0, 0x2a); 512 } 513 514 void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 515 EmitR(0, rs, rt, rd, 0, 0x2b); 516 } 517 518 void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 519 EmitI(0xa, rs, rt, imm16); 520 } 521 522 void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 523 EmitI(0xb, rs, rt, imm16); 524 } 525 526 void MipsAssembler::B(uint16_t imm16) { 527 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16); 528 } 529 530 void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { 531 EmitI(0x4, rs, rt, imm16); 532 } 533 534 void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { 535 EmitI(0x5, rs, rt, imm16); 536 } 537 538 void MipsAssembler::Beqz(Register rt, uint16_t imm16) { 539 Beq(ZERO, rt, imm16); 540 } 541 542 void MipsAssembler::Bnez(Register rt, uint16_t imm16) { 543 Bne(ZERO, rt, imm16); 544 } 545 546 void MipsAssembler::Bltz(Register rt, uint16_t imm16) { 547 EmitI(0x1, rt, static_cast<Register>(0), imm16); 548 } 549 550 void MipsAssembler::Bgez(Register rt, uint16_t imm16) { 551 EmitI(0x1, rt, static_cast<Register>(0x1), imm16); 552 } 553 554 void MipsAssembler::Blez(Register rt, uint16_t imm16) { 555 EmitI(0x6, rt, static_cast<Register>(0), imm16); 556 } 557 558 void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { 559 EmitI(0x7, rt, static_cast<Register>(0), imm16); 560 } 561 562 void MipsAssembler::Bc1f(uint16_t imm16) { 563 Bc1f(0, imm16); 564 } 565 566 void MipsAssembler::Bc1f(int cc, uint16_t imm16) { 567 CHECK(!IsR6()); 568 CHECK(IsUint<3>(cc)) << cc; 569 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16); 570 } 571 572 void MipsAssembler::Bc1t(uint16_t imm16) { 573 Bc1t(0, imm16); 574 } 575 576 void MipsAssembler::Bc1t(int cc, uint16_t imm16) { 577 CHECK(!IsR6()); 578 CHECK(IsUint<3>(cc)) << cc; 579 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16); 580 } 581 582 void MipsAssembler::J(uint32_t addr26) { 583 EmitI26(0x2, addr26); 584 } 585 586 void MipsAssembler::Jal(uint32_t addr26) { 587 EmitI26(0x3, addr26); 588 } 589 590 void MipsAssembler::Jalr(Register rd, Register rs) { 591 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09); 592 } 593 594 void MipsAssembler::Jalr(Register rs) { 595 Jalr(RA, rs); 596 } 597 598 void MipsAssembler::Jr(Register rs) { 599 Jalr(ZERO, rs); 600 } 601 602 void MipsAssembler::Nal() { 603 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0); 604 } 605 606 void MipsAssembler::Auipc(Register rs, uint16_t imm16) { 607 CHECK(IsR6()); 608 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16); 609 } 610 611 void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { 612 CHECK(IsR6()); 613 CHECK(IsUint<19>(imm19)) << imm19; 614 EmitI21(0x3B, rs, imm19); 615 } 616 617 void MipsAssembler::Bc(uint32_t imm26) { 618 CHECK(IsR6()); 619 EmitI26(0x32, imm26); 620 } 621 622 void MipsAssembler::Jic(Register rt, uint16_t imm16) { 623 CHECK(IsR6()); 624 EmitI(0x36, static_cast<Register>(0), rt, imm16); 625 } 626 627 void MipsAssembler::Jialc(Register rt, uint16_t imm16) { 628 CHECK(IsR6()); 629 EmitI(0x3E, static_cast<Register>(0), rt, imm16); 630 } 631 632 void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) { 633 CHECK(IsR6()); 634 CHECK_NE(rs, ZERO); 635 CHECK_NE(rt, ZERO); 636 CHECK_NE(rs, rt); 637 EmitI(0x17, rs, rt, imm16); 638 } 639 640 void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { 641 CHECK(IsR6()); 642 CHECK_NE(rt, ZERO); 643 EmitI(0x17, rt, rt, imm16); 644 } 645 646 void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) { 647 CHECK(IsR6()); 648 CHECK_NE(rt, ZERO); 649 EmitI(0x17, static_cast<Register>(0), rt, imm16); 650 } 651 652 void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) { 653 CHECK(IsR6()); 654 CHECK_NE(rs, ZERO); 655 CHECK_NE(rt, ZERO); 656 CHECK_NE(rs, rt); 657 EmitI(0x16, rs, rt, imm16); 658 } 659 660 void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { 661 CHECK(IsR6()); 662 CHECK_NE(rt, ZERO); 663 EmitI(0x16, rt, rt, imm16); 664 } 665 666 void MipsAssembler::Blezc(Register rt, uint16_t imm16) { 667 CHECK(IsR6()); 668 CHECK_NE(rt, ZERO); 669 EmitI(0x16, static_cast<Register>(0), rt, imm16); 670 } 671 672 void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) { 673 CHECK(IsR6()); 674 CHECK_NE(rs, ZERO); 675 CHECK_NE(rt, ZERO); 676 CHECK_NE(rs, rt); 677 EmitI(0x7, rs, rt, imm16); 678 } 679 680 void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) { 681 CHECK(IsR6()); 682 CHECK_NE(rs, ZERO); 683 CHECK_NE(rt, ZERO); 684 CHECK_NE(rs, rt); 685 EmitI(0x6, rs, rt, imm16); 686 } 687 688 void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) { 689 CHECK(IsR6()); 690 CHECK_NE(rs, ZERO); 691 CHECK_NE(rt, ZERO); 692 CHECK_NE(rs, rt); 693 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16); 694 } 695 696 void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) { 697 CHECK(IsR6()); 698 CHECK_NE(rs, ZERO); 699 CHECK_NE(rt, ZERO); 700 CHECK_NE(rs, rt); 701 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16); 702 } 703 704 void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { 705 CHECK(IsR6()); 706 CHECK_NE(rs, ZERO); 707 EmitI21(0x36, rs, imm21); 708 } 709 710 void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { 711 CHECK(IsR6()); 712 CHECK_NE(rs, ZERO); 713 EmitI21(0x3E, rs, imm21); 714 } 715 716 void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { 717 CHECK(IsR6()); 718 EmitFI(0x11, 0x9, ft, imm16); 719 } 720 721 void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { 722 CHECK(IsR6()); 723 EmitFI(0x11, 0xD, ft, imm16); 724 } 725 726 void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { 727 switch (cond) { 728 case kCondLTZ: 729 CHECK_EQ(rt, ZERO); 730 Bltz(rs, imm16); 731 break; 732 case kCondGEZ: 733 CHECK_EQ(rt, ZERO); 734 Bgez(rs, imm16); 735 break; 736 case kCondLEZ: 737 CHECK_EQ(rt, ZERO); 738 Blez(rs, imm16); 739 break; 740 case kCondGTZ: 741 CHECK_EQ(rt, ZERO); 742 Bgtz(rs, imm16); 743 break; 744 case kCondEQ: 745 Beq(rs, rt, imm16); 746 break; 747 case kCondNE: 748 Bne(rs, rt, imm16); 749 break; 750 case kCondEQZ: 751 CHECK_EQ(rt, ZERO); 752 Beqz(rs, imm16); 753 break; 754 case kCondNEZ: 755 CHECK_EQ(rt, ZERO); 756 Bnez(rs, imm16); 757 break; 758 case kCondF: 759 CHECK_EQ(rt, ZERO); 760 Bc1f(static_cast<int>(rs), imm16); 761 break; 762 case kCondT: 763 CHECK_EQ(rt, ZERO); 764 Bc1t(static_cast<int>(rs), imm16); 765 break; 766 case kCondLT: 767 case kCondGE: 768 case kCondLE: 769 case kCondGT: 770 case kCondLTU: 771 case kCondGEU: 772 case kUncond: 773 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 774 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 775 LOG(FATAL) << "Unexpected branch condition " << cond; 776 UNREACHABLE(); 777 } 778 } 779 780 void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { 781 switch (cond) { 782 case kCondLT: 783 Bltc(rs, rt, imm16_21); 784 break; 785 case kCondGE: 786 Bgec(rs, rt, imm16_21); 787 break; 788 case kCondLE: 789 Bgec(rt, rs, imm16_21); 790 break; 791 case kCondGT: 792 Bltc(rt, rs, imm16_21); 793 break; 794 case kCondLTZ: 795 CHECK_EQ(rt, ZERO); 796 Bltzc(rs, imm16_21); 797 break; 798 case kCondGEZ: 799 CHECK_EQ(rt, ZERO); 800 Bgezc(rs, imm16_21); 801 break; 802 case kCondLEZ: 803 CHECK_EQ(rt, ZERO); 804 Blezc(rs, imm16_21); 805 break; 806 case kCondGTZ: 807 CHECK_EQ(rt, ZERO); 808 Bgtzc(rs, imm16_21); 809 break; 810 case kCondEQ: 811 Beqc(rs, rt, imm16_21); 812 break; 813 case kCondNE: 814 Bnec(rs, rt, imm16_21); 815 break; 816 case kCondEQZ: 817 CHECK_EQ(rt, ZERO); 818 Beqzc(rs, imm16_21); 819 break; 820 case kCondNEZ: 821 CHECK_EQ(rt, ZERO); 822 Bnezc(rs, imm16_21); 823 break; 824 case kCondLTU: 825 Bltuc(rs, rt, imm16_21); 826 break; 827 case kCondGEU: 828 Bgeuc(rs, rt, imm16_21); 829 break; 830 case kCondF: 831 CHECK_EQ(rt, ZERO); 832 Bc1eqz(static_cast<FRegister>(rs), imm16_21); 833 break; 834 case kCondT: 835 CHECK_EQ(rt, ZERO); 836 Bc1nez(static_cast<FRegister>(rs), imm16_21); 837 break; 838 case kUncond: 839 LOG(FATAL) << "Unexpected branch condition " << cond; 840 UNREACHABLE(); 841 } 842 } 843 844 void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 845 EmitFR(0x11, 0x10, ft, fs, fd, 0x0); 846 } 847 848 void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 849 EmitFR(0x11, 0x10, ft, fs, fd, 0x1); 850 } 851 852 void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 853 EmitFR(0x11, 0x10, ft, fs, fd, 0x2); 854 } 855 856 void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 857 EmitFR(0x11, 0x10, ft, fs, fd, 0x3); 858 } 859 860 void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { 861 EmitFR(0x11, 0x11, ft, fs, fd, 0x0); 862 } 863 864 void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { 865 EmitFR(0x11, 0x11, ft, fs, fd, 0x1); 866 } 867 868 void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { 869 EmitFR(0x11, 0x11, ft, fs, fd, 0x2); 870 } 871 872 void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { 873 EmitFR(0x11, 0x11, ft, fs, fd, 0x3); 874 } 875 876 void MipsAssembler::SqrtS(FRegister fd, FRegister fs) { 877 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4); 878 } 879 880 void MipsAssembler::SqrtD(FRegister fd, FRegister fs) { 881 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4); 882 } 883 884 void MipsAssembler::AbsS(FRegister fd, FRegister fs) { 885 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5); 886 } 887 888 void MipsAssembler::AbsD(FRegister fd, FRegister fs) { 889 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5); 890 } 891 892 void MipsAssembler::MovS(FRegister fd, FRegister fs) { 893 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6); 894 } 895 896 void MipsAssembler::MovD(FRegister fd, FRegister fs) { 897 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6); 898 } 899 900 void MipsAssembler::NegS(FRegister fd, FRegister fs) { 901 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7); 902 } 903 904 void MipsAssembler::NegD(FRegister fd, FRegister fs) { 905 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7); 906 } 907 908 void MipsAssembler::CunS(FRegister fs, FRegister ft) { 909 CunS(0, fs, ft); 910 } 911 912 void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { 913 CHECK(!IsR6()); 914 CHECK(IsUint<3>(cc)) << cc; 915 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31); 916 } 917 918 void MipsAssembler::CeqS(FRegister fs, FRegister ft) { 919 CeqS(0, fs, ft); 920 } 921 922 void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { 923 CHECK(!IsR6()); 924 CHECK(IsUint<3>(cc)) << cc; 925 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32); 926 } 927 928 void MipsAssembler::CueqS(FRegister fs, FRegister ft) { 929 CueqS(0, fs, ft); 930 } 931 932 void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { 933 CHECK(!IsR6()); 934 CHECK(IsUint<3>(cc)) << cc; 935 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33); 936 } 937 938 void MipsAssembler::ColtS(FRegister fs, FRegister ft) { 939 ColtS(0, fs, ft); 940 } 941 942 void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { 943 CHECK(!IsR6()); 944 CHECK(IsUint<3>(cc)) << cc; 945 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34); 946 } 947 948 void MipsAssembler::CultS(FRegister fs, FRegister ft) { 949 CultS(0, fs, ft); 950 } 951 952 void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { 953 CHECK(!IsR6()); 954 CHECK(IsUint<3>(cc)) << cc; 955 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35); 956 } 957 958 void MipsAssembler::ColeS(FRegister fs, FRegister ft) { 959 ColeS(0, fs, ft); 960 } 961 962 void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { 963 CHECK(!IsR6()); 964 CHECK(IsUint<3>(cc)) << cc; 965 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36); 966 } 967 968 void MipsAssembler::CuleS(FRegister fs, FRegister ft) { 969 CuleS(0, fs, ft); 970 } 971 972 void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { 973 CHECK(!IsR6()); 974 CHECK(IsUint<3>(cc)) << cc; 975 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37); 976 } 977 978 void MipsAssembler::CunD(FRegister fs, FRegister ft) { 979 CunD(0, fs, ft); 980 } 981 982 void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { 983 CHECK(!IsR6()); 984 CHECK(IsUint<3>(cc)) << cc; 985 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31); 986 } 987 988 void MipsAssembler::CeqD(FRegister fs, FRegister ft) { 989 CeqD(0, fs, ft); 990 } 991 992 void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { 993 CHECK(!IsR6()); 994 CHECK(IsUint<3>(cc)) << cc; 995 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32); 996 } 997 998 void MipsAssembler::CueqD(FRegister fs, FRegister ft) { 999 CueqD(0, fs, ft); 1000 } 1001 1002 void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { 1003 CHECK(!IsR6()); 1004 CHECK(IsUint<3>(cc)) << cc; 1005 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33); 1006 } 1007 1008 void MipsAssembler::ColtD(FRegister fs, FRegister ft) { 1009 ColtD(0, fs, ft); 1010 } 1011 1012 void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { 1013 CHECK(!IsR6()); 1014 CHECK(IsUint<3>(cc)) << cc; 1015 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34); 1016 } 1017 1018 void MipsAssembler::CultD(FRegister fs, FRegister ft) { 1019 CultD(0, fs, ft); 1020 } 1021 1022 void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { 1023 CHECK(!IsR6()); 1024 CHECK(IsUint<3>(cc)) << cc; 1025 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35); 1026 } 1027 1028 void MipsAssembler::ColeD(FRegister fs, FRegister ft) { 1029 ColeD(0, fs, ft); 1030 } 1031 1032 void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { 1033 CHECK(!IsR6()); 1034 CHECK(IsUint<3>(cc)) << cc; 1035 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36); 1036 } 1037 1038 void MipsAssembler::CuleD(FRegister fs, FRegister ft) { 1039 CuleD(0, fs, ft); 1040 } 1041 1042 void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { 1043 CHECK(!IsR6()); 1044 CHECK(IsUint<3>(cc)) << cc; 1045 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37); 1046 } 1047 1048 void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { 1049 CHECK(IsR6()); 1050 EmitFR(0x11, 0x14, ft, fs, fd, 0x01); 1051 } 1052 1053 void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { 1054 CHECK(IsR6()); 1055 EmitFR(0x11, 0x14, ft, fs, fd, 0x02); 1056 } 1057 1058 void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { 1059 CHECK(IsR6()); 1060 EmitFR(0x11, 0x14, ft, fs, fd, 0x03); 1061 } 1062 1063 void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { 1064 CHECK(IsR6()); 1065 EmitFR(0x11, 0x14, ft, fs, fd, 0x04); 1066 } 1067 1068 void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { 1069 CHECK(IsR6()); 1070 EmitFR(0x11, 0x14, ft, fs, fd, 0x05); 1071 } 1072 1073 void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { 1074 CHECK(IsR6()); 1075 EmitFR(0x11, 0x14, ft, fs, fd, 0x06); 1076 } 1077 1078 void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { 1079 CHECK(IsR6()); 1080 EmitFR(0x11, 0x14, ft, fs, fd, 0x07); 1081 } 1082 1083 void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { 1084 CHECK(IsR6()); 1085 EmitFR(0x11, 0x14, ft, fs, fd, 0x11); 1086 } 1087 1088 void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { 1089 CHECK(IsR6()); 1090 EmitFR(0x11, 0x14, ft, fs, fd, 0x12); 1091 } 1092 1093 void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { 1094 CHECK(IsR6()); 1095 EmitFR(0x11, 0x14, ft, fs, fd, 0x13); 1096 } 1097 1098 void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { 1099 CHECK(IsR6()); 1100 EmitFR(0x11, 0x15, ft, fs, fd, 0x01); 1101 } 1102 1103 void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { 1104 CHECK(IsR6()); 1105 EmitFR(0x11, 0x15, ft, fs, fd, 0x02); 1106 } 1107 1108 void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { 1109 CHECK(IsR6()); 1110 EmitFR(0x11, 0x15, ft, fs, fd, 0x03); 1111 } 1112 1113 void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { 1114 CHECK(IsR6()); 1115 EmitFR(0x11, 0x15, ft, fs, fd, 0x04); 1116 } 1117 1118 void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { 1119 CHECK(IsR6()); 1120 EmitFR(0x11, 0x15, ft, fs, fd, 0x05); 1121 } 1122 1123 void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { 1124 CHECK(IsR6()); 1125 EmitFR(0x11, 0x15, ft, fs, fd, 0x06); 1126 } 1127 1128 void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { 1129 CHECK(IsR6()); 1130 EmitFR(0x11, 0x15, ft, fs, fd, 0x07); 1131 } 1132 1133 void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { 1134 CHECK(IsR6()); 1135 EmitFR(0x11, 0x15, ft, fs, fd, 0x11); 1136 } 1137 1138 void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { 1139 CHECK(IsR6()); 1140 EmitFR(0x11, 0x15, ft, fs, fd, 0x12); 1141 } 1142 1143 void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { 1144 CHECK(IsR6()); 1145 EmitFR(0x11, 0x15, ft, fs, fd, 0x13); 1146 } 1147 1148 void MipsAssembler::Movf(Register rd, Register rs, int cc) { 1149 CHECK(!IsR6()); 1150 CHECK(IsUint<3>(cc)) << cc; 1151 EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01); 1152 } 1153 1154 void MipsAssembler::Movt(Register rd, Register rs, int cc) { 1155 CHECK(!IsR6()); 1156 CHECK(IsUint<3>(cc)) << cc; 1157 EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01); 1158 } 1159 1160 void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) { 1161 CHECK(!IsR6()); 1162 CHECK(IsUint<3>(cc)) << cc; 1163 EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11); 1164 } 1165 1166 void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) { 1167 CHECK(!IsR6()); 1168 CHECK(IsUint<3>(cc)) << cc; 1169 EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11); 1170 } 1171 1172 void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) { 1173 CHECK(!IsR6()); 1174 CHECK(IsUint<3>(cc)) << cc; 1175 EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11); 1176 } 1177 1178 void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) { 1179 CHECK(!IsR6()); 1180 CHECK(IsUint<3>(cc)) << cc; 1181 EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11); 1182 } 1183 1184 void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) { 1185 CHECK(IsR6()); 1186 EmitFR(0x11, 0x10, ft, fs, fd, 0x10); 1187 } 1188 1189 void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) { 1190 CHECK(IsR6()); 1191 EmitFR(0x11, 0x11, ft, fs, fd, 0x10); 1192 } 1193 1194 void MipsAssembler::ClassS(FRegister fd, FRegister fs) { 1195 CHECK(IsR6()); 1196 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b); 1197 } 1198 1199 void MipsAssembler::ClassD(FRegister fd, FRegister fs) { 1200 CHECK(IsR6()); 1201 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b); 1202 } 1203 1204 void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) { 1205 CHECK(IsR6()); 1206 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c); 1207 } 1208 1209 void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) { 1210 CHECK(IsR6()); 1211 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c); 1212 } 1213 1214 void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) { 1215 CHECK(IsR6()); 1216 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e); 1217 } 1218 1219 void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) { 1220 CHECK(IsR6()); 1221 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e); 1222 } 1223 1224 void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { 1225 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09); 1226 } 1227 1228 void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { 1229 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09); 1230 } 1231 1232 void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { 1233 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D); 1234 } 1235 1236 void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { 1237 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D); 1238 } 1239 1240 void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { 1241 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20); 1242 } 1243 1244 void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { 1245 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21); 1246 } 1247 1248 void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { 1249 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20); 1250 } 1251 1252 void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { 1253 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21); 1254 } 1255 1256 void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { 1257 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20); 1258 } 1259 1260 void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { 1261 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21); 1262 } 1263 1264 void MipsAssembler::FloorWS(FRegister fd, FRegister fs) { 1265 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf); 1266 } 1267 1268 void MipsAssembler::FloorWD(FRegister fd, FRegister fs) { 1269 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf); 1270 } 1271 1272 void MipsAssembler::Mfc1(Register rt, FRegister fs) { 1273 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1274 } 1275 1276 void MipsAssembler::Mtc1(Register rt, FRegister fs) { 1277 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1278 } 1279 1280 void MipsAssembler::Mfhc1(Register rt, FRegister fs) { 1281 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1282 } 1283 1284 void MipsAssembler::Mthc1(Register rt, FRegister fs) { 1285 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1286 } 1287 1288 void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) { 1289 if (Is32BitFPU()) { 1290 CHECK_EQ(fs % 2, 0) << fs; 1291 Mfc1(rt, static_cast<FRegister>(fs + 1)); 1292 } else { 1293 Mfhc1(rt, fs); 1294 } 1295 } 1296 1297 void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) { 1298 if (Is32BitFPU()) { 1299 CHECK_EQ(fs % 2, 0) << fs; 1300 Mtc1(rt, static_cast<FRegister>(fs + 1)); 1301 } else { 1302 Mthc1(rt, fs); 1303 } 1304 } 1305 1306 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 1307 EmitI(0x31, rs, static_cast<Register>(ft), imm16); 1308 } 1309 1310 void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { 1311 EmitI(0x35, rs, static_cast<Register>(ft), imm16); 1312 } 1313 1314 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 1315 EmitI(0x39, rs, static_cast<Register>(ft), imm16); 1316 } 1317 1318 void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { 1319 EmitI(0x3d, rs, static_cast<Register>(ft), imm16); 1320 } 1321 1322 void MipsAssembler::Break() { 1323 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), 1324 static_cast<Register>(0), 0, 0xD); 1325 } 1326 1327 void MipsAssembler::Nop() { 1328 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0); 1329 } 1330 1331 void MipsAssembler::Move(Register rd, Register rs) { 1332 Or(rd, rs, ZERO); 1333 } 1334 1335 void MipsAssembler::Clear(Register rd) { 1336 Move(rd, ZERO); 1337 } 1338 1339 void MipsAssembler::Not(Register rd, Register rs) { 1340 Nor(rd, rs, ZERO); 1341 } 1342 1343 void MipsAssembler::Push(Register rs) { 1344 IncreaseFrameSize(kMipsWordSize); 1345 Sw(rs, SP, 0); 1346 } 1347 1348 void MipsAssembler::Pop(Register rd) { 1349 Lw(rd, SP, 0); 1350 DecreaseFrameSize(kMipsWordSize); 1351 } 1352 1353 void MipsAssembler::PopAndReturn(Register rd, Register rt) { 1354 Lw(rd, SP, 0); 1355 Jr(rt); 1356 DecreaseFrameSize(kMipsWordSize); 1357 } 1358 1359 void MipsAssembler::LoadConst32(Register rd, int32_t value) { 1360 if (IsUint<16>(value)) { 1361 // Use OR with (unsigned) immediate to encode 16b unsigned int. 1362 Ori(rd, ZERO, value); 1363 } else if (IsInt<16>(value)) { 1364 // Use ADD with (signed) immediate to encode 16b signed int. 1365 Addiu(rd, ZERO, value); 1366 } else { 1367 Lui(rd, High16Bits(value)); 1368 if (value & 0xFFFF) 1369 Ori(rd, rd, Low16Bits(value)); 1370 } 1371 } 1372 1373 void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) { 1374 uint32_t low = Low32Bits(value); 1375 uint32_t high = High32Bits(value); 1376 LoadConst32(reg_lo, low); 1377 if (high != low) { 1378 LoadConst32(reg_hi, high); 1379 } else { 1380 Move(reg_hi, reg_lo); 1381 } 1382 } 1383 1384 void MipsAssembler::StoreConst32ToOffset(int32_t value, 1385 Register base, 1386 int32_t offset, 1387 Register temp) { 1388 if (!IsInt<16>(offset)) { 1389 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value. 1390 LoadConst32(AT, offset); 1391 Addu(AT, AT, base); 1392 base = AT; 1393 offset = 0; 1394 } 1395 if (value == 0) { 1396 temp = ZERO; 1397 } else { 1398 LoadConst32(temp, value); 1399 } 1400 Sw(temp, base, offset); 1401 } 1402 1403 void MipsAssembler::StoreConst64ToOffset(int64_t value, 1404 Register base, 1405 int32_t offset, 1406 Register temp) { 1407 // IsInt<16> must be passed a signed value. 1408 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) { 1409 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value. 1410 LoadConst32(AT, offset); 1411 Addu(AT, AT, base); 1412 base = AT; 1413 offset = 0; 1414 } 1415 uint32_t low = Low32Bits(value); 1416 uint32_t high = High32Bits(value); 1417 if (low == 0) { 1418 Sw(ZERO, base, offset); 1419 } else { 1420 LoadConst32(temp, low); 1421 Sw(temp, base, offset); 1422 } 1423 if (high == 0) { 1424 Sw(ZERO, base, offset + kMipsWordSize); 1425 } else { 1426 if (high != low) { 1427 LoadConst32(temp, high); 1428 } 1429 Sw(temp, base, offset + kMipsWordSize); 1430 } 1431 } 1432 1433 void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) { 1434 if (value == 0) { 1435 temp = ZERO; 1436 } else { 1437 LoadConst32(temp, value); 1438 } 1439 Mtc1(temp, r); 1440 } 1441 1442 void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) { 1443 uint32_t low = Low32Bits(value); 1444 uint32_t high = High32Bits(value); 1445 if (low == 0) { 1446 Mtc1(ZERO, rd); 1447 } else { 1448 LoadConst32(temp, low); 1449 Mtc1(temp, rd); 1450 } 1451 if (high == 0) { 1452 MoveToFpuHigh(ZERO, rd); 1453 } else { 1454 LoadConst32(temp, high); 1455 MoveToFpuHigh(temp, rd); 1456 } 1457 } 1458 1459 void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) { 1460 if (IsInt<16>(value)) { 1461 Addiu(rt, rs, value); 1462 } else { 1463 LoadConst32(temp, value); 1464 Addu(rt, rs, temp); 1465 } 1466 } 1467 1468 void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size, 1469 MipsAssembler::Branch::Type short_type, 1470 MipsAssembler::Branch::Type long_type) { 1471 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; 1472 } 1473 1474 void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) { 1475 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_); 1476 if (is_r6) { 1477 // R6 1478 if (is_call) { 1479 InitShortOrLong(offset_size, kR6Call, kR6LongCall); 1480 } else if (condition_ == kUncond) { 1481 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch); 1482 } else { 1483 if (condition_ == kCondEQZ || condition_ == kCondNEZ) { 1484 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. 1485 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch; 1486 } else { 1487 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch); 1488 } 1489 } 1490 } else { 1491 // R2 1492 if (is_call) { 1493 InitShortOrLong(offset_size, kCall, kLongCall); 1494 } else if (condition_ == kUncond) { 1495 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch); 1496 } else { 1497 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch); 1498 } 1499 } 1500 old_type_ = type_; 1501 } 1502 1503 bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) { 1504 switch (condition) { 1505 case kCondLT: 1506 case kCondGT: 1507 case kCondNE: 1508 case kCondLTU: 1509 return lhs == rhs; 1510 default: 1511 return false; 1512 } 1513 } 1514 1515 bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) { 1516 switch (condition) { 1517 case kUncond: 1518 return true; 1519 case kCondGE: 1520 case kCondLE: 1521 case kCondEQ: 1522 case kCondGEU: 1523 return lhs == rhs; 1524 default: 1525 return false; 1526 } 1527 } 1528 1529 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target) 1530 : old_location_(location), 1531 location_(location), 1532 target_(target), 1533 lhs_reg_(0), 1534 rhs_reg_(0), 1535 condition_(kUncond) { 1536 InitializeType(false, is_r6); 1537 } 1538 1539 MipsAssembler::Branch::Branch(bool is_r6, 1540 uint32_t location, 1541 uint32_t target, 1542 MipsAssembler::BranchCondition condition, 1543 Register lhs_reg, 1544 Register rhs_reg) 1545 : old_location_(location), 1546 location_(location), 1547 target_(target), 1548 lhs_reg_(lhs_reg), 1549 rhs_reg_(rhs_reg), 1550 condition_(condition) { 1551 CHECK_NE(condition, kUncond); 1552 switch (condition) { 1553 case kCondLT: 1554 case kCondGE: 1555 case kCondLE: 1556 case kCondGT: 1557 case kCondLTU: 1558 case kCondGEU: 1559 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 1560 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 1561 // We leave this up to the caller. 1562 CHECK(is_r6); 1563 FALLTHROUGH_INTENDED; 1564 case kCondEQ: 1565 case kCondNE: 1566 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1567 // To compare with 0, use dedicated kCond*Z conditions. 1568 CHECK_NE(lhs_reg, ZERO); 1569 CHECK_NE(rhs_reg, ZERO); 1570 break; 1571 case kCondLTZ: 1572 case kCondGEZ: 1573 case kCondLEZ: 1574 case kCondGTZ: 1575 case kCondEQZ: 1576 case kCondNEZ: 1577 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1578 CHECK_NE(lhs_reg, ZERO); 1579 CHECK_EQ(rhs_reg, ZERO); 1580 break; 1581 case kCondF: 1582 case kCondT: 1583 CHECK_EQ(rhs_reg, ZERO); 1584 break; 1585 case kUncond: 1586 UNREACHABLE(); 1587 } 1588 CHECK(!IsNop(condition, lhs_reg, rhs_reg)); 1589 if (IsUncond(condition, lhs_reg, rhs_reg)) { 1590 // Branch condition is always true, make the branch unconditional. 1591 condition_ = kUncond; 1592 } 1593 InitializeType(false, is_r6); 1594 } 1595 1596 MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg) 1597 : old_location_(location), 1598 location_(location), 1599 target_(target), 1600 lhs_reg_(indirect_reg), 1601 rhs_reg_(0), 1602 condition_(kUncond) { 1603 CHECK_NE(indirect_reg, ZERO); 1604 CHECK_NE(indirect_reg, AT); 1605 InitializeType(true, is_r6); 1606 } 1607 1608 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( 1609 MipsAssembler::BranchCondition cond) { 1610 switch (cond) { 1611 case kCondLT: 1612 return kCondGE; 1613 case kCondGE: 1614 return kCondLT; 1615 case kCondLE: 1616 return kCondGT; 1617 case kCondGT: 1618 return kCondLE; 1619 case kCondLTZ: 1620 return kCondGEZ; 1621 case kCondGEZ: 1622 return kCondLTZ; 1623 case kCondLEZ: 1624 return kCondGTZ; 1625 case kCondGTZ: 1626 return kCondLEZ; 1627 case kCondEQ: 1628 return kCondNE; 1629 case kCondNE: 1630 return kCondEQ; 1631 case kCondEQZ: 1632 return kCondNEZ; 1633 case kCondNEZ: 1634 return kCondEQZ; 1635 case kCondLTU: 1636 return kCondGEU; 1637 case kCondGEU: 1638 return kCondLTU; 1639 case kCondF: 1640 return kCondT; 1641 case kCondT: 1642 return kCondF; 1643 case kUncond: 1644 LOG(FATAL) << "Unexpected branch condition " << cond; 1645 } 1646 UNREACHABLE(); 1647 } 1648 1649 MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { 1650 return type_; 1651 } 1652 1653 MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { 1654 return condition_; 1655 } 1656 1657 Register MipsAssembler::Branch::GetLeftRegister() const { 1658 return static_cast<Register>(lhs_reg_); 1659 } 1660 1661 Register MipsAssembler::Branch::GetRightRegister() const { 1662 return static_cast<Register>(rhs_reg_); 1663 } 1664 1665 uint32_t MipsAssembler::Branch::GetTarget() const { 1666 return target_; 1667 } 1668 1669 uint32_t MipsAssembler::Branch::GetLocation() const { 1670 return location_; 1671 } 1672 1673 uint32_t MipsAssembler::Branch::GetOldLocation() const { 1674 return old_location_; 1675 } 1676 1677 uint32_t MipsAssembler::Branch::GetLength() const { 1678 return branch_info_[type_].length; 1679 } 1680 1681 uint32_t MipsAssembler::Branch::GetOldLength() const { 1682 return branch_info_[old_type_].length; 1683 } 1684 1685 uint32_t MipsAssembler::Branch::GetSize() const { 1686 return GetLength() * sizeof(uint32_t); 1687 } 1688 1689 uint32_t MipsAssembler::Branch::GetOldSize() const { 1690 return GetOldLength() * sizeof(uint32_t); 1691 } 1692 1693 uint32_t MipsAssembler::Branch::GetEndLocation() const { 1694 return GetLocation() + GetSize(); 1695 } 1696 1697 uint32_t MipsAssembler::Branch::GetOldEndLocation() const { 1698 return GetOldLocation() + GetOldSize(); 1699 } 1700 1701 bool MipsAssembler::Branch::IsLong() const { 1702 switch (type_) { 1703 // R2 short branches. 1704 case kUncondBranch: 1705 case kCondBranch: 1706 case kCall: 1707 // R6 short branches. 1708 case kR6UncondBranch: 1709 case kR6CondBranch: 1710 case kR6Call: 1711 return false; 1712 // R2 long branches. 1713 case kLongUncondBranch: 1714 case kLongCondBranch: 1715 case kLongCall: 1716 // R6 long branches. 1717 case kR6LongUncondBranch: 1718 case kR6LongCondBranch: 1719 case kR6LongCall: 1720 return true; 1721 } 1722 UNREACHABLE(); 1723 } 1724 1725 bool MipsAssembler::Branch::IsResolved() const { 1726 return target_ != kUnresolved; 1727 } 1728 1729 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const { 1730 OffsetBits offset_size = 1731 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) 1732 ? kOffset23 1733 : branch_info_[type_].offset_size; 1734 return offset_size; 1735 } 1736 1737 MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location, 1738 uint32_t target) { 1739 // For unresolved targets assume the shortest encoding 1740 // (later it will be made longer if needed). 1741 if (target == kUnresolved) 1742 return kOffset16; 1743 int64_t distance = static_cast<int64_t>(target) - location; 1744 // To simplify calculations in composite branches consisting of multiple instructions 1745 // bump up the distance by a value larger than the max byte size of a composite branch. 1746 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; 1747 if (IsInt<kOffset16>(distance)) 1748 return kOffset16; 1749 else if (IsInt<kOffset18>(distance)) 1750 return kOffset18; 1751 else if (IsInt<kOffset21>(distance)) 1752 return kOffset21; 1753 else if (IsInt<kOffset23>(distance)) 1754 return kOffset23; 1755 else if (IsInt<kOffset28>(distance)) 1756 return kOffset28; 1757 return kOffset32; 1758 } 1759 1760 void MipsAssembler::Branch::Resolve(uint32_t target) { 1761 target_ = target; 1762 } 1763 1764 void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { 1765 if (location_ > expand_location) { 1766 location_ += delta; 1767 } 1768 if (!IsResolved()) { 1769 return; // Don't know the target yet. 1770 } 1771 if (target_ > expand_location) { 1772 target_ += delta; 1773 } 1774 } 1775 1776 void MipsAssembler::Branch::PromoteToLong() { 1777 switch (type_) { 1778 // R2 short branches. 1779 case kUncondBranch: 1780 type_ = kLongUncondBranch; 1781 break; 1782 case kCondBranch: 1783 type_ = kLongCondBranch; 1784 break; 1785 case kCall: 1786 type_ = kLongCall; 1787 break; 1788 // R6 short branches. 1789 case kR6UncondBranch: 1790 type_ = kR6LongUncondBranch; 1791 break; 1792 case kR6CondBranch: 1793 type_ = kR6LongCondBranch; 1794 break; 1795 case kR6Call: 1796 type_ = kR6LongCall; 1797 break; 1798 default: 1799 // Note: 'type_' is already long. 1800 break; 1801 } 1802 CHECK(IsLong()); 1803 } 1804 1805 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) { 1806 // If the branch is still unresolved or already long, nothing to do. 1807 if (IsLong() || !IsResolved()) { 1808 return 0; 1809 } 1810 // Promote the short branch to long if the offset size is too small 1811 // to hold the distance between location_ and target_. 1812 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) { 1813 PromoteToLong(); 1814 uint32_t old_size = GetOldSize(); 1815 uint32_t new_size = GetSize(); 1816 CHECK_GT(new_size, old_size); 1817 return new_size - old_size; 1818 } 1819 // The following logic is for debugging/testing purposes. 1820 // Promote some short branches to long when it's not really required. 1821 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) { 1822 int64_t distance = static_cast<int64_t>(target_) - location_; 1823 distance = (distance >= 0) ? distance : -distance; 1824 if (distance >= max_short_distance) { 1825 PromoteToLong(); 1826 uint32_t old_size = GetOldSize(); 1827 uint32_t new_size = GetSize(); 1828 CHECK_GT(new_size, old_size); 1829 return new_size - old_size; 1830 } 1831 } 1832 return 0; 1833 } 1834 1835 uint32_t MipsAssembler::Branch::GetOffsetLocation() const { 1836 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t); 1837 } 1838 1839 uint32_t MipsAssembler::Branch::GetOffset() const { 1840 CHECK(IsResolved()); 1841 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); 1842 // Calculate the byte distance between instructions and also account for 1843 // different PC-relative origins. 1844 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t); 1845 // Prepare the offset for encoding into the instruction(s). 1846 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; 1847 return offset; 1848 } 1849 1850 MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { 1851 CHECK_LT(branch_id, branches_.size()); 1852 return &branches_[branch_id]; 1853 } 1854 1855 const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { 1856 CHECK_LT(branch_id, branches_.size()); 1857 return &branches_[branch_id]; 1858 } 1859 1860 void MipsAssembler::Bind(MipsLabel* label) { 1861 CHECK(!label->IsBound()); 1862 uint32_t bound_pc = buffer_.Size(); 1863 1864 // Walk the list of branches referring to and preceding this label. 1865 // Store the previously unknown target addresses in them. 1866 while (label->IsLinked()) { 1867 uint32_t branch_id = label->Position(); 1868 Branch* branch = GetBranch(branch_id); 1869 branch->Resolve(bound_pc); 1870 1871 uint32_t branch_location = branch->GetLocation(); 1872 // Extract the location of the previous branch in the list (walking the list backwards; 1873 // the previous branch ID was stored in the space reserved for this branch). 1874 uint32_t prev = buffer_.Load<uint32_t>(branch_location); 1875 1876 // On to the previous branch in the list... 1877 label->position_ = prev; 1878 } 1879 1880 // Now make the label object contain its own location (relative to the end of the preceding 1881 // branch, if any; it will be used by the branches referring to and following this label). 1882 label->prev_branch_id_plus_one_ = branches_.size(); 1883 if (label->prev_branch_id_plus_one_) { 1884 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1885 const Branch* branch = GetBranch(branch_id); 1886 bound_pc -= branch->GetEndLocation(); 1887 } 1888 label->BindTo(bound_pc); 1889 } 1890 1891 uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const { 1892 CHECK(label->IsBound()); 1893 uint32_t target = label->Position(); 1894 if (label->prev_branch_id_plus_one_) { 1895 // Get label location based on the branch preceding it. 1896 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1897 const Branch* branch = GetBranch(branch_id); 1898 target += branch->GetEndLocation(); 1899 } 1900 return target; 1901 } 1902 1903 uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) { 1904 // We can reconstruct the adjustment by going through all the branches from the beginning 1905 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop 1906 // with increasing old_position, we can use the data from last AdjustedPosition() to 1907 // continue where we left off and the whole loop should be O(m+n) where m is the number 1908 // of positions to adjust and n is the number of branches. 1909 if (old_position < last_old_position_) { 1910 last_position_adjustment_ = 0; 1911 last_old_position_ = 0; 1912 last_branch_id_ = 0; 1913 } 1914 while (last_branch_id_ != branches_.size()) { 1915 const Branch* branch = GetBranch(last_branch_id_); 1916 if (branch->GetLocation() >= old_position + last_position_adjustment_) { 1917 break; 1918 } 1919 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); 1920 ++last_branch_id_; 1921 } 1922 last_old_position_ = old_position; 1923 return old_position + last_position_adjustment_; 1924 } 1925 1926 void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) { 1927 uint32_t length = branches_.back().GetLength(); 1928 if (!label->IsBound()) { 1929 // Branch forward (to a following label), distance is unknown. 1930 // The first branch forward will contain 0, serving as the terminator of 1931 // the list of forward-reaching branches. 1932 Emit(label->position_); 1933 length--; 1934 // Now make the label object point to this branch 1935 // (this forms a linked list of branches preceding this label). 1936 uint32_t branch_id = branches_.size() - 1; 1937 label->LinkTo(branch_id); 1938 } 1939 // Reserve space for the branch. 1940 while (length--) { 1941 Nop(); 1942 } 1943 } 1944 1945 void MipsAssembler::Buncond(MipsLabel* label) { 1946 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1947 branches_.emplace_back(IsR6(), buffer_.Size(), target); 1948 FinalizeLabeledBranch(label); 1949 } 1950 1951 void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) { 1952 // If lhs = rhs, this can be a NOP. 1953 if (Branch::IsNop(condition, lhs, rhs)) { 1954 return; 1955 } 1956 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1957 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs); 1958 FinalizeLabeledBranch(label); 1959 } 1960 1961 void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) { 1962 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1963 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg); 1964 FinalizeLabeledBranch(label); 1965 } 1966 1967 void MipsAssembler::PromoteBranches() { 1968 // Promote short branches to long as necessary. 1969 bool changed; 1970 do { 1971 changed = false; 1972 for (auto& branch : branches_) { 1973 CHECK(branch.IsResolved()); 1974 uint32_t delta = branch.PromoteIfNeeded(); 1975 // If this branch has been promoted and needs to expand in size, 1976 // relocate all branches by the expansion size. 1977 if (delta) { 1978 changed = true; 1979 uint32_t expand_location = branch.GetLocation(); 1980 for (auto& branch2 : branches_) { 1981 branch2.Relocate(expand_location, delta); 1982 } 1983 } 1984 } 1985 } while (changed); 1986 1987 // Account for branch expansion by resizing the code buffer 1988 // and moving the code in it to its final location. 1989 size_t branch_count = branches_.size(); 1990 if (branch_count > 0) { 1991 // Resize. 1992 Branch& last_branch = branches_[branch_count - 1]; 1993 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); 1994 uint32_t old_size = buffer_.Size(); 1995 buffer_.Resize(old_size + size_delta); 1996 // Move the code residing between branch placeholders. 1997 uint32_t end = old_size; 1998 for (size_t i = branch_count; i > 0; ) { 1999 Branch& branch = branches_[--i]; 2000 uint32_t size = end - branch.GetOldEndLocation(); 2001 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); 2002 end = branch.GetOldLocation(); 2003 } 2004 } 2005 } 2006 2007 // Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 2008 const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = { 2009 // R2 short branches. 2010 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch 2011 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch 2012 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall 2013 // R2 long branches. 2014 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch 2015 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch 2016 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall 2017 // R6 short branches. 2018 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch 2019 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch 2020 // Exception: kOffset23 for beqzc/bnezc. 2021 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call 2022 // R6 long branches. 2023 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch 2024 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch 2025 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall 2026 }; 2027 2028 // Note: make sure branch_info_[] and mitBranch() are kept synchronized. 2029 void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { 2030 CHECK_EQ(overwriting_, true); 2031 overwrite_location_ = branch->GetLocation(); 2032 uint32_t offset = branch->GetOffset(); 2033 BranchCondition condition = branch->GetCondition(); 2034 Register lhs = branch->GetLeftRegister(); 2035 Register rhs = branch->GetRightRegister(); 2036 switch (branch->GetType()) { 2037 // R2 short branches. 2038 case Branch::kUncondBranch: 2039 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2040 B(offset); 2041 Nop(); // TODO: improve by filling the delay slot. 2042 break; 2043 case Branch::kCondBranch: 2044 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2045 EmitBcondR2(condition, lhs, rhs, offset); 2046 Nop(); // TODO: improve by filling the delay slot. 2047 break; 2048 case Branch::kCall: 2049 Nal(); 2050 Nop(); // TODO: is this NOP really needed here? 2051 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2052 Addiu(lhs, RA, offset); 2053 Jalr(lhs); 2054 Nop(); 2055 break; 2056 2057 // R2 long branches. 2058 case Branch::kLongUncondBranch: 2059 // To get the value of the PC register we need to use the NAL instruction. 2060 // NAL clobbers the RA register. However, RA must be preserved if the 2061 // method is compiled without the entry/exit sequences that would take care 2062 // of preserving RA (typically, leaf methods don't preserve RA explicitly). 2063 // So, we need to preserve RA in some temporary storage ourselves. The AT 2064 // register can't be used for this because we need it to load a constant 2065 // which will be added to the value that NAL stores in RA. And we can't 2066 // use T9 for this in the context of the JNI compiler, which uses it 2067 // as a scratch register (see InterproceduralScratchRegister()). 2068 // If we were to add a 32-bit constant to RA using two ADDIU instructions, 2069 // we'd also need to use the ROTR instruction, which requires no less than 2070 // MIPSR2. 2071 // Perhaps, we could use T8 or one of R2's multiplier/divider registers 2072 // (LO or HI) or even a floating-point register, but that doesn't seem 2073 // like a nice solution. We may want this to work on both R6 and pre-R6. 2074 // For now simply use the stack for RA. This should be OK since for the 2075 // vast majority of code a short PC-relative branch is sufficient. 2076 // TODO: can this be improved? 2077 Push(RA); 2078 Nal(); 2079 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2080 Lui(AT, High16Bits(offset)); 2081 Ori(AT, AT, Low16Bits(offset)); 2082 Addu(AT, AT, RA); 2083 Lw(RA, SP, 0); 2084 Jr(AT); 2085 DecreaseFrameSize(kMipsWordSize); 2086 break; 2087 case Branch::kLongCondBranch: 2088 // The comment on case 'Branch::kLongUncondBranch' applies here as well. 2089 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the 2090 // number of instructions skipped: 2091 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). 2092 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); 2093 Push(RA); 2094 Nal(); 2095 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2096 Lui(AT, High16Bits(offset)); 2097 Ori(AT, AT, Low16Bits(offset)); 2098 Addu(AT, AT, RA); 2099 Lw(RA, SP, 0); 2100 Jr(AT); 2101 DecreaseFrameSize(kMipsWordSize); 2102 break; 2103 case Branch::kLongCall: 2104 Nal(); 2105 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2106 Lui(AT, High16Bits(offset)); 2107 Ori(AT, AT, Low16Bits(offset)); 2108 Addu(lhs, AT, RA); 2109 Jalr(lhs); 2110 Nop(); 2111 break; 2112 2113 // R6 short branches. 2114 case Branch::kR6UncondBranch: 2115 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2116 Bc(offset); 2117 break; 2118 case Branch::kR6CondBranch: 2119 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2120 EmitBcondR6(condition, lhs, rhs, offset); 2121 Nop(); // TODO: improve by filling the forbidden/delay slot. 2122 break; 2123 case Branch::kR6Call: 2124 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2125 Addiupc(lhs, offset); 2126 Jialc(lhs, 0); 2127 break; 2128 2129 // R6 long branches. 2130 case Branch::kR6LongUncondBranch: 2131 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 2132 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2133 Auipc(AT, High16Bits(offset)); 2134 Jic(AT, Low16Bits(offset)); 2135 break; 2136 case Branch::kR6LongCondBranch: 2137 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); 2138 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 2139 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2140 Auipc(AT, High16Bits(offset)); 2141 Jic(AT, Low16Bits(offset)); 2142 break; 2143 case Branch::kR6LongCall: 2144 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu. 2145 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 2146 Auipc(lhs, High16Bits(offset)); 2147 Addiu(lhs, lhs, Low16Bits(offset)); 2148 Jialc(lhs, 0); 2149 break; 2150 } 2151 CHECK_EQ(overwrite_location_, branch->GetEndLocation()); 2152 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); 2153 } 2154 2155 void MipsAssembler::B(MipsLabel* label) { 2156 Buncond(label); 2157 } 2158 2159 void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) { 2160 Call(label, indirect_reg); 2161 } 2162 2163 void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) { 2164 Bcond(label, kCondEQ, rs, rt); 2165 } 2166 2167 void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) { 2168 Bcond(label, kCondNE, rs, rt); 2169 } 2170 2171 void MipsAssembler::Beqz(Register rt, MipsLabel* label) { 2172 Bcond(label, kCondEQZ, rt); 2173 } 2174 2175 void MipsAssembler::Bnez(Register rt, MipsLabel* label) { 2176 Bcond(label, kCondNEZ, rt); 2177 } 2178 2179 void MipsAssembler::Bltz(Register rt, MipsLabel* label) { 2180 Bcond(label, kCondLTZ, rt); 2181 } 2182 2183 void MipsAssembler::Bgez(Register rt, MipsLabel* label) { 2184 Bcond(label, kCondGEZ, rt); 2185 } 2186 2187 void MipsAssembler::Blez(Register rt, MipsLabel* label) { 2188 Bcond(label, kCondLEZ, rt); 2189 } 2190 2191 void MipsAssembler::Bgtz(Register rt, MipsLabel* label) { 2192 Bcond(label, kCondGTZ, rt); 2193 } 2194 2195 void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) { 2196 if (IsR6()) { 2197 Bcond(label, kCondLT, rs, rt); 2198 } else if (!Branch::IsNop(kCondLT, rs, rt)) { 2199 // Synthesize the instruction (not available on R2). 2200 Slt(AT, rs, rt); 2201 Bnez(AT, label); 2202 } 2203 } 2204 2205 void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) { 2206 if (IsR6()) { 2207 Bcond(label, kCondGE, rs, rt); 2208 } else if (Branch::IsUncond(kCondGE, rs, rt)) { 2209 B(label); 2210 } else { 2211 // Synthesize the instruction (not available on R2). 2212 Slt(AT, rs, rt); 2213 Beqz(AT, label); 2214 } 2215 } 2216 2217 void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) { 2218 if (IsR6()) { 2219 Bcond(label, kCondLTU, rs, rt); 2220 } else if (!Branch::IsNop(kCondLTU, rs, rt)) { 2221 // Synthesize the instruction (not available on R2). 2222 Sltu(AT, rs, rt); 2223 Bnez(AT, label); 2224 } 2225 } 2226 2227 void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) { 2228 if (IsR6()) { 2229 Bcond(label, kCondGEU, rs, rt); 2230 } else if (Branch::IsUncond(kCondGEU, rs, rt)) { 2231 B(label); 2232 } else { 2233 // Synthesize the instruction (not available on R2). 2234 Sltu(AT, rs, rt); 2235 Beqz(AT, label); 2236 } 2237 } 2238 2239 void MipsAssembler::Bc1f(MipsLabel* label) { 2240 Bc1f(0, label); 2241 } 2242 2243 void MipsAssembler::Bc1f(int cc, MipsLabel* label) { 2244 CHECK(IsUint<3>(cc)) << cc; 2245 Bcond(label, kCondF, static_cast<Register>(cc), ZERO); 2246 } 2247 2248 void MipsAssembler::Bc1t(MipsLabel* label) { 2249 Bc1t(0, label); 2250 } 2251 2252 void MipsAssembler::Bc1t(int cc, MipsLabel* label) { 2253 CHECK(IsUint<3>(cc)) << cc; 2254 Bcond(label, kCondT, static_cast<Register>(cc), ZERO); 2255 } 2256 2257 void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) { 2258 Bcond(label, kCondF, static_cast<Register>(ft), ZERO); 2259 } 2260 2261 void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) { 2262 Bcond(label, kCondT, static_cast<Register>(ft), ZERO); 2263 } 2264 2265 void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base, 2266 int32_t offset) { 2267 // IsInt<16> must be passed a signed value. 2268 if (!IsInt<16>(offset) || 2269 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2270 LoadConst32(AT, offset); 2271 Addu(AT, AT, base); 2272 base = AT; 2273 offset = 0; 2274 } 2275 2276 switch (type) { 2277 case kLoadSignedByte: 2278 Lb(reg, base, offset); 2279 break; 2280 case kLoadUnsignedByte: 2281 Lbu(reg, base, offset); 2282 break; 2283 case kLoadSignedHalfword: 2284 Lh(reg, base, offset); 2285 break; 2286 case kLoadUnsignedHalfword: 2287 Lhu(reg, base, offset); 2288 break; 2289 case kLoadWord: 2290 Lw(reg, base, offset); 2291 break; 2292 case kLoadDoubleword: 2293 if (reg == base) { 2294 // This will clobber the base when loading the lower register. Since we have to load the 2295 // higher register as well, this will fail. Solution: reverse the order. 2296 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2297 Lw(reg, base, offset); 2298 } else { 2299 Lw(reg, base, offset); 2300 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2301 } 2302 break; 2303 default: 2304 LOG(FATAL) << "UNREACHABLE"; 2305 } 2306 } 2307 2308 void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { 2309 if (!IsInt<16>(offset)) { 2310 LoadConst32(AT, offset); 2311 Addu(AT, AT, base); 2312 base = AT; 2313 offset = 0; 2314 } 2315 2316 Lwc1(reg, base, offset); 2317 } 2318 2319 void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) { 2320 // IsInt<16> must be passed a signed value. 2321 if (!IsInt<16>(offset) || 2322 (!IsAligned<kMipsDoublewordSize>(offset) && 2323 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2324 LoadConst32(AT, offset); 2325 Addu(AT, AT, base); 2326 base = AT; 2327 offset = 0; 2328 } 2329 2330 if (offset & 0x7) { 2331 if (Is32BitFPU()) { 2332 Lwc1(reg, base, offset); 2333 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); 2334 } else { 2335 // 64-bit FPU. 2336 Lwc1(reg, base, offset); 2337 Lw(T8, base, offset + kMipsWordSize); 2338 Mthc1(T8, reg); 2339 } 2340 } else { 2341 Ldc1(reg, base, offset); 2342 } 2343 } 2344 2345 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, 2346 size_t size) { 2347 MipsManagedRegister dst = m_dst.AsMips(); 2348 if (dst.IsNoRegister()) { 2349 CHECK_EQ(0u, size) << dst; 2350 } else if (dst.IsCoreRegister()) { 2351 CHECK_EQ(kMipsWordSize, size) << dst; 2352 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); 2353 } else if (dst.IsRegisterPair()) { 2354 CHECK_EQ(kMipsDoublewordSize, size) << dst; 2355 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset); 2356 } else if (dst.IsFRegister()) { 2357 if (size == kMipsWordSize) { 2358 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); 2359 } else { 2360 CHECK_EQ(kMipsDoublewordSize, size) << dst; 2361 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset); 2362 } 2363 } 2364 } 2365 2366 void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base, 2367 int32_t offset) { 2368 // IsInt<16> must be passed a signed value. 2369 if (!IsInt<16>(offset) || 2370 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2371 LoadConst32(AT, offset); 2372 Addu(AT, AT, base); 2373 base = AT; 2374 offset = 0; 2375 } 2376 2377 switch (type) { 2378 case kStoreByte: 2379 Sb(reg, base, offset); 2380 break; 2381 case kStoreHalfword: 2382 Sh(reg, base, offset); 2383 break; 2384 case kStoreWord: 2385 Sw(reg, base, offset); 2386 break; 2387 case kStoreDoubleword: 2388 CHECK_NE(reg, base); 2389 CHECK_NE(static_cast<Register>(reg + 1), base); 2390 Sw(reg, base, offset); 2391 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2392 break; 2393 default: 2394 LOG(FATAL) << "UNREACHABLE"; 2395 } 2396 } 2397 2398 void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { 2399 if (!IsInt<16>(offset)) { 2400 LoadConst32(AT, offset); 2401 Addu(AT, AT, base); 2402 base = AT; 2403 offset = 0; 2404 } 2405 2406 Swc1(reg, base, offset); 2407 } 2408 2409 void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) { 2410 // IsInt<16> must be passed a signed value. 2411 if (!IsInt<16>(offset) || 2412 (!IsAligned<kMipsDoublewordSize>(offset) && 2413 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2414 LoadConst32(AT, offset); 2415 Addu(AT, AT, base); 2416 base = AT; 2417 offset = 0; 2418 } 2419 2420 if (offset & 0x7) { 2421 if (Is32BitFPU()) { 2422 Swc1(reg, base, offset); 2423 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); 2424 } else { 2425 // 64-bit FPU. 2426 Mfhc1(T8, reg); 2427 Swc1(reg, base, offset); 2428 Sw(T8, base, offset + kMipsWordSize); 2429 } 2430 } else { 2431 Sdc1(reg, base, offset); 2432 } 2433 } 2434 2435 static dwarf::Reg DWARFReg(Register reg) { 2436 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 2437 } 2438 2439 constexpr size_t kFramePointerSize = 4; 2440 2441 void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, 2442 const std::vector<ManagedRegister>& callee_save_regs, 2443 const ManagedRegisterEntrySpills& entry_spills) { 2444 CHECK_ALIGNED(frame_size, kStackAlignment); 2445 DCHECK(!overwriting_); 2446 2447 // Increase frame to required size. 2448 IncreaseFrameSize(frame_size); 2449 2450 // Push callee saves and return address. 2451 int stack_offset = frame_size - kFramePointerSize; 2452 StoreToOffset(kStoreWord, RA, SP, stack_offset); 2453 cfi_.RelOffset(DWARFReg(RA), stack_offset); 2454 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 2455 stack_offset -= kFramePointerSize; 2456 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 2457 StoreToOffset(kStoreWord, reg, SP, stack_offset); 2458 cfi_.RelOffset(DWARFReg(reg), stack_offset); 2459 } 2460 2461 // Write out Method*. 2462 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); 2463 2464 // Write out entry spills. 2465 int32_t offset = frame_size + kFramePointerSize; 2466 for (size_t i = 0; i < entry_spills.size(); ++i) { 2467 MipsManagedRegister reg = entry_spills.at(i).AsMips(); 2468 if (reg.IsNoRegister()) { 2469 ManagedRegisterSpill spill = entry_spills.at(i); 2470 offset += spill.getSize(); 2471 } else if (reg.IsCoreRegister()) { 2472 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); 2473 offset += kMipsWordSize; 2474 } else if (reg.IsFRegister()) { 2475 StoreSToOffset(reg.AsFRegister(), SP, offset); 2476 offset += kMipsWordSize; 2477 } else if (reg.IsDRegister()) { 2478 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset); 2479 offset += kMipsDoublewordSize; 2480 } 2481 } 2482 } 2483 2484 void MipsAssembler::RemoveFrame(size_t frame_size, 2485 const std::vector<ManagedRegister>& callee_save_regs) { 2486 CHECK_ALIGNED(frame_size, kStackAlignment); 2487 DCHECK(!overwriting_); 2488 cfi_.RememberState(); 2489 2490 // Pop callee saves and return address. 2491 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 2492 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 2493 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 2494 LoadFromOffset(kLoadWord, reg, SP, stack_offset); 2495 cfi_.Restore(DWARFReg(reg)); 2496 stack_offset += kFramePointerSize; 2497 } 2498 LoadFromOffset(kLoadWord, RA, SP, stack_offset); 2499 cfi_.Restore(DWARFReg(RA)); 2500 2501 // Decrease frame to required size. 2502 DecreaseFrameSize(frame_size); 2503 2504 // Then jump to the return address. 2505 Jr(RA); 2506 Nop(); 2507 2508 // The CFI should be restored for any code that follows the exit block. 2509 cfi_.RestoreState(); 2510 cfi_.DefCFAOffset(frame_size); 2511 } 2512 2513 void MipsAssembler::IncreaseFrameSize(size_t adjust) { 2514 CHECK_ALIGNED(adjust, kFramePointerSize); 2515 Addiu32(SP, SP, -adjust); 2516 cfi_.AdjustCFAOffset(adjust); 2517 if (overwriting_) { 2518 cfi_.OverrideDelayedPC(overwrite_location_); 2519 } 2520 } 2521 2522 void MipsAssembler::DecreaseFrameSize(size_t adjust) { 2523 CHECK_ALIGNED(adjust, kFramePointerSize); 2524 Addiu32(SP, SP, adjust); 2525 cfi_.AdjustCFAOffset(-adjust); 2526 if (overwriting_) { 2527 cfi_.OverrideDelayedPC(overwrite_location_); 2528 } 2529 } 2530 2531 void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 2532 MipsManagedRegister src = msrc.AsMips(); 2533 if (src.IsNoRegister()) { 2534 CHECK_EQ(0u, size); 2535 } else if (src.IsCoreRegister()) { 2536 CHECK_EQ(kMipsWordSize, size); 2537 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2538 } else if (src.IsRegisterPair()) { 2539 CHECK_EQ(kMipsDoublewordSize, size); 2540 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); 2541 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), 2542 SP, dest.Int32Value() + kMipsWordSize); 2543 } else if (src.IsFRegister()) { 2544 if (size == kMipsWordSize) { 2545 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); 2546 } else { 2547 CHECK_EQ(kMipsDoublewordSize, size); 2548 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value()); 2549 } 2550 } 2551 } 2552 2553 void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 2554 MipsManagedRegister src = msrc.AsMips(); 2555 CHECK(src.IsCoreRegister()); 2556 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2557 } 2558 2559 void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 2560 MipsManagedRegister src = msrc.AsMips(); 2561 CHECK(src.IsCoreRegister()); 2562 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2563 } 2564 2565 void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 2566 ManagedRegister mscratch) { 2567 MipsManagedRegister scratch = mscratch.AsMips(); 2568 CHECK(scratch.IsCoreRegister()) << scratch; 2569 LoadConst32(scratch.AsCoreRegister(), imm); 2570 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2571 } 2572 2573 void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm, 2574 ManagedRegister mscratch) { 2575 MipsManagedRegister scratch = mscratch.AsMips(); 2576 CHECK(scratch.IsCoreRegister()) << scratch; 2577 // Is this function even referenced anywhere else in the code? 2578 LoadConst32(scratch.AsCoreRegister(), imm); 2579 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value()); 2580 } 2581 2582 void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs, 2583 FrameOffset fr_offs, 2584 ManagedRegister mscratch) { 2585 MipsManagedRegister scratch = mscratch.AsMips(); 2586 CHECK(scratch.IsCoreRegister()) << scratch; 2587 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); 2588 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2589 S1, thr_offs.Int32Value()); 2590 } 2591 2592 void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) { 2593 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 2594 } 2595 2596 void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 2597 FrameOffset in_off, ManagedRegister mscratch) { 2598 MipsManagedRegister src = msrc.AsMips(); 2599 MipsManagedRegister scratch = mscratch.AsMips(); 2600 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2601 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); 2602 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 2603 } 2604 2605 void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 2606 return EmitLoad(mdest, SP, src.Int32Value(), size); 2607 } 2608 2609 void MipsAssembler::LoadFromThread32(ManagedRegister mdest, 2610 ThreadOffset<kMipsWordSize> src, size_t size) { 2611 return EmitLoad(mdest, S1, src.Int32Value(), size); 2612 } 2613 2614 void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 2615 MipsManagedRegister dest = mdest.AsMips(); 2616 CHECK(dest.IsCoreRegister()); 2617 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); 2618 } 2619 2620 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 2621 bool unpoison_reference) { 2622 MipsManagedRegister dest = mdest.AsMips(); 2623 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 2624 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 2625 base.AsMips().AsCoreRegister(), offs.Int32Value()); 2626 if (kPoisonHeapReferences && unpoison_reference) { 2627 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister()); 2628 } 2629 } 2630 2631 void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) { 2632 MipsManagedRegister dest = mdest.AsMips(); 2633 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 2634 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 2635 base.AsMips().AsCoreRegister(), offs.Int32Value()); 2636 } 2637 2638 void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest, 2639 ThreadOffset<kMipsWordSize> offs) { 2640 MipsManagedRegister dest = mdest.AsMips(); 2641 CHECK(dest.IsCoreRegister()); 2642 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); 2643 } 2644 2645 void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2646 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 2647 } 2648 2649 void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2650 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 2651 } 2652 2653 void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 2654 MipsManagedRegister dest = mdest.AsMips(); 2655 MipsManagedRegister src = msrc.AsMips(); 2656 if (!dest.Equals(src)) { 2657 if (dest.IsCoreRegister()) { 2658 CHECK(src.IsCoreRegister()) << src; 2659 Move(dest.AsCoreRegister(), src.AsCoreRegister()); 2660 } else if (dest.IsFRegister()) { 2661 CHECK(src.IsFRegister()) << src; 2662 if (size == kMipsWordSize) { 2663 MovS(dest.AsFRegister(), src.AsFRegister()); 2664 } else { 2665 CHECK_EQ(kMipsDoublewordSize, size); 2666 MovD(dest.AsFRegister(), src.AsFRegister()); 2667 } 2668 } else if (dest.IsDRegister()) { 2669 CHECK(src.IsDRegister()) << src; 2670 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow()); 2671 } else { 2672 CHECK(dest.IsRegisterPair()) << dest; 2673 CHECK(src.IsRegisterPair()) << src; 2674 // Ensure that the first move doesn't clobber the input of the second. 2675 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { 2676 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 2677 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 2678 } else { 2679 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 2680 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 2681 } 2682 } 2683 } 2684 } 2685 2686 void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { 2687 MipsManagedRegister scratch = mscratch.AsMips(); 2688 CHECK(scratch.IsCoreRegister()) << scratch; 2689 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2690 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2691 } 2692 2693 void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs, 2694 ThreadOffset<kMipsWordSize> thr_offs, 2695 ManagedRegister mscratch) { 2696 MipsManagedRegister scratch = mscratch.AsMips(); 2697 CHECK(scratch.IsCoreRegister()) << scratch; 2698 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2699 S1, thr_offs.Int32Value()); 2700 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2701 SP, fr_offs.Int32Value()); 2702 } 2703 2704 void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs, 2705 FrameOffset fr_offs, 2706 ManagedRegister mscratch) { 2707 MipsManagedRegister scratch = mscratch.AsMips(); 2708 CHECK(scratch.IsCoreRegister()) << scratch; 2709 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2710 SP, fr_offs.Int32Value()); 2711 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2712 S1, thr_offs.Int32Value()); 2713 } 2714 2715 void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) { 2716 MipsManagedRegister scratch = mscratch.AsMips(); 2717 CHECK(scratch.IsCoreRegister()) << scratch; 2718 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size; 2719 if (size == kMipsWordSize) { 2720 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2721 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2722 } else if (size == kMipsDoublewordSize) { 2723 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2724 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2725 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize); 2726 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 2727 } 2728 } 2729 2730 void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 2731 ManagedRegister mscratch, size_t size) { 2732 Register scratch = mscratch.AsMips().AsCoreRegister(); 2733 CHECK_EQ(size, kMipsWordSize); 2734 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); 2735 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); 2736 } 2737 2738 void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 2739 ManagedRegister mscratch, size_t size) { 2740 Register scratch = mscratch.AsMips().AsCoreRegister(); 2741 CHECK_EQ(size, kMipsWordSize); 2742 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 2743 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 2744 } 2745 2746 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2747 FrameOffset src_base ATTRIBUTE_UNUSED, 2748 Offset src_offset ATTRIBUTE_UNUSED, 2749 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2750 size_t size ATTRIBUTE_UNUSED) { 2751 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2752 } 2753 2754 void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, 2755 ManagedRegister src, Offset src_offset, 2756 ManagedRegister mscratch, size_t size) { 2757 CHECK_EQ(size, kMipsWordSize); 2758 Register scratch = mscratch.AsMips().AsCoreRegister(); 2759 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); 2760 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 2761 } 2762 2763 void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2764 Offset dest_offset ATTRIBUTE_UNUSED, 2765 FrameOffset src ATTRIBUTE_UNUSED, 2766 Offset src_offset ATTRIBUTE_UNUSED, 2767 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2768 size_t size ATTRIBUTE_UNUSED) { 2769 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2770 } 2771 2772 void MipsAssembler::MemoryBarrier(ManagedRegister) { 2773 // TODO: sync? 2774 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2775 } 2776 2777 void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 2778 FrameOffset handle_scope_offset, 2779 ManagedRegister min_reg, 2780 bool null_allowed) { 2781 MipsManagedRegister out_reg = mout_reg.AsMips(); 2782 MipsManagedRegister in_reg = min_reg.AsMips(); 2783 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; 2784 CHECK(out_reg.IsCoreRegister()) << out_reg; 2785 if (null_allowed) { 2786 MipsLabel null_arg; 2787 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2788 // the address in the handle scope holding the reference. 2789 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset). 2790 if (in_reg.IsNoRegister()) { 2791 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 2792 SP, handle_scope_offset.Int32Value()); 2793 in_reg = out_reg; 2794 } 2795 if (!out_reg.Equals(in_reg)) { 2796 LoadConst32(out_reg.AsCoreRegister(), 0); 2797 } 2798 Beqz(in_reg.AsCoreRegister(), &null_arg); 2799 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2800 Bind(&null_arg); 2801 } else { 2802 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2803 } 2804 } 2805 2806 void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, 2807 FrameOffset handle_scope_offset, 2808 ManagedRegister mscratch, 2809 bool null_allowed) { 2810 MipsManagedRegister scratch = mscratch.AsMips(); 2811 CHECK(scratch.IsCoreRegister()) << scratch; 2812 if (null_allowed) { 2813 MipsLabel null_arg; 2814 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2815 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2816 // the address in the handle scope holding the reference. 2817 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset). 2818 Beqz(scratch.AsCoreRegister(), &null_arg); 2819 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2820 Bind(&null_arg); 2821 } else { 2822 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2823 } 2824 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); 2825 } 2826 2827 // Given a handle scope entry, load the associated reference. 2828 void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 2829 ManagedRegister min_reg) { 2830 MipsManagedRegister out_reg = mout_reg.AsMips(); 2831 MipsManagedRegister in_reg = min_reg.AsMips(); 2832 CHECK(out_reg.IsCoreRegister()) << out_reg; 2833 CHECK(in_reg.IsCoreRegister()) << in_reg; 2834 MipsLabel null_arg; 2835 if (!out_reg.Equals(in_reg)) { 2836 LoadConst32(out_reg.AsCoreRegister(), 0); 2837 } 2838 Beqz(in_reg.AsCoreRegister(), &null_arg); 2839 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 2840 in_reg.AsCoreRegister(), 0); 2841 Bind(&null_arg); 2842 } 2843 2844 void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 2845 bool could_be_null ATTRIBUTE_UNUSED) { 2846 // TODO: not validating references. 2847 } 2848 2849 void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 2850 bool could_be_null ATTRIBUTE_UNUSED) { 2851 // TODO: not validating references. 2852 } 2853 2854 void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 2855 MipsManagedRegister base = mbase.AsMips(); 2856 MipsManagedRegister scratch = mscratch.AsMips(); 2857 CHECK(base.IsCoreRegister()) << base; 2858 CHECK(scratch.IsCoreRegister()) << scratch; 2859 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2860 base.AsCoreRegister(), offset.Int32Value()); 2861 Jalr(scratch.AsCoreRegister()); 2862 Nop(); 2863 // TODO: place reference map on call. 2864 } 2865 2866 void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 2867 MipsManagedRegister scratch = mscratch.AsMips(); 2868 CHECK(scratch.IsCoreRegister()) << scratch; 2869 // Call *(*(SP + base) + offset) 2870 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value()); 2871 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2872 scratch.AsCoreRegister(), offset.Int32Value()); 2873 Jalr(scratch.AsCoreRegister()); 2874 Nop(); 2875 // TODO: place reference map on call. 2876 } 2877 2878 void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED, 2879 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2880 UNIMPLEMENTED(FATAL) << "no mips implementation"; 2881 } 2882 2883 void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 2884 Move(tr.AsMips().AsCoreRegister(), S1); 2885 } 2886 2887 void MipsAssembler::GetCurrentThread(FrameOffset offset, 2888 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2889 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 2890 } 2891 2892 void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 2893 MipsManagedRegister scratch = mscratch.AsMips(); 2894 exception_blocks_.emplace_back(scratch, stack_adjust); 2895 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2896 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value()); 2897 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry()); 2898 // as the NAL instruction (occurring in long R2 branches) may become deprecated. 2899 // For now use common for R2 and R6 instructions as this code must execute on both. 2900 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry()); 2901 } 2902 2903 void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) { 2904 Bind(exception->Entry()); 2905 if (exception->stack_adjust_ != 0) { // Fix up the frame. 2906 DecreaseFrameSize(exception->stack_adjust_); 2907 } 2908 // Pass exception object as argument. 2909 // Don't care about preserving A0 as this call won't return. 2910 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); 2911 Move(A0, exception->scratch_.AsCoreRegister()); 2912 // Set up call to Thread::Current()->pDeliverException. 2913 LoadFromOffset(kLoadWord, T9, S1, 2914 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value()); 2915 Jr(T9); 2916 Nop(); 2917 2918 // Call never returns. 2919 Break(); 2920 } 2921 2922 } // namespace mips 2923 } // namespace art 2924