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 26namespace art { 27namespace mips { 28 29std::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 38void MipsAssembler::FinalizeCode() { 39 for (auto& exception_block : exception_blocks_) { 40 EmitExceptionPoll(&exception_block); 41 } 42 PromoteBranches(); 43} 44 45void 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 52void 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 102void 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 113void 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 125void 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 138void 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 148void 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 157void 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 163void 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 177void 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 186void MipsAssembler::Addu(Register rd, Register rs, Register rt) { 187 EmitR(0, rs, rt, rd, 0, 0x21); 188} 189 190void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { 191 EmitI(0x9, rs, rt, imm16); 192} 193 194void MipsAssembler::Subu(Register rd, Register rs, Register rt) { 195 EmitR(0, rs, rt, rd, 0, 0x23); 196} 197 198void MipsAssembler::MultR2(Register rs, Register rt) { 199 CHECK(!IsR6()); 200 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18); 201} 202 203void MipsAssembler::MultuR2(Register rs, Register rt) { 204 CHECK(!IsR6()); 205 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19); 206} 207 208void MipsAssembler::DivR2(Register rs, Register rt) { 209 CHECK(!IsR6()); 210 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a); 211} 212 213void MipsAssembler::DivuR2(Register rs, Register rt) { 214 CHECK(!IsR6()); 215 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b); 216} 217 218void MipsAssembler::MulR2(Register rd, Register rs, Register rt) { 219 CHECK(!IsR6()); 220 EmitR(0x1c, rs, rt, rd, 0, 2); 221} 222 223void MipsAssembler::DivR2(Register rd, Register rs, Register rt) { 224 CHECK(!IsR6()); 225 DivR2(rs, rt); 226 Mflo(rd); 227} 228 229void MipsAssembler::ModR2(Register rd, Register rs, Register rt) { 230 CHECK(!IsR6()); 231 DivR2(rs, rt); 232 Mfhi(rd); 233} 234 235void MipsAssembler::DivuR2(Register rd, Register rs, Register rt) { 236 CHECK(!IsR6()); 237 DivuR2(rs, rt); 238 Mflo(rd); 239} 240 241void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) { 242 CHECK(!IsR6()); 243 DivuR2(rs, rt); 244 Mfhi(rd); 245} 246 247void MipsAssembler::MulR6(Register rd, Register rs, Register rt) { 248 CHECK(IsR6()); 249 EmitR(0, rs, rt, rd, 2, 0x18); 250} 251 252void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) { 253 CHECK(IsR6()); 254 EmitR(0, rs, rt, rd, 3, 0x18); 255} 256 257void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) { 258 CHECK(IsR6()); 259 EmitR(0, rs, rt, rd, 3, 0x19); 260} 261 262void MipsAssembler::DivR6(Register rd, Register rs, Register rt) { 263 CHECK(IsR6()); 264 EmitR(0, rs, rt, rd, 2, 0x1a); 265} 266 267void MipsAssembler::ModR6(Register rd, Register rs, Register rt) { 268 CHECK(IsR6()); 269 EmitR(0, rs, rt, rd, 3, 0x1a); 270} 271 272void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) { 273 CHECK(IsR6()); 274 EmitR(0, rs, rt, rd, 2, 0x1b); 275} 276 277void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) { 278 CHECK(IsR6()); 279 EmitR(0, rs, rt, rd, 3, 0x1b); 280} 281 282void MipsAssembler::And(Register rd, Register rs, Register rt) { 283 EmitR(0, rs, rt, rd, 0, 0x24); 284} 285 286void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { 287 EmitI(0xc, rs, rt, imm16); 288} 289 290void MipsAssembler::Or(Register rd, Register rs, Register rt) { 291 EmitR(0, rs, rt, rd, 0, 0x25); 292} 293 294void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { 295 EmitI(0xd, rs, rt, imm16); 296} 297 298void MipsAssembler::Xor(Register rd, Register rs, Register rt) { 299 EmitR(0, rs, rt, rd, 0, 0x26); 300} 301 302void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { 303 EmitI(0xe, rs, rt, imm16); 304} 305 306void MipsAssembler::Nor(Register rd, Register rs, Register rt) { 307 EmitR(0, rs, rt, rd, 0, 0x27); 308} 309 310void MipsAssembler::Movz(Register rd, Register rs, Register rt) { 311 CHECK(!IsR6()); 312 EmitR(0, rs, rt, rd, 0, 0x0A); 313} 314 315void MipsAssembler::Movn(Register rd, Register rs, Register rt) { 316 CHECK(!IsR6()); 317 EmitR(0, rs, rt, rd, 0, 0x0B); 318} 319 320void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { 321 CHECK(IsR6()); 322 EmitR(0, rs, rt, rd, 0, 0x35); 323} 324 325void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { 326 CHECK(IsR6()); 327 EmitR(0, rs, rt, rd, 0, 0x37); 328} 329 330void MipsAssembler::ClzR6(Register rd, Register rs) { 331 CHECK(IsR6()); 332 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10); 333} 334 335void MipsAssembler::ClzR2(Register rd, Register rs) { 336 CHECK(!IsR6()); 337 EmitR(0x1C, rs, rd, rd, 0, 0x20); 338} 339 340void MipsAssembler::CloR6(Register rd, Register rs) { 341 CHECK(IsR6()); 342 EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11); 343} 344 345void MipsAssembler::CloR2(Register rd, Register rs) { 346 CHECK(!IsR6()); 347 EmitR(0x1C, rs, rd, rd, 0, 0x21); 348} 349 350void MipsAssembler::Seb(Register rd, Register rt) { 351 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20); 352} 353 354void MipsAssembler::Seh(Register rd, Register rt) { 355 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20); 356} 357 358void MipsAssembler::Wsbh(Register rd, Register rt) { 359 EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20); 360} 361 362void MipsAssembler::Bitswap(Register rd, Register rt) { 363 CHECK(IsR6()); 364 EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20); 365} 366 367void 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 372void 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 377void 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 382void 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 387void MipsAssembler::Sllv(Register rd, Register rt, Register rs) { 388 EmitR(0, rs, rt, rd, 0, 0x04); 389} 390 391void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { 392 EmitR(0, rs, rt, rd, 0, 0x06); 393} 394 395void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { 396 EmitR(0, rs, rt, rd, 1, 0x06); 397} 398 399void MipsAssembler::Srav(Register rd, Register rt, Register rs) { 400 EmitR(0, rs, rt, rd, 0, 0x07); 401} 402 403void 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 410void 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 417void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { 418 EmitI(0x20, rs, rt, imm16); 419} 420 421void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { 422 EmitI(0x21, rs, rt, imm16); 423} 424 425void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { 426 EmitI(0x23, rs, rt, imm16); 427} 428 429void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) { 430 CHECK(!IsR6()); 431 EmitI(0x22, rs, rt, imm16); 432} 433 434void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) { 435 CHECK(!IsR6()); 436 EmitI(0x26, rs, rt, imm16); 437} 438 439void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { 440 EmitI(0x24, rs, rt, imm16); 441} 442 443void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { 444 EmitI(0x25, rs, rt, imm16); 445} 446 447void MipsAssembler::Lui(Register rt, uint16_t imm16) { 448 EmitI(0xf, static_cast<Register>(0), rt, imm16); 449} 450 451void 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 456void MipsAssembler::Mfhi(Register rd) { 457 CHECK(!IsR6()); 458 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10); 459} 460 461void MipsAssembler::Mflo(Register rd) { 462 CHECK(!IsR6()); 463 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12); 464} 465 466void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { 467 EmitI(0x28, rs, rt, imm16); 468} 469 470void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { 471 EmitI(0x29, rs, rt, imm16); 472} 473 474void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { 475 EmitI(0x2b, rs, rt, imm16); 476} 477 478void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) { 479 CHECK(!IsR6()); 480 EmitI(0x2a, rs, rt, imm16); 481} 482 483void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) { 484 CHECK(!IsR6()); 485 EmitI(0x2e, rs, rt, imm16); 486} 487 488void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) { 489 CHECK(!IsR6()); 490 EmitI(0x30, base, rt, imm16); 491} 492 493void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) { 494 CHECK(!IsR6()); 495 EmitI(0x38, base, rt, imm16); 496} 497 498void 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 504void 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 510void MipsAssembler::Slt(Register rd, Register rs, Register rt) { 511 EmitR(0, rs, rt, rd, 0, 0x2a); 512} 513 514void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 515 EmitR(0, rs, rt, rd, 0, 0x2b); 516} 517 518void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 519 EmitI(0xa, rs, rt, imm16); 520} 521 522void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 523 EmitI(0xb, rs, rt, imm16); 524} 525 526void MipsAssembler::B(uint16_t imm16) { 527 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16); 528} 529 530void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { 531 EmitI(0x4, rs, rt, imm16); 532} 533 534void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { 535 EmitI(0x5, rs, rt, imm16); 536} 537 538void MipsAssembler::Beqz(Register rt, uint16_t imm16) { 539 Beq(ZERO, rt, imm16); 540} 541 542void MipsAssembler::Bnez(Register rt, uint16_t imm16) { 543 Bne(ZERO, rt, imm16); 544} 545 546void MipsAssembler::Bltz(Register rt, uint16_t imm16) { 547 EmitI(0x1, rt, static_cast<Register>(0), imm16); 548} 549 550void MipsAssembler::Bgez(Register rt, uint16_t imm16) { 551 EmitI(0x1, rt, static_cast<Register>(0x1), imm16); 552} 553 554void MipsAssembler::Blez(Register rt, uint16_t imm16) { 555 EmitI(0x6, rt, static_cast<Register>(0), imm16); 556} 557 558void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { 559 EmitI(0x7, rt, static_cast<Register>(0), imm16); 560} 561 562void MipsAssembler::Bc1f(uint16_t imm16) { 563 Bc1f(0, imm16); 564} 565 566void 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 572void MipsAssembler::Bc1t(uint16_t imm16) { 573 Bc1t(0, imm16); 574} 575 576void 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 582void MipsAssembler::J(uint32_t addr26) { 583 EmitI26(0x2, addr26); 584} 585 586void MipsAssembler::Jal(uint32_t addr26) { 587 EmitI26(0x3, addr26); 588} 589 590void MipsAssembler::Jalr(Register rd, Register rs) { 591 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09); 592} 593 594void MipsAssembler::Jalr(Register rs) { 595 Jalr(RA, rs); 596} 597 598void MipsAssembler::Jr(Register rs) { 599 Jalr(ZERO, rs); 600} 601 602void MipsAssembler::Nal() { 603 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0); 604} 605 606void MipsAssembler::Auipc(Register rs, uint16_t imm16) { 607 CHECK(IsR6()); 608 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16); 609} 610 611void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { 612 CHECK(IsR6()); 613 CHECK(IsUint<19>(imm19)) << imm19; 614 EmitI21(0x3B, rs, imm19); 615} 616 617void MipsAssembler::Bc(uint32_t imm26) { 618 CHECK(IsR6()); 619 EmitI26(0x32, imm26); 620} 621 622void MipsAssembler::Jic(Register rt, uint16_t imm16) { 623 CHECK(IsR6()); 624 EmitI(0x36, static_cast<Register>(0), rt, imm16); 625} 626 627void MipsAssembler::Jialc(Register rt, uint16_t imm16) { 628 CHECK(IsR6()); 629 EmitI(0x3E, static_cast<Register>(0), rt, imm16); 630} 631 632void 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 640void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { 641 CHECK(IsR6()); 642 CHECK_NE(rt, ZERO); 643 EmitI(0x17, rt, rt, imm16); 644} 645 646void 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 652void 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 660void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { 661 CHECK(IsR6()); 662 CHECK_NE(rt, ZERO); 663 EmitI(0x16, rt, rt, imm16); 664} 665 666void 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 672void 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 680void 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 688void 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 696void 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 704void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { 705 CHECK(IsR6()); 706 CHECK_NE(rs, ZERO); 707 EmitI21(0x36, rs, imm21); 708} 709 710void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { 711 CHECK(IsR6()); 712 CHECK_NE(rs, ZERO); 713 EmitI21(0x3E, rs, imm21); 714} 715 716void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { 717 CHECK(IsR6()); 718 EmitFI(0x11, 0x9, ft, imm16); 719} 720 721void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { 722 CHECK(IsR6()); 723 EmitFI(0x11, 0xD, ft, imm16); 724} 725 726void 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 780void 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 844void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 845 EmitFR(0x11, 0x10, ft, fs, fd, 0x0); 846} 847 848void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 849 EmitFR(0x11, 0x10, ft, fs, fd, 0x1); 850} 851 852void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 853 EmitFR(0x11, 0x10, ft, fs, fd, 0x2); 854} 855 856void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 857 EmitFR(0x11, 0x10, ft, fs, fd, 0x3); 858} 859 860void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { 861 EmitFR(0x11, 0x11, ft, fs, fd, 0x0); 862} 863 864void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { 865 EmitFR(0x11, 0x11, ft, fs, fd, 0x1); 866} 867 868void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { 869 EmitFR(0x11, 0x11, ft, fs, fd, 0x2); 870} 871 872void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { 873 EmitFR(0x11, 0x11, ft, fs, fd, 0x3); 874} 875 876void MipsAssembler::SqrtS(FRegister fd, FRegister fs) { 877 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4); 878} 879 880void MipsAssembler::SqrtD(FRegister fd, FRegister fs) { 881 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4); 882} 883 884void MipsAssembler::AbsS(FRegister fd, FRegister fs) { 885 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5); 886} 887 888void MipsAssembler::AbsD(FRegister fd, FRegister fs) { 889 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5); 890} 891 892void MipsAssembler::MovS(FRegister fd, FRegister fs) { 893 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6); 894} 895 896void MipsAssembler::MovD(FRegister fd, FRegister fs) { 897 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6); 898} 899 900void MipsAssembler::NegS(FRegister fd, FRegister fs) { 901 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7); 902} 903 904void MipsAssembler::NegD(FRegister fd, FRegister fs) { 905 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7); 906} 907 908void MipsAssembler::CunS(FRegister fs, FRegister ft) { 909 CunS(0, fs, ft); 910} 911 912void 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 918void MipsAssembler::CeqS(FRegister fs, FRegister ft) { 919 CeqS(0, fs, ft); 920} 921 922void 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 928void MipsAssembler::CueqS(FRegister fs, FRegister ft) { 929 CueqS(0, fs, ft); 930} 931 932void 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 938void MipsAssembler::ColtS(FRegister fs, FRegister ft) { 939 ColtS(0, fs, ft); 940} 941 942void 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 948void MipsAssembler::CultS(FRegister fs, FRegister ft) { 949 CultS(0, fs, ft); 950} 951 952void 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 958void MipsAssembler::ColeS(FRegister fs, FRegister ft) { 959 ColeS(0, fs, ft); 960} 961 962void 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 968void MipsAssembler::CuleS(FRegister fs, FRegister ft) { 969 CuleS(0, fs, ft); 970} 971 972void 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 978void MipsAssembler::CunD(FRegister fs, FRegister ft) { 979 CunD(0, fs, ft); 980} 981 982void 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 988void MipsAssembler::CeqD(FRegister fs, FRegister ft) { 989 CeqD(0, fs, ft); 990} 991 992void 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 998void MipsAssembler::CueqD(FRegister fs, FRegister ft) { 999 CueqD(0, fs, ft); 1000} 1001 1002void 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 1008void MipsAssembler::ColtD(FRegister fs, FRegister ft) { 1009 ColtD(0, fs, ft); 1010} 1011 1012void 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 1018void MipsAssembler::CultD(FRegister fs, FRegister ft) { 1019 CultD(0, fs, ft); 1020} 1021 1022void 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 1028void MipsAssembler::ColeD(FRegister fs, FRegister ft) { 1029 ColeD(0, fs, ft); 1030} 1031 1032void 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 1038void MipsAssembler::CuleD(FRegister fs, FRegister ft) { 1039 CuleD(0, fs, ft); 1040} 1041 1042void 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 1048void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { 1049 CHECK(IsR6()); 1050 EmitFR(0x11, 0x14, ft, fs, fd, 0x01); 1051} 1052 1053void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { 1054 CHECK(IsR6()); 1055 EmitFR(0x11, 0x14, ft, fs, fd, 0x02); 1056} 1057 1058void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { 1059 CHECK(IsR6()); 1060 EmitFR(0x11, 0x14, ft, fs, fd, 0x03); 1061} 1062 1063void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { 1064 CHECK(IsR6()); 1065 EmitFR(0x11, 0x14, ft, fs, fd, 0x04); 1066} 1067 1068void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { 1069 CHECK(IsR6()); 1070 EmitFR(0x11, 0x14, ft, fs, fd, 0x05); 1071} 1072 1073void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { 1074 CHECK(IsR6()); 1075 EmitFR(0x11, 0x14, ft, fs, fd, 0x06); 1076} 1077 1078void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { 1079 CHECK(IsR6()); 1080 EmitFR(0x11, 0x14, ft, fs, fd, 0x07); 1081} 1082 1083void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { 1084 CHECK(IsR6()); 1085 EmitFR(0x11, 0x14, ft, fs, fd, 0x11); 1086} 1087 1088void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { 1089 CHECK(IsR6()); 1090 EmitFR(0x11, 0x14, ft, fs, fd, 0x12); 1091} 1092 1093void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { 1094 CHECK(IsR6()); 1095 EmitFR(0x11, 0x14, ft, fs, fd, 0x13); 1096} 1097 1098void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { 1099 CHECK(IsR6()); 1100 EmitFR(0x11, 0x15, ft, fs, fd, 0x01); 1101} 1102 1103void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { 1104 CHECK(IsR6()); 1105 EmitFR(0x11, 0x15, ft, fs, fd, 0x02); 1106} 1107 1108void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { 1109 CHECK(IsR6()); 1110 EmitFR(0x11, 0x15, ft, fs, fd, 0x03); 1111} 1112 1113void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { 1114 CHECK(IsR6()); 1115 EmitFR(0x11, 0x15, ft, fs, fd, 0x04); 1116} 1117 1118void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { 1119 CHECK(IsR6()); 1120 EmitFR(0x11, 0x15, ft, fs, fd, 0x05); 1121} 1122 1123void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { 1124 CHECK(IsR6()); 1125 EmitFR(0x11, 0x15, ft, fs, fd, 0x06); 1126} 1127 1128void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { 1129 CHECK(IsR6()); 1130 EmitFR(0x11, 0x15, ft, fs, fd, 0x07); 1131} 1132 1133void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { 1134 CHECK(IsR6()); 1135 EmitFR(0x11, 0x15, ft, fs, fd, 0x11); 1136} 1137 1138void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { 1139 CHECK(IsR6()); 1140 EmitFR(0x11, 0x15, ft, fs, fd, 0x12); 1141} 1142 1143void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { 1144 CHECK(IsR6()); 1145 EmitFR(0x11, 0x15, ft, fs, fd, 0x13); 1146} 1147 1148void 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 1154void 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 1160void 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 1166void 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 1172void 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 1178void 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 1184void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) { 1185 CHECK(IsR6()); 1186 EmitFR(0x11, 0x10, ft, fs, fd, 0x10); 1187} 1188 1189void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) { 1190 CHECK(IsR6()); 1191 EmitFR(0x11, 0x11, ft, fs, fd, 0x10); 1192} 1193 1194void MipsAssembler::ClassS(FRegister fd, FRegister fs) { 1195 CHECK(IsR6()); 1196 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b); 1197} 1198 1199void MipsAssembler::ClassD(FRegister fd, FRegister fs) { 1200 CHECK(IsR6()); 1201 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b); 1202} 1203 1204void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) { 1205 CHECK(IsR6()); 1206 EmitFR(0x11, 0x10, ft, fs, fd, 0x1c); 1207} 1208 1209void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) { 1210 CHECK(IsR6()); 1211 EmitFR(0x11, 0x11, ft, fs, fd, 0x1c); 1212} 1213 1214void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) { 1215 CHECK(IsR6()); 1216 EmitFR(0x11, 0x10, ft, fs, fd, 0x1e); 1217} 1218 1219void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) { 1220 CHECK(IsR6()); 1221 EmitFR(0x11, 0x11, ft, fs, fd, 0x1e); 1222} 1223 1224void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { 1225 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09); 1226} 1227 1228void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { 1229 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09); 1230} 1231 1232void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { 1233 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D); 1234} 1235 1236void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { 1237 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D); 1238} 1239 1240void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { 1241 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20); 1242} 1243 1244void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { 1245 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21); 1246} 1247 1248void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { 1249 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20); 1250} 1251 1252void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { 1253 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21); 1254} 1255 1256void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { 1257 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20); 1258} 1259 1260void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { 1261 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21); 1262} 1263 1264void MipsAssembler::FloorWS(FRegister fd, FRegister fs) { 1265 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf); 1266} 1267 1268void MipsAssembler::FloorWD(FRegister fd, FRegister fs) { 1269 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf); 1270} 1271 1272void MipsAssembler::Mfc1(Register rt, FRegister fs) { 1273 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1274} 1275 1276void MipsAssembler::Mtc1(Register rt, FRegister fs) { 1277 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1278} 1279 1280void MipsAssembler::Mfhc1(Register rt, FRegister fs) { 1281 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1282} 1283 1284void MipsAssembler::Mthc1(Register rt, FRegister fs) { 1285 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1286} 1287 1288void 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 1297void 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 1306void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 1307 EmitI(0x31, rs, static_cast<Register>(ft), imm16); 1308} 1309 1310void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { 1311 EmitI(0x35, rs, static_cast<Register>(ft), imm16); 1312} 1313 1314void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 1315 EmitI(0x39, rs, static_cast<Register>(ft), imm16); 1316} 1317 1318void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { 1319 EmitI(0x3d, rs, static_cast<Register>(ft), imm16); 1320} 1321 1322void MipsAssembler::Break() { 1323 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), 1324 static_cast<Register>(0), 0, 0xD); 1325} 1326 1327void MipsAssembler::Nop() { 1328 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0); 1329} 1330 1331void MipsAssembler::Move(Register rd, Register rs) { 1332 Or(rd, rs, ZERO); 1333} 1334 1335void MipsAssembler::Clear(Register rd) { 1336 Move(rd, ZERO); 1337} 1338 1339void MipsAssembler::Not(Register rd, Register rs) { 1340 Nor(rd, rs, ZERO); 1341} 1342 1343void MipsAssembler::Push(Register rs) { 1344 IncreaseFrameSize(kMipsWordSize); 1345 Sw(rs, SP, 0); 1346} 1347 1348void MipsAssembler::Pop(Register rd) { 1349 Lw(rd, SP, 0); 1350 DecreaseFrameSize(kMipsWordSize); 1351} 1352 1353void MipsAssembler::PopAndReturn(Register rd, Register rt) { 1354 Lw(rd, SP, 0); 1355 Jr(rt); 1356 DecreaseFrameSize(kMipsWordSize); 1357} 1358 1359void 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 1373void 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 1384void 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 1403void 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 1433void 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 1442void 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 1459void 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 1468void 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 1474void 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 1503bool 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 1515bool 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 1529MipsAssembler::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 1539MipsAssembler::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 1596MipsAssembler::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 1608MipsAssembler::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 1649MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { 1650 return type_; 1651} 1652 1653MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { 1654 return condition_; 1655} 1656 1657Register MipsAssembler::Branch::GetLeftRegister() const { 1658 return static_cast<Register>(lhs_reg_); 1659} 1660 1661Register MipsAssembler::Branch::GetRightRegister() const { 1662 return static_cast<Register>(rhs_reg_); 1663} 1664 1665uint32_t MipsAssembler::Branch::GetTarget() const { 1666 return target_; 1667} 1668 1669uint32_t MipsAssembler::Branch::GetLocation() const { 1670 return location_; 1671} 1672 1673uint32_t MipsAssembler::Branch::GetOldLocation() const { 1674 return old_location_; 1675} 1676 1677uint32_t MipsAssembler::Branch::GetLength() const { 1678 return branch_info_[type_].length; 1679} 1680 1681uint32_t MipsAssembler::Branch::GetOldLength() const { 1682 return branch_info_[old_type_].length; 1683} 1684 1685uint32_t MipsAssembler::Branch::GetSize() const { 1686 return GetLength() * sizeof(uint32_t); 1687} 1688 1689uint32_t MipsAssembler::Branch::GetOldSize() const { 1690 return GetOldLength() * sizeof(uint32_t); 1691} 1692 1693uint32_t MipsAssembler::Branch::GetEndLocation() const { 1694 return GetLocation() + GetSize(); 1695} 1696 1697uint32_t MipsAssembler::Branch::GetOldEndLocation() const { 1698 return GetOldLocation() + GetOldSize(); 1699} 1700 1701bool 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 1725bool MipsAssembler::Branch::IsResolved() const { 1726 return target_ != kUnresolved; 1727} 1728 1729MipsAssembler::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 1737MipsAssembler::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 1760void MipsAssembler::Branch::Resolve(uint32_t target) { 1761 target_ = target; 1762} 1763 1764void 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 1776void 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 1805uint32_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 1835uint32_t MipsAssembler::Branch::GetOffsetLocation() const { 1836 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t); 1837} 1838 1839uint32_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 1850MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { 1851 CHECK_LT(branch_id, branches_.size()); 1852 return &branches_[branch_id]; 1853} 1854 1855const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { 1856 CHECK_LT(branch_id, branches_.size()); 1857 return &branches_[branch_id]; 1858} 1859 1860void 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 1891uint32_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 1903uint32_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 1926void 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 1945void 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 1951void 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 1961void 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 1967void 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. 2008const 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. 2029void 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 2155void MipsAssembler::B(MipsLabel* label) { 2156 Buncond(label); 2157} 2158 2159void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) { 2160 Call(label, indirect_reg); 2161} 2162 2163void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) { 2164 Bcond(label, kCondEQ, rs, rt); 2165} 2166 2167void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) { 2168 Bcond(label, kCondNE, rs, rt); 2169} 2170 2171void MipsAssembler::Beqz(Register rt, MipsLabel* label) { 2172 Bcond(label, kCondEQZ, rt); 2173} 2174 2175void MipsAssembler::Bnez(Register rt, MipsLabel* label) { 2176 Bcond(label, kCondNEZ, rt); 2177} 2178 2179void MipsAssembler::Bltz(Register rt, MipsLabel* label) { 2180 Bcond(label, kCondLTZ, rt); 2181} 2182 2183void MipsAssembler::Bgez(Register rt, MipsLabel* label) { 2184 Bcond(label, kCondGEZ, rt); 2185} 2186 2187void MipsAssembler::Blez(Register rt, MipsLabel* label) { 2188 Bcond(label, kCondLEZ, rt); 2189} 2190 2191void MipsAssembler::Bgtz(Register rt, MipsLabel* label) { 2192 Bcond(label, kCondGTZ, rt); 2193} 2194 2195void 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 2205void 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 2217void 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 2227void 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 2239void MipsAssembler::Bc1f(MipsLabel* label) { 2240 Bc1f(0, label); 2241} 2242 2243void MipsAssembler::Bc1f(int cc, MipsLabel* label) { 2244 CHECK(IsUint<3>(cc)) << cc; 2245 Bcond(label, kCondF, static_cast<Register>(cc), ZERO); 2246} 2247 2248void MipsAssembler::Bc1t(MipsLabel* label) { 2249 Bc1t(0, label); 2250} 2251 2252void MipsAssembler::Bc1t(int cc, MipsLabel* label) { 2253 CHECK(IsUint<3>(cc)) << cc; 2254 Bcond(label, kCondT, static_cast<Register>(cc), ZERO); 2255} 2256 2257void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) { 2258 Bcond(label, kCondF, static_cast<Register>(ft), ZERO); 2259} 2260 2261void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) { 2262 Bcond(label, kCondT, static_cast<Register>(ft), ZERO); 2263} 2264 2265void 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 2308void 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 2319void 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 2345void 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 2366void 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 2398void 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 2409void 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 2435static dwarf::Reg DWARFReg(Register reg) { 2436 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 2437} 2438 2439constexpr size_t kFramePointerSize = 4; 2440 2441void 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 2484void 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 2513void 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 2522void 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 2531void 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 2553void 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 2559void 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 2565void 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 2573void 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 2582void 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 2592void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) { 2593 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 2594} 2595 2596void 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 2605void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 2606 return EmitLoad(mdest, SP, src.Int32Value(), size); 2607} 2608 2609void MipsAssembler::LoadFromThread32(ManagedRegister mdest, 2610 ThreadOffset<kMipsWordSize> src, size_t size) { 2611 return EmitLoad(mdest, S1, src.Int32Value(), size); 2612} 2613 2614void 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 2620void 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 2631void 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 2638void 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 2645void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2646 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 2647} 2648 2649void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2650 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 2651} 2652 2653void 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 2686void 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 2693void 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 2704void 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 2715void 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 2730void 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 2738void 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 2746void 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 2754void 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 2763void 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 2772void MipsAssembler::MemoryBarrier(ManagedRegister) { 2773 // TODO: sync? 2774 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2775} 2776 2777void 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 2806void 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. 2828void 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 2844void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 2845 bool could_be_null ATTRIBUTE_UNUSED) { 2846 // TODO: not validating references. 2847} 2848 2849void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 2850 bool could_be_null ATTRIBUTE_UNUSED) { 2851 // TODO: not validating references. 2852} 2853 2854void 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 2866void 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 2878void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED, 2879 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2880 UNIMPLEMENTED(FATAL) << "no mips implementation"; 2881} 2882 2883void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 2884 Move(tr.AsMips().AsCoreRegister(), S1); 2885} 2886 2887void MipsAssembler::GetCurrentThread(FrameOffset offset, 2888 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2889 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 2890} 2891 2892void 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 2903void 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