assembler_mips.cc revision 3acee732f9475fbfc6b046e0044b764e7ff5ac01
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::Slt(Register rd, Register rs, Register rt) { 489 EmitR(0, rs, rt, rd, 0, 0x2a); 490} 491 492void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 493 EmitR(0, rs, rt, rd, 0, 0x2b); 494} 495 496void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 497 EmitI(0xa, rs, rt, imm16); 498} 499 500void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 501 EmitI(0xb, rs, rt, imm16); 502} 503 504void MipsAssembler::B(uint16_t imm16) { 505 EmitI(0x4, static_cast<Register>(0), static_cast<Register>(0), imm16); 506} 507 508void MipsAssembler::Beq(Register rs, Register rt, uint16_t imm16) { 509 EmitI(0x4, rs, rt, imm16); 510} 511 512void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) { 513 EmitI(0x5, rs, rt, imm16); 514} 515 516void MipsAssembler::Beqz(Register rt, uint16_t imm16) { 517 Beq(ZERO, rt, imm16); 518} 519 520void MipsAssembler::Bnez(Register rt, uint16_t imm16) { 521 Bne(ZERO, rt, imm16); 522} 523 524void MipsAssembler::Bltz(Register rt, uint16_t imm16) { 525 EmitI(0x1, rt, static_cast<Register>(0), imm16); 526} 527 528void MipsAssembler::Bgez(Register rt, uint16_t imm16) { 529 EmitI(0x1, rt, static_cast<Register>(0x1), imm16); 530} 531 532void MipsAssembler::Blez(Register rt, uint16_t imm16) { 533 EmitI(0x6, rt, static_cast<Register>(0), imm16); 534} 535 536void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { 537 EmitI(0x7, rt, static_cast<Register>(0), imm16); 538} 539 540void MipsAssembler::Bc1f(int cc, uint16_t imm16) { 541 CHECK(!IsR6()); 542 CHECK(IsUint<3>(cc)) << cc; 543 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16); 544} 545 546void MipsAssembler::Bc1t(int cc, uint16_t imm16) { 547 CHECK(!IsR6()); 548 CHECK(IsUint<3>(cc)) << cc; 549 EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16); 550} 551 552void MipsAssembler::J(uint32_t addr26) { 553 EmitI26(0x2, addr26); 554} 555 556void MipsAssembler::Jal(uint32_t addr26) { 557 EmitI26(0x3, addr26); 558} 559 560void MipsAssembler::Jalr(Register rd, Register rs) { 561 EmitR(0, rs, static_cast<Register>(0), rd, 0, 0x09); 562} 563 564void MipsAssembler::Jalr(Register rs) { 565 Jalr(RA, rs); 566} 567 568void MipsAssembler::Jr(Register rs) { 569 Jalr(ZERO, rs); 570} 571 572void MipsAssembler::Nal() { 573 EmitI(0x1, static_cast<Register>(0), static_cast<Register>(0x10), 0); 574} 575 576void MipsAssembler::Auipc(Register rs, uint16_t imm16) { 577 CHECK(IsR6()); 578 EmitI(0x3B, rs, static_cast<Register>(0x1E), imm16); 579} 580 581void MipsAssembler::Addiupc(Register rs, uint32_t imm19) { 582 CHECK(IsR6()); 583 CHECK(IsUint<19>(imm19)) << imm19; 584 EmitI21(0x3B, rs, imm19); 585} 586 587void MipsAssembler::Bc(uint32_t imm26) { 588 CHECK(IsR6()); 589 EmitI26(0x32, imm26); 590} 591 592void MipsAssembler::Jic(Register rt, uint16_t imm16) { 593 CHECK(IsR6()); 594 EmitI(0x36, static_cast<Register>(0), rt, imm16); 595} 596 597void MipsAssembler::Jialc(Register rt, uint16_t imm16) { 598 CHECK(IsR6()); 599 EmitI(0x3E, static_cast<Register>(0), rt, imm16); 600} 601 602void MipsAssembler::Bltc(Register rs, Register rt, uint16_t imm16) { 603 CHECK(IsR6()); 604 CHECK_NE(rs, ZERO); 605 CHECK_NE(rt, ZERO); 606 CHECK_NE(rs, rt); 607 EmitI(0x17, rs, rt, imm16); 608} 609 610void MipsAssembler::Bltzc(Register rt, uint16_t imm16) { 611 CHECK(IsR6()); 612 CHECK_NE(rt, ZERO); 613 EmitI(0x17, rt, rt, imm16); 614} 615 616void MipsAssembler::Bgtzc(Register rt, uint16_t imm16) { 617 CHECK(IsR6()); 618 CHECK_NE(rt, ZERO); 619 EmitI(0x17, static_cast<Register>(0), rt, imm16); 620} 621 622void MipsAssembler::Bgec(Register rs, Register rt, uint16_t imm16) { 623 CHECK(IsR6()); 624 CHECK_NE(rs, ZERO); 625 CHECK_NE(rt, ZERO); 626 CHECK_NE(rs, rt); 627 EmitI(0x16, rs, rt, imm16); 628} 629 630void MipsAssembler::Bgezc(Register rt, uint16_t imm16) { 631 CHECK(IsR6()); 632 CHECK_NE(rt, ZERO); 633 EmitI(0x16, rt, rt, imm16); 634} 635 636void MipsAssembler::Blezc(Register rt, uint16_t imm16) { 637 CHECK(IsR6()); 638 CHECK_NE(rt, ZERO); 639 EmitI(0x16, static_cast<Register>(0), rt, imm16); 640} 641 642void MipsAssembler::Bltuc(Register rs, Register rt, uint16_t imm16) { 643 CHECK(IsR6()); 644 CHECK_NE(rs, ZERO); 645 CHECK_NE(rt, ZERO); 646 CHECK_NE(rs, rt); 647 EmitI(0x7, rs, rt, imm16); 648} 649 650void MipsAssembler::Bgeuc(Register rs, Register rt, uint16_t imm16) { 651 CHECK(IsR6()); 652 CHECK_NE(rs, ZERO); 653 CHECK_NE(rt, ZERO); 654 CHECK_NE(rs, rt); 655 EmitI(0x6, rs, rt, imm16); 656} 657 658void MipsAssembler::Beqc(Register rs, Register rt, uint16_t imm16) { 659 CHECK(IsR6()); 660 CHECK_NE(rs, ZERO); 661 CHECK_NE(rt, ZERO); 662 CHECK_NE(rs, rt); 663 EmitI(0x8, std::min(rs, rt), std::max(rs, rt), imm16); 664} 665 666void MipsAssembler::Bnec(Register rs, Register rt, uint16_t imm16) { 667 CHECK(IsR6()); 668 CHECK_NE(rs, ZERO); 669 CHECK_NE(rt, ZERO); 670 CHECK_NE(rs, rt); 671 EmitI(0x18, std::min(rs, rt), std::max(rs, rt), imm16); 672} 673 674void MipsAssembler::Beqzc(Register rs, uint32_t imm21) { 675 CHECK(IsR6()); 676 CHECK_NE(rs, ZERO); 677 EmitI21(0x36, rs, imm21); 678} 679 680void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { 681 CHECK(IsR6()); 682 CHECK_NE(rs, ZERO); 683 EmitI21(0x3E, rs, imm21); 684} 685 686void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { 687 CHECK(IsR6()); 688 EmitFI(0x11, 0x9, ft, imm16); 689} 690 691void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { 692 CHECK(IsR6()); 693 EmitFI(0x11, 0xD, ft, imm16); 694} 695 696void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { 697 switch (cond) { 698 case kCondLTZ: 699 CHECK_EQ(rt, ZERO); 700 Bltz(rs, imm16); 701 break; 702 case kCondGEZ: 703 CHECK_EQ(rt, ZERO); 704 Bgez(rs, imm16); 705 break; 706 case kCondLEZ: 707 CHECK_EQ(rt, ZERO); 708 Blez(rs, imm16); 709 break; 710 case kCondGTZ: 711 CHECK_EQ(rt, ZERO); 712 Bgtz(rs, imm16); 713 break; 714 case kCondEQ: 715 Beq(rs, rt, imm16); 716 break; 717 case kCondNE: 718 Bne(rs, rt, imm16); 719 break; 720 case kCondEQZ: 721 CHECK_EQ(rt, ZERO); 722 Beqz(rs, imm16); 723 break; 724 case kCondNEZ: 725 CHECK_EQ(rt, ZERO); 726 Bnez(rs, imm16); 727 break; 728 case kCondF: 729 CHECK_EQ(rt, ZERO); 730 Bc1f(static_cast<int>(rs), imm16); 731 break; 732 case kCondT: 733 CHECK_EQ(rt, ZERO); 734 Bc1t(static_cast<int>(rs), imm16); 735 break; 736 case kCondLT: 737 case kCondGE: 738 case kCondLE: 739 case kCondGT: 740 case kCondLTU: 741 case kCondGEU: 742 case kUncond: 743 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 744 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 745 LOG(FATAL) << "Unexpected branch condition " << cond; 746 UNREACHABLE(); 747 } 748} 749 750void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { 751 switch (cond) { 752 case kCondLT: 753 Bltc(rs, rt, imm16_21); 754 break; 755 case kCondGE: 756 Bgec(rs, rt, imm16_21); 757 break; 758 case kCondLE: 759 Bgec(rt, rs, imm16_21); 760 break; 761 case kCondGT: 762 Bltc(rt, rs, imm16_21); 763 break; 764 case kCondLTZ: 765 CHECK_EQ(rt, ZERO); 766 Bltzc(rs, imm16_21); 767 break; 768 case kCondGEZ: 769 CHECK_EQ(rt, ZERO); 770 Bgezc(rs, imm16_21); 771 break; 772 case kCondLEZ: 773 CHECK_EQ(rt, ZERO); 774 Blezc(rs, imm16_21); 775 break; 776 case kCondGTZ: 777 CHECK_EQ(rt, ZERO); 778 Bgtzc(rs, imm16_21); 779 break; 780 case kCondEQ: 781 Beqc(rs, rt, imm16_21); 782 break; 783 case kCondNE: 784 Bnec(rs, rt, imm16_21); 785 break; 786 case kCondEQZ: 787 CHECK_EQ(rt, ZERO); 788 Beqzc(rs, imm16_21); 789 break; 790 case kCondNEZ: 791 CHECK_EQ(rt, ZERO); 792 Bnezc(rs, imm16_21); 793 break; 794 case kCondLTU: 795 Bltuc(rs, rt, imm16_21); 796 break; 797 case kCondGEU: 798 Bgeuc(rs, rt, imm16_21); 799 break; 800 case kCondF: 801 CHECK_EQ(rt, ZERO); 802 Bc1eqz(static_cast<FRegister>(rs), imm16_21); 803 break; 804 case kCondT: 805 CHECK_EQ(rt, ZERO); 806 Bc1nez(static_cast<FRegister>(rs), imm16_21); 807 break; 808 case kUncond: 809 LOG(FATAL) << "Unexpected branch condition " << cond; 810 UNREACHABLE(); 811 } 812} 813 814void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 815 EmitFR(0x11, 0x10, ft, fs, fd, 0x0); 816} 817 818void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 819 EmitFR(0x11, 0x10, ft, fs, fd, 0x1); 820} 821 822void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 823 EmitFR(0x11, 0x10, ft, fs, fd, 0x2); 824} 825 826void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 827 EmitFR(0x11, 0x10, ft, fs, fd, 0x3); 828} 829 830void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) { 831 EmitFR(0x11, 0x11, ft, fs, fd, 0x0); 832} 833 834void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) { 835 EmitFR(0x11, 0x11, ft, fs, fd, 0x1); 836} 837 838void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) { 839 EmitFR(0x11, 0x11, ft, fs, fd, 0x2); 840} 841 842void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) { 843 EmitFR(0x11, 0x11, ft, fs, fd, 0x3); 844} 845 846void MipsAssembler::MovS(FRegister fd, FRegister fs) { 847 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6); 848} 849 850void MipsAssembler::MovD(FRegister fd, FRegister fs) { 851 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6); 852} 853 854void MipsAssembler::NegS(FRegister fd, FRegister fs) { 855 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7); 856} 857 858void MipsAssembler::NegD(FRegister fd, FRegister fs) { 859 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7); 860} 861 862void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { 863 CHECK(!IsR6()); 864 CHECK(IsUint<3>(cc)) << cc; 865 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31); 866} 867 868void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { 869 CHECK(!IsR6()); 870 CHECK(IsUint<3>(cc)) << cc; 871 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32); 872} 873 874void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { 875 CHECK(!IsR6()); 876 CHECK(IsUint<3>(cc)) << cc; 877 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33); 878} 879 880void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { 881 CHECK(!IsR6()); 882 CHECK(IsUint<3>(cc)) << cc; 883 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34); 884} 885 886void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { 887 CHECK(!IsR6()); 888 CHECK(IsUint<3>(cc)) << cc; 889 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35); 890} 891 892void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { 893 CHECK(!IsR6()); 894 CHECK(IsUint<3>(cc)) << cc; 895 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36); 896} 897 898void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { 899 CHECK(!IsR6()); 900 CHECK(IsUint<3>(cc)) << cc; 901 EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37); 902} 903 904void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { 905 CHECK(!IsR6()); 906 CHECK(IsUint<3>(cc)) << cc; 907 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31); 908} 909 910void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { 911 CHECK(!IsR6()); 912 CHECK(IsUint<3>(cc)) << cc; 913 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32); 914} 915 916void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { 917 CHECK(!IsR6()); 918 CHECK(IsUint<3>(cc)) << cc; 919 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33); 920} 921 922void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { 923 CHECK(!IsR6()); 924 CHECK(IsUint<3>(cc)) << cc; 925 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34); 926} 927 928void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { 929 CHECK(!IsR6()); 930 CHECK(IsUint<3>(cc)) << cc; 931 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35); 932} 933 934void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { 935 CHECK(!IsR6()); 936 CHECK(IsUint<3>(cc)) << cc; 937 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36); 938} 939 940void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { 941 CHECK(!IsR6()); 942 CHECK(IsUint<3>(cc)) << cc; 943 EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37); 944} 945 946void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { 947 CHECK(IsR6()); 948 EmitFR(0x11, 0x14, ft, fs, fd, 0x01); 949} 950 951void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { 952 CHECK(IsR6()); 953 EmitFR(0x11, 0x14, ft, fs, fd, 0x02); 954} 955 956void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { 957 CHECK(IsR6()); 958 EmitFR(0x11, 0x14, ft, fs, fd, 0x03); 959} 960 961void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { 962 CHECK(IsR6()); 963 EmitFR(0x11, 0x14, ft, fs, fd, 0x04); 964} 965 966void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { 967 CHECK(IsR6()); 968 EmitFR(0x11, 0x14, ft, fs, fd, 0x05); 969} 970 971void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { 972 CHECK(IsR6()); 973 EmitFR(0x11, 0x14, ft, fs, fd, 0x06); 974} 975 976void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { 977 CHECK(IsR6()); 978 EmitFR(0x11, 0x14, ft, fs, fd, 0x07); 979} 980 981void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { 982 CHECK(IsR6()); 983 EmitFR(0x11, 0x14, ft, fs, fd, 0x11); 984} 985 986void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { 987 CHECK(IsR6()); 988 EmitFR(0x11, 0x14, ft, fs, fd, 0x12); 989} 990 991void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { 992 CHECK(IsR6()); 993 EmitFR(0x11, 0x14, ft, fs, fd, 0x13); 994} 995 996void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { 997 CHECK(IsR6()); 998 EmitFR(0x11, 0x15, ft, fs, fd, 0x01); 999} 1000 1001void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { 1002 CHECK(IsR6()); 1003 EmitFR(0x11, 0x15, ft, fs, fd, 0x02); 1004} 1005 1006void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { 1007 CHECK(IsR6()); 1008 EmitFR(0x11, 0x15, ft, fs, fd, 0x03); 1009} 1010 1011void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { 1012 CHECK(IsR6()); 1013 EmitFR(0x11, 0x15, ft, fs, fd, 0x04); 1014} 1015 1016void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { 1017 CHECK(IsR6()); 1018 EmitFR(0x11, 0x15, ft, fs, fd, 0x05); 1019} 1020 1021void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { 1022 CHECK(IsR6()); 1023 EmitFR(0x11, 0x15, ft, fs, fd, 0x06); 1024} 1025 1026void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { 1027 CHECK(IsR6()); 1028 EmitFR(0x11, 0x15, ft, fs, fd, 0x07); 1029} 1030 1031void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { 1032 CHECK(IsR6()); 1033 EmitFR(0x11, 0x15, ft, fs, fd, 0x11); 1034} 1035 1036void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { 1037 CHECK(IsR6()); 1038 EmitFR(0x11, 0x15, ft, fs, fd, 0x12); 1039} 1040 1041void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { 1042 CHECK(IsR6()); 1043 EmitFR(0x11, 0x15, ft, fs, fd, 0x13); 1044} 1045 1046void MipsAssembler::Movf(Register rd, Register rs, int cc) { 1047 CHECK(!IsR6()); 1048 CHECK(IsUint<3>(cc)) << cc; 1049 EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01); 1050} 1051 1052void MipsAssembler::Movt(Register rd, Register rs, int cc) { 1053 CHECK(!IsR6()); 1054 CHECK(IsUint<3>(cc)) << cc; 1055 EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01); 1056} 1057 1058void MipsAssembler::TruncLS(FRegister fd, FRegister fs) { 1059 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09); 1060} 1061 1062void MipsAssembler::TruncLD(FRegister fd, FRegister fs) { 1063 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09); 1064} 1065 1066void MipsAssembler::TruncWS(FRegister fd, FRegister fs) { 1067 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D); 1068} 1069 1070void MipsAssembler::TruncWD(FRegister fd, FRegister fs) { 1071 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D); 1072} 1073 1074void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { 1075 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20); 1076} 1077 1078void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) { 1079 EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21); 1080} 1081 1082void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) { 1083 EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20); 1084} 1085 1086void MipsAssembler::Cvtds(FRegister fd, FRegister fs) { 1087 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21); 1088} 1089 1090void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) { 1091 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20); 1092} 1093 1094void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) { 1095 EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21); 1096} 1097 1098void MipsAssembler::Mfc1(Register rt, FRegister fs) { 1099 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1100} 1101 1102void MipsAssembler::Mtc1(Register rt, FRegister fs) { 1103 EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1104} 1105 1106void MipsAssembler::Mfhc1(Register rt, FRegister fs) { 1107 EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1108} 1109 1110void MipsAssembler::Mthc1(Register rt, FRegister fs) { 1111 EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 1112} 1113 1114void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) { 1115 if (Is32BitFPU()) { 1116 CHECK_EQ(fs % 2, 0) << fs; 1117 Mfc1(rt, static_cast<FRegister>(fs + 1)); 1118 } else { 1119 Mfhc1(rt, fs); 1120 } 1121} 1122 1123void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) { 1124 if (Is32BitFPU()) { 1125 CHECK_EQ(fs % 2, 0) << fs; 1126 Mtc1(rt, static_cast<FRegister>(fs + 1)); 1127 } else { 1128 Mthc1(rt, fs); 1129 } 1130} 1131 1132void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 1133 EmitI(0x31, rs, static_cast<Register>(ft), imm16); 1134} 1135 1136void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) { 1137 EmitI(0x35, rs, static_cast<Register>(ft), imm16); 1138} 1139 1140void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 1141 EmitI(0x39, rs, static_cast<Register>(ft), imm16); 1142} 1143 1144void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) { 1145 EmitI(0x3d, rs, static_cast<Register>(ft), imm16); 1146} 1147 1148void MipsAssembler::Break() { 1149 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), 1150 static_cast<Register>(0), 0, 0xD); 1151} 1152 1153void MipsAssembler::Nop() { 1154 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0); 1155} 1156 1157void MipsAssembler::Move(Register rd, Register rs) { 1158 Or(rd, rs, ZERO); 1159} 1160 1161void MipsAssembler::Clear(Register rd) { 1162 Move(rd, ZERO); 1163} 1164 1165void MipsAssembler::Not(Register rd, Register rs) { 1166 Nor(rd, rs, ZERO); 1167} 1168 1169void MipsAssembler::Push(Register rs) { 1170 IncreaseFrameSize(kMipsWordSize); 1171 Sw(rs, SP, 0); 1172} 1173 1174void MipsAssembler::Pop(Register rd) { 1175 Lw(rd, SP, 0); 1176 DecreaseFrameSize(kMipsWordSize); 1177} 1178 1179void MipsAssembler::PopAndReturn(Register rd, Register rt) { 1180 Lw(rd, SP, 0); 1181 Jr(rt); 1182 DecreaseFrameSize(kMipsWordSize); 1183} 1184 1185void MipsAssembler::LoadConst32(Register rd, int32_t value) { 1186 if (IsUint<16>(value)) { 1187 // Use OR with (unsigned) immediate to encode 16b unsigned int. 1188 Ori(rd, ZERO, value); 1189 } else if (IsInt<16>(value)) { 1190 // Use ADD with (signed) immediate to encode 16b signed int. 1191 Addiu(rd, ZERO, value); 1192 } else { 1193 Lui(rd, High16Bits(value)); 1194 if (value & 0xFFFF) 1195 Ori(rd, rd, Low16Bits(value)); 1196 } 1197} 1198 1199void MipsAssembler::LoadConst64(Register reg_hi, Register reg_lo, int64_t value) { 1200 uint32_t low = Low32Bits(value); 1201 uint32_t high = High32Bits(value); 1202 LoadConst32(reg_lo, low); 1203 if (high != low) { 1204 LoadConst32(reg_hi, high); 1205 } else { 1206 Move(reg_hi, reg_lo); 1207 } 1208} 1209 1210void MipsAssembler::StoreConst32ToOffset(int32_t value, 1211 Register base, 1212 int32_t offset, 1213 Register temp) { 1214 if (!IsInt<16>(offset)) { 1215 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value. 1216 LoadConst32(AT, offset); 1217 Addu(AT, AT, base); 1218 base = AT; 1219 offset = 0; 1220 } 1221 if (value == 0) { 1222 temp = ZERO; 1223 } else { 1224 LoadConst32(temp, value); 1225 } 1226 Sw(temp, base, offset); 1227} 1228 1229void MipsAssembler::StoreConst64ToOffset(int64_t value, 1230 Register base, 1231 int32_t offset, 1232 Register temp) { 1233 // IsInt<16> must be passed a signed value. 1234 if (!IsInt<16>(offset) || !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize))) { 1235 CHECK_NE(temp, AT); // Must not use AT as temp, as not to overwrite the loaded value. 1236 LoadConst32(AT, offset); 1237 Addu(AT, AT, base); 1238 base = AT; 1239 offset = 0; 1240 } 1241 uint32_t low = Low32Bits(value); 1242 uint32_t high = High32Bits(value); 1243 if (low == 0) { 1244 Sw(ZERO, base, offset); 1245 } else { 1246 LoadConst32(temp, low); 1247 Sw(temp, base, offset); 1248 } 1249 if (high == 0) { 1250 Sw(ZERO, base, offset + kMipsWordSize); 1251 } else { 1252 if (high != low) { 1253 LoadConst32(temp, high); 1254 } 1255 Sw(temp, base, offset + kMipsWordSize); 1256 } 1257} 1258 1259void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) { 1260 if (value == 0) { 1261 temp = ZERO; 1262 } else { 1263 LoadConst32(temp, value); 1264 } 1265 Mtc1(temp, r); 1266} 1267 1268void MipsAssembler::LoadDConst64(FRegister rd, int64_t value, Register temp) { 1269 uint32_t low = Low32Bits(value); 1270 uint32_t high = High32Bits(value); 1271 if (low == 0) { 1272 Mtc1(ZERO, rd); 1273 } else { 1274 LoadConst32(temp, low); 1275 Mtc1(temp, rd); 1276 } 1277 if (high == 0) { 1278 MoveToFpuHigh(ZERO, rd); 1279 } else { 1280 LoadConst32(temp, high); 1281 MoveToFpuHigh(temp, rd); 1282 } 1283} 1284 1285void MipsAssembler::Addiu32(Register rt, Register rs, int32_t value, Register temp) { 1286 if (IsInt<16>(value)) { 1287 Addiu(rt, rs, value); 1288 } else { 1289 LoadConst32(temp, value); 1290 Addu(rt, rs, temp); 1291 } 1292} 1293 1294void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits offset_size, 1295 MipsAssembler::Branch::Type short_type, 1296 MipsAssembler::Branch::Type long_type) { 1297 type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type; 1298} 1299 1300void MipsAssembler::Branch::InitializeType(bool is_call, bool is_r6) { 1301 OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_); 1302 if (is_r6) { 1303 // R6 1304 if (is_call) { 1305 InitShortOrLong(offset_size, kR6Call, kR6LongCall); 1306 } else if (condition_ == kUncond) { 1307 InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch); 1308 } else { 1309 if (condition_ == kCondEQZ || condition_ == kCondNEZ) { 1310 // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions. 1311 type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch; 1312 } else { 1313 InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch); 1314 } 1315 } 1316 } else { 1317 // R2 1318 if (is_call) { 1319 InitShortOrLong(offset_size, kCall, kLongCall); 1320 } else if (condition_ == kUncond) { 1321 InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch); 1322 } else { 1323 InitShortOrLong(offset_size, kCondBranch, kLongCondBranch); 1324 } 1325 } 1326 old_type_ = type_; 1327} 1328 1329bool MipsAssembler::Branch::IsNop(BranchCondition condition, Register lhs, Register rhs) { 1330 switch (condition) { 1331 case kCondLT: 1332 case kCondGT: 1333 case kCondNE: 1334 case kCondLTU: 1335 return lhs == rhs; 1336 default: 1337 return false; 1338 } 1339} 1340 1341bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Register rhs) { 1342 switch (condition) { 1343 case kUncond: 1344 return true; 1345 case kCondGE: 1346 case kCondLE: 1347 case kCondEQ: 1348 case kCondGEU: 1349 return lhs == rhs; 1350 default: 1351 return false; 1352 } 1353} 1354 1355MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target) 1356 : old_location_(location), 1357 location_(location), 1358 target_(target), 1359 lhs_reg_(0), 1360 rhs_reg_(0), 1361 condition_(kUncond) { 1362 InitializeType(false, is_r6); 1363} 1364 1365MipsAssembler::Branch::Branch(bool is_r6, 1366 uint32_t location, 1367 uint32_t target, 1368 MipsAssembler::BranchCondition condition, 1369 Register lhs_reg, 1370 Register rhs_reg) 1371 : old_location_(location), 1372 location_(location), 1373 target_(target), 1374 lhs_reg_(lhs_reg), 1375 rhs_reg_(rhs_reg), 1376 condition_(condition) { 1377 CHECK_NE(condition, kUncond); 1378 switch (condition) { 1379 case kCondLT: 1380 case kCondGE: 1381 case kCondLE: 1382 case kCondGT: 1383 case kCondLTU: 1384 case kCondGEU: 1385 // We don't support synthetic R2 branches (preceded with slt[u]) at this level 1386 // (R2 doesn't have branches to compare 2 registers using <, <=, >=, >). 1387 // We leave this up to the caller. 1388 CHECK(is_r6); 1389 FALLTHROUGH_INTENDED; 1390 case kCondEQ: 1391 case kCondNE: 1392 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1393 // To compare with 0, use dedicated kCond*Z conditions. 1394 CHECK_NE(lhs_reg, ZERO); 1395 CHECK_NE(rhs_reg, ZERO); 1396 break; 1397 case kCondLTZ: 1398 case kCondGEZ: 1399 case kCondLEZ: 1400 case kCondGTZ: 1401 case kCondEQZ: 1402 case kCondNEZ: 1403 // Require registers other than 0 not only for R6, but also for R2 to catch errors. 1404 CHECK_NE(lhs_reg, ZERO); 1405 CHECK_EQ(rhs_reg, ZERO); 1406 break; 1407 case kCondF: 1408 case kCondT: 1409 CHECK_EQ(rhs_reg, ZERO); 1410 break; 1411 case kUncond: 1412 UNREACHABLE(); 1413 } 1414 CHECK(!IsNop(condition, lhs_reg, rhs_reg)); 1415 if (IsUncond(condition, lhs_reg, rhs_reg)) { 1416 // Branch condition is always true, make the branch unconditional. 1417 condition_ = kUncond; 1418 } 1419 InitializeType(false, is_r6); 1420} 1421 1422MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg) 1423 : old_location_(location), 1424 location_(location), 1425 target_(target), 1426 lhs_reg_(indirect_reg), 1427 rhs_reg_(0), 1428 condition_(kUncond) { 1429 CHECK_NE(indirect_reg, ZERO); 1430 CHECK_NE(indirect_reg, AT); 1431 InitializeType(true, is_r6); 1432} 1433 1434MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( 1435 MipsAssembler::BranchCondition cond) { 1436 switch (cond) { 1437 case kCondLT: 1438 return kCondGE; 1439 case kCondGE: 1440 return kCondLT; 1441 case kCondLE: 1442 return kCondGT; 1443 case kCondGT: 1444 return kCondLE; 1445 case kCondLTZ: 1446 return kCondGEZ; 1447 case kCondGEZ: 1448 return kCondLTZ; 1449 case kCondLEZ: 1450 return kCondGTZ; 1451 case kCondGTZ: 1452 return kCondLEZ; 1453 case kCondEQ: 1454 return kCondNE; 1455 case kCondNE: 1456 return kCondEQ; 1457 case kCondEQZ: 1458 return kCondNEZ; 1459 case kCondNEZ: 1460 return kCondEQZ; 1461 case kCondLTU: 1462 return kCondGEU; 1463 case kCondGEU: 1464 return kCondLTU; 1465 case kCondF: 1466 return kCondT; 1467 case kCondT: 1468 return kCondF; 1469 case kUncond: 1470 LOG(FATAL) << "Unexpected branch condition " << cond; 1471 } 1472 UNREACHABLE(); 1473} 1474 1475MipsAssembler::Branch::Type MipsAssembler::Branch::GetType() const { 1476 return type_; 1477} 1478 1479MipsAssembler::BranchCondition MipsAssembler::Branch::GetCondition() const { 1480 return condition_; 1481} 1482 1483Register MipsAssembler::Branch::GetLeftRegister() const { 1484 return static_cast<Register>(lhs_reg_); 1485} 1486 1487Register MipsAssembler::Branch::GetRightRegister() const { 1488 return static_cast<Register>(rhs_reg_); 1489} 1490 1491uint32_t MipsAssembler::Branch::GetTarget() const { 1492 return target_; 1493} 1494 1495uint32_t MipsAssembler::Branch::GetLocation() const { 1496 return location_; 1497} 1498 1499uint32_t MipsAssembler::Branch::GetOldLocation() const { 1500 return old_location_; 1501} 1502 1503uint32_t MipsAssembler::Branch::GetLength() const { 1504 return branch_info_[type_].length; 1505} 1506 1507uint32_t MipsAssembler::Branch::GetOldLength() const { 1508 return branch_info_[old_type_].length; 1509} 1510 1511uint32_t MipsAssembler::Branch::GetSize() const { 1512 return GetLength() * sizeof(uint32_t); 1513} 1514 1515uint32_t MipsAssembler::Branch::GetOldSize() const { 1516 return GetOldLength() * sizeof(uint32_t); 1517} 1518 1519uint32_t MipsAssembler::Branch::GetEndLocation() const { 1520 return GetLocation() + GetSize(); 1521} 1522 1523uint32_t MipsAssembler::Branch::GetOldEndLocation() const { 1524 return GetOldLocation() + GetOldSize(); 1525} 1526 1527bool MipsAssembler::Branch::IsLong() const { 1528 switch (type_) { 1529 // R2 short branches. 1530 case kUncondBranch: 1531 case kCondBranch: 1532 case kCall: 1533 // R6 short branches. 1534 case kR6UncondBranch: 1535 case kR6CondBranch: 1536 case kR6Call: 1537 return false; 1538 // R2 long branches. 1539 case kLongUncondBranch: 1540 case kLongCondBranch: 1541 case kLongCall: 1542 // R6 long branches. 1543 case kR6LongUncondBranch: 1544 case kR6LongCondBranch: 1545 case kR6LongCall: 1546 return true; 1547 } 1548 UNREACHABLE(); 1549} 1550 1551bool MipsAssembler::Branch::IsResolved() const { 1552 return target_ != kUnresolved; 1553} 1554 1555MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const { 1556 OffsetBits offset_size = 1557 (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ)) 1558 ? kOffset23 1559 : branch_info_[type_].offset_size; 1560 return offset_size; 1561} 1562 1563MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSizeNeeded(uint32_t location, 1564 uint32_t target) { 1565 // For unresolved targets assume the shortest encoding 1566 // (later it will be made longer if needed). 1567 if (target == kUnresolved) 1568 return kOffset16; 1569 int64_t distance = static_cast<int64_t>(target) - location; 1570 // To simplify calculations in composite branches consisting of multiple instructions 1571 // bump up the distance by a value larger than the max byte size of a composite branch. 1572 distance += (distance >= 0) ? kMaxBranchSize : -kMaxBranchSize; 1573 if (IsInt<kOffset16>(distance)) 1574 return kOffset16; 1575 else if (IsInt<kOffset18>(distance)) 1576 return kOffset18; 1577 else if (IsInt<kOffset21>(distance)) 1578 return kOffset21; 1579 else if (IsInt<kOffset23>(distance)) 1580 return kOffset23; 1581 else if (IsInt<kOffset28>(distance)) 1582 return kOffset28; 1583 return kOffset32; 1584} 1585 1586void MipsAssembler::Branch::Resolve(uint32_t target) { 1587 target_ = target; 1588} 1589 1590void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) { 1591 if (location_ > expand_location) { 1592 location_ += delta; 1593 } 1594 if (!IsResolved()) { 1595 return; // Don't know the target yet. 1596 } 1597 if (target_ > expand_location) { 1598 target_ += delta; 1599 } 1600} 1601 1602void MipsAssembler::Branch::PromoteToLong() { 1603 switch (type_) { 1604 // R2 short branches. 1605 case kUncondBranch: 1606 type_ = kLongUncondBranch; 1607 break; 1608 case kCondBranch: 1609 type_ = kLongCondBranch; 1610 break; 1611 case kCall: 1612 type_ = kLongCall; 1613 break; 1614 // R6 short branches. 1615 case kR6UncondBranch: 1616 type_ = kR6LongUncondBranch; 1617 break; 1618 case kR6CondBranch: 1619 type_ = kR6LongCondBranch; 1620 break; 1621 case kR6Call: 1622 type_ = kR6LongCall; 1623 break; 1624 default: 1625 // Note: 'type_' is already long. 1626 break; 1627 } 1628 CHECK(IsLong()); 1629} 1630 1631uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) { 1632 // If the branch is still unresolved or already long, nothing to do. 1633 if (IsLong() || !IsResolved()) { 1634 return 0; 1635 } 1636 // Promote the short branch to long if the offset size is too small 1637 // to hold the distance between location_ and target_. 1638 if (GetOffsetSizeNeeded(location_, target_) > GetOffsetSize()) { 1639 PromoteToLong(); 1640 uint32_t old_size = GetOldSize(); 1641 uint32_t new_size = GetSize(); 1642 CHECK_GT(new_size, old_size); 1643 return new_size - old_size; 1644 } 1645 // The following logic is for debugging/testing purposes. 1646 // Promote some short branches to long when it's not really required. 1647 if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) { 1648 int64_t distance = static_cast<int64_t>(target_) - location_; 1649 distance = (distance >= 0) ? distance : -distance; 1650 if (distance >= max_short_distance) { 1651 PromoteToLong(); 1652 uint32_t old_size = GetOldSize(); 1653 uint32_t new_size = GetSize(); 1654 CHECK_GT(new_size, old_size); 1655 return new_size - old_size; 1656 } 1657 } 1658 return 0; 1659} 1660 1661uint32_t MipsAssembler::Branch::GetOffsetLocation() const { 1662 return location_ + branch_info_[type_].instr_offset * sizeof(uint32_t); 1663} 1664 1665uint32_t MipsAssembler::Branch::GetOffset() const { 1666 CHECK(IsResolved()); 1667 uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize()); 1668 // Calculate the byte distance between instructions and also account for 1669 // different PC-relative origins. 1670 uint32_t offset = target_ - GetOffsetLocation() - branch_info_[type_].pc_org * sizeof(uint32_t); 1671 // Prepare the offset for encoding into the instruction(s). 1672 offset = (offset & ofs_mask) >> branch_info_[type_].offset_shift; 1673 return offset; 1674} 1675 1676MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) { 1677 CHECK_LT(branch_id, branches_.size()); 1678 return &branches_[branch_id]; 1679} 1680 1681const MipsAssembler::Branch* MipsAssembler::GetBranch(uint32_t branch_id) const { 1682 CHECK_LT(branch_id, branches_.size()); 1683 return &branches_[branch_id]; 1684} 1685 1686void MipsAssembler::Bind(MipsLabel* label) { 1687 CHECK(!label->IsBound()); 1688 uint32_t bound_pc = buffer_.Size(); 1689 1690 // Walk the list of branches referring to and preceding this label. 1691 // Store the previously unknown target addresses in them. 1692 while (label->IsLinked()) { 1693 uint32_t branch_id = label->Position(); 1694 Branch* branch = GetBranch(branch_id); 1695 branch->Resolve(bound_pc); 1696 1697 uint32_t branch_location = branch->GetLocation(); 1698 // Extract the location of the previous branch in the list (walking the list backwards; 1699 // the previous branch ID was stored in the space reserved for this branch). 1700 uint32_t prev = buffer_.Load<uint32_t>(branch_location); 1701 1702 // On to the previous branch in the list... 1703 label->position_ = prev; 1704 } 1705 1706 // Now make the label object contain its own location (relative to the end of the preceding 1707 // branch, if any; it will be used by the branches referring to and following this label). 1708 label->prev_branch_id_plus_one_ = branches_.size(); 1709 if (label->prev_branch_id_plus_one_) { 1710 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1711 const Branch* branch = GetBranch(branch_id); 1712 bound_pc -= branch->GetEndLocation(); 1713 } 1714 label->BindTo(bound_pc); 1715} 1716 1717uint32_t MipsAssembler::GetLabelLocation(MipsLabel* label) const { 1718 CHECK(label->IsBound()); 1719 uint32_t target = label->Position(); 1720 if (label->prev_branch_id_plus_one_) { 1721 // Get label location based on the branch preceding it. 1722 uint32_t branch_id = label->prev_branch_id_plus_one_ - 1; 1723 const Branch* branch = GetBranch(branch_id); 1724 target += branch->GetEndLocation(); 1725 } 1726 return target; 1727} 1728 1729uint32_t MipsAssembler::GetAdjustedPosition(uint32_t old_position) { 1730 // We can reconstruct the adjustment by going through all the branches from the beginning 1731 // up to the old_position. Since we expect AdjustedPosition() to be called in a loop 1732 // with increasing old_position, we can use the data from last AdjustedPosition() to 1733 // continue where we left off and the whole loop should be O(m+n) where m is the number 1734 // of positions to adjust and n is the number of branches. 1735 if (old_position < last_old_position_) { 1736 last_position_adjustment_ = 0; 1737 last_old_position_ = 0; 1738 last_branch_id_ = 0; 1739 } 1740 while (last_branch_id_ != branches_.size()) { 1741 const Branch* branch = GetBranch(last_branch_id_); 1742 if (branch->GetLocation() >= old_position + last_position_adjustment_) { 1743 break; 1744 } 1745 last_position_adjustment_ += branch->GetSize() - branch->GetOldSize(); 1746 ++last_branch_id_; 1747 } 1748 last_old_position_ = old_position; 1749 return old_position + last_position_adjustment_; 1750} 1751 1752void MipsAssembler::FinalizeLabeledBranch(MipsLabel* label) { 1753 uint32_t length = branches_.back().GetLength(); 1754 if (!label->IsBound()) { 1755 // Branch forward (to a following label), distance is unknown. 1756 // The first branch forward will contain 0, serving as the terminator of 1757 // the list of forward-reaching branches. 1758 Emit(label->position_); 1759 length--; 1760 // Now make the label object point to this branch 1761 // (this forms a linked list of branches preceding this label). 1762 uint32_t branch_id = branches_.size() - 1; 1763 label->LinkTo(branch_id); 1764 } 1765 // Reserve space for the branch. 1766 while (length--) { 1767 Nop(); 1768 } 1769} 1770 1771void MipsAssembler::Buncond(MipsLabel* label) { 1772 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1773 branches_.emplace_back(IsR6(), buffer_.Size(), target); 1774 FinalizeLabeledBranch(label); 1775} 1776 1777void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) { 1778 // If lhs = rhs, this can be a NOP. 1779 if (Branch::IsNop(condition, lhs, rhs)) { 1780 return; 1781 } 1782 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1783 branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs); 1784 FinalizeLabeledBranch(label); 1785} 1786 1787void MipsAssembler::Call(MipsLabel* label, Register indirect_reg) { 1788 uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved; 1789 branches_.emplace_back(IsR6(), buffer_.Size(), target, indirect_reg); 1790 FinalizeLabeledBranch(label); 1791} 1792 1793void MipsAssembler::PromoteBranches() { 1794 // Promote short branches to long as necessary. 1795 bool changed; 1796 do { 1797 changed = false; 1798 for (auto& branch : branches_) { 1799 CHECK(branch.IsResolved()); 1800 uint32_t delta = branch.PromoteIfNeeded(); 1801 // If this branch has been promoted and needs to expand in size, 1802 // relocate all branches by the expansion size. 1803 if (delta) { 1804 changed = true; 1805 uint32_t expand_location = branch.GetLocation(); 1806 for (auto& branch2 : branches_) { 1807 branch2.Relocate(expand_location, delta); 1808 } 1809 } 1810 } 1811 } while (changed); 1812 1813 // Account for branch expansion by resizing the code buffer 1814 // and moving the code in it to its final location. 1815 size_t branch_count = branches_.size(); 1816 if (branch_count > 0) { 1817 // Resize. 1818 Branch& last_branch = branches_[branch_count - 1]; 1819 uint32_t size_delta = last_branch.GetEndLocation() - last_branch.GetOldEndLocation(); 1820 uint32_t old_size = buffer_.Size(); 1821 buffer_.Resize(old_size + size_delta); 1822 // Move the code residing between branch placeholders. 1823 uint32_t end = old_size; 1824 for (size_t i = branch_count; i > 0; ) { 1825 Branch& branch = branches_[--i]; 1826 uint32_t size = end - branch.GetOldEndLocation(); 1827 buffer_.Move(branch.GetEndLocation(), branch.GetOldEndLocation(), size); 1828 end = branch.GetOldLocation(); 1829 } 1830 } 1831} 1832 1833// Note: make sure branch_info_[] and EmitBranch() are kept synchronized. 1834const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = { 1835 // R2 short branches. 1836 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch 1837 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch 1838 { 5, 2, 0, MipsAssembler::Branch::kOffset16, 0 }, // kCall 1839 // R2 long branches. 1840 { 9, 3, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongUncondBranch 1841 { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCondBranch 1842 { 6, 1, 1, MipsAssembler::Branch::kOffset32, 0 }, // kLongCall 1843 // R6 short branches. 1844 { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch 1845 { 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch 1846 // Exception: kOffset23 for beqzc/bnezc. 1847 { 2, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Call 1848 // R6 long branches. 1849 { 2, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongUncondBranch 1850 { 3, 1, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCondBranch 1851 { 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kR6LongCall 1852}; 1853 1854// Note: make sure branch_info_[] and mitBranch() are kept synchronized. 1855void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { 1856 CHECK_EQ(overwriting_, true); 1857 overwrite_location_ = branch->GetLocation(); 1858 uint32_t offset = branch->GetOffset(); 1859 BranchCondition condition = branch->GetCondition(); 1860 Register lhs = branch->GetLeftRegister(); 1861 Register rhs = branch->GetRightRegister(); 1862 switch (branch->GetType()) { 1863 // R2 short branches. 1864 case Branch::kUncondBranch: 1865 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1866 B(offset); 1867 Nop(); // TODO: improve by filling the delay slot. 1868 break; 1869 case Branch::kCondBranch: 1870 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1871 EmitBcondR2(condition, lhs, rhs, offset); 1872 Nop(); // TODO: improve by filling the delay slot. 1873 break; 1874 case Branch::kCall: 1875 Nal(); 1876 Nop(); // TODO: is this NOP really needed here? 1877 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1878 Addiu(lhs, RA, offset); 1879 Jalr(lhs); 1880 Nop(); 1881 break; 1882 1883 // R2 long branches. 1884 case Branch::kLongUncondBranch: 1885 // To get the value of the PC register we need to use the NAL instruction. 1886 // NAL clobbers the RA register. However, RA must be preserved if the 1887 // method is compiled without the entry/exit sequences that would take care 1888 // of preserving RA (typically, leaf methods don't preserve RA explicitly). 1889 // So, we need to preserve RA in some temporary storage ourselves. The AT 1890 // register can't be used for this because we need it to load a constant 1891 // which will be added to the value that NAL stores in RA. And we can't 1892 // use T9 for this in the context of the JNI compiler, which uses it 1893 // as a scratch register (see InterproceduralScratchRegister()). 1894 // If we were to add a 32-bit constant to RA using two ADDIU instructions, 1895 // we'd also need to use the ROTR instruction, which requires no less than 1896 // MIPSR2. 1897 // Perhaps, we could use T8 or one of R2's multiplier/divider registers 1898 // (LO or HI) or even a floating-point register, but that doesn't seem 1899 // like a nice solution. We may want this to work on both R6 and pre-R6. 1900 // For now simply use the stack for RA. This should be OK since for the 1901 // vast majority of code a short PC-relative branch is sufficient. 1902 // TODO: can this be improved? 1903 Push(RA); 1904 Nal(); 1905 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1906 Lui(AT, High16Bits(offset)); 1907 Ori(AT, AT, Low16Bits(offset)); 1908 Addu(AT, AT, RA); 1909 Lw(RA, SP, 0); 1910 Jr(AT); 1911 DecreaseFrameSize(kMipsWordSize); 1912 break; 1913 case Branch::kLongCondBranch: 1914 // The comment on case 'Branch::kLongUncondBranch' applies here as well. 1915 // Note: the opposite condition branch encodes 8 as the distance, which is equal to the 1916 // number of instructions skipped: 1917 // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). 1918 EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); 1919 Push(RA); 1920 Nal(); 1921 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1922 Lui(AT, High16Bits(offset)); 1923 Ori(AT, AT, Low16Bits(offset)); 1924 Addu(AT, AT, RA); 1925 Lw(RA, SP, 0); 1926 Jr(AT); 1927 DecreaseFrameSize(kMipsWordSize); 1928 break; 1929 case Branch::kLongCall: 1930 Nal(); 1931 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1932 Lui(AT, High16Bits(offset)); 1933 Ori(AT, AT, Low16Bits(offset)); 1934 Addu(lhs, AT, RA); 1935 Jalr(lhs); 1936 Nop(); 1937 break; 1938 1939 // R6 short branches. 1940 case Branch::kR6UncondBranch: 1941 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1942 Bc(offset); 1943 break; 1944 case Branch::kR6CondBranch: 1945 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1946 EmitBcondR6(condition, lhs, rhs, offset); 1947 Nop(); // TODO: improve by filling the forbidden/delay slot. 1948 break; 1949 case Branch::kR6Call: 1950 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1951 Addiupc(lhs, offset); 1952 Jialc(lhs, 0); 1953 break; 1954 1955 // R6 long branches. 1956 case Branch::kR6LongUncondBranch: 1957 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 1958 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1959 Auipc(AT, High16Bits(offset)); 1960 Jic(AT, Low16Bits(offset)); 1961 break; 1962 case Branch::kR6LongCondBranch: 1963 EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); 1964 offset += (offset & 0x8000) << 1; // Account for sign extension in jic. 1965 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1966 Auipc(AT, High16Bits(offset)); 1967 Jic(AT, Low16Bits(offset)); 1968 break; 1969 case Branch::kR6LongCall: 1970 offset += (offset & 0x8000) << 1; // Account for sign extension in addiu. 1971 CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); 1972 Auipc(lhs, High16Bits(offset)); 1973 Addiu(lhs, lhs, Low16Bits(offset)); 1974 Jialc(lhs, 0); 1975 break; 1976 } 1977 CHECK_EQ(overwrite_location_, branch->GetEndLocation()); 1978 CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize)); 1979} 1980 1981void MipsAssembler::B(MipsLabel* label) { 1982 Buncond(label); 1983} 1984 1985void MipsAssembler::Jalr(MipsLabel* label, Register indirect_reg) { 1986 Call(label, indirect_reg); 1987} 1988 1989void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) { 1990 Bcond(label, kCondEQ, rs, rt); 1991} 1992 1993void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) { 1994 Bcond(label, kCondNE, rs, rt); 1995} 1996 1997void MipsAssembler::Beqz(Register rt, MipsLabel* label) { 1998 Bcond(label, kCondEQZ, rt); 1999} 2000 2001void MipsAssembler::Bnez(Register rt, MipsLabel* label) { 2002 Bcond(label, kCondNEZ, rt); 2003} 2004 2005void MipsAssembler::Bltz(Register rt, MipsLabel* label) { 2006 Bcond(label, kCondLTZ, rt); 2007} 2008 2009void MipsAssembler::Bgez(Register rt, MipsLabel* label) { 2010 Bcond(label, kCondGEZ, rt); 2011} 2012 2013void MipsAssembler::Blez(Register rt, MipsLabel* label) { 2014 Bcond(label, kCondLEZ, rt); 2015} 2016 2017void MipsAssembler::Bgtz(Register rt, MipsLabel* label) { 2018 Bcond(label, kCondGTZ, rt); 2019} 2020 2021void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) { 2022 if (IsR6()) { 2023 Bcond(label, kCondLT, rs, rt); 2024 } else if (!Branch::IsNop(kCondLT, rs, rt)) { 2025 // Synthesize the instruction (not available on R2). 2026 Slt(AT, rs, rt); 2027 Bnez(AT, label); 2028 } 2029} 2030 2031void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) { 2032 if (IsR6()) { 2033 Bcond(label, kCondGE, rs, rt); 2034 } else if (Branch::IsUncond(kCondGE, rs, rt)) { 2035 B(label); 2036 } else { 2037 // Synthesize the instruction (not available on R2). 2038 Slt(AT, rs, rt); 2039 Beqz(AT, label); 2040 } 2041} 2042 2043void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) { 2044 if (IsR6()) { 2045 Bcond(label, kCondLTU, rs, rt); 2046 } else if (!Branch::IsNop(kCondLTU, rs, rt)) { 2047 // Synthesize the instruction (not available on R2). 2048 Sltu(AT, rs, rt); 2049 Bnez(AT, label); 2050 } 2051} 2052 2053void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) { 2054 if (IsR6()) { 2055 Bcond(label, kCondGEU, rs, rt); 2056 } else if (Branch::IsUncond(kCondGEU, rs, rt)) { 2057 B(label); 2058 } else { 2059 // Synthesize the instruction (not available on R2). 2060 Sltu(AT, rs, rt); 2061 Beqz(AT, label); 2062 } 2063} 2064 2065void MipsAssembler::Bc1f(int cc, MipsLabel* label) { 2066 CHECK(IsUint<3>(cc)) << cc; 2067 Bcond(label, kCondF, static_cast<Register>(cc), ZERO); 2068} 2069 2070void MipsAssembler::Bc1t(int cc, MipsLabel* label) { 2071 CHECK(IsUint<3>(cc)) << cc; 2072 Bcond(label, kCondT, static_cast<Register>(cc), ZERO); 2073} 2074 2075void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) { 2076 Bcond(label, kCondF, static_cast<Register>(ft), ZERO); 2077} 2078 2079void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) { 2080 Bcond(label, kCondT, static_cast<Register>(ft), ZERO); 2081} 2082 2083void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base, 2084 int32_t offset) { 2085 // IsInt<16> must be passed a signed value. 2086 if (!IsInt<16>(offset) || 2087 (type == kLoadDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2088 LoadConst32(AT, offset); 2089 Addu(AT, AT, base); 2090 base = AT; 2091 offset = 0; 2092 } 2093 2094 switch (type) { 2095 case kLoadSignedByte: 2096 Lb(reg, base, offset); 2097 break; 2098 case kLoadUnsignedByte: 2099 Lbu(reg, base, offset); 2100 break; 2101 case kLoadSignedHalfword: 2102 Lh(reg, base, offset); 2103 break; 2104 case kLoadUnsignedHalfword: 2105 Lhu(reg, base, offset); 2106 break; 2107 case kLoadWord: 2108 Lw(reg, base, offset); 2109 break; 2110 case kLoadDoubleword: 2111 if (reg == base) { 2112 // This will clobber the base when loading the lower register. Since we have to load the 2113 // higher register as well, this will fail. Solution: reverse the order. 2114 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2115 Lw(reg, base, offset); 2116 } else { 2117 Lw(reg, base, offset); 2118 Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2119 } 2120 break; 2121 default: 2122 LOG(FATAL) << "UNREACHABLE"; 2123 } 2124} 2125 2126void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { 2127 if (!IsInt<16>(offset)) { 2128 LoadConst32(AT, offset); 2129 Addu(AT, AT, base); 2130 base = AT; 2131 offset = 0; 2132 } 2133 2134 Lwc1(reg, base, offset); 2135} 2136 2137void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) { 2138 // IsInt<16> must be passed a signed value. 2139 if (!IsInt<16>(offset) || 2140 (!IsAligned<kMipsDoublewordSize>(offset) && 2141 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2142 LoadConst32(AT, offset); 2143 Addu(AT, AT, base); 2144 base = AT; 2145 offset = 0; 2146 } 2147 2148 if (offset & 0x7) { 2149 if (Is32BitFPU()) { 2150 Lwc1(reg, base, offset); 2151 Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); 2152 } else { 2153 // 64-bit FPU. 2154 Lwc1(reg, base, offset); 2155 Lw(T8, base, offset + kMipsWordSize); 2156 Mthc1(T8, reg); 2157 } 2158 } else { 2159 Ldc1(reg, base, offset); 2160 } 2161} 2162 2163void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, 2164 size_t size) { 2165 MipsManagedRegister dst = m_dst.AsMips(); 2166 if (dst.IsNoRegister()) { 2167 CHECK_EQ(0u, size) << dst; 2168 } else if (dst.IsCoreRegister()) { 2169 CHECK_EQ(kMipsWordSize, size) << dst; 2170 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); 2171 } else if (dst.IsRegisterPair()) { 2172 CHECK_EQ(kMipsDoublewordSize, size) << dst; 2173 LoadFromOffset(kLoadDoubleword, dst.AsRegisterPairLow(), src_register, src_offset); 2174 } else if (dst.IsFRegister()) { 2175 if (size == kMipsWordSize) { 2176 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); 2177 } else { 2178 CHECK_EQ(kMipsDoublewordSize, size) << dst; 2179 LoadDFromOffset(dst.AsFRegister(), src_register, src_offset); 2180 } 2181 } 2182} 2183 2184void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base, 2185 int32_t offset) { 2186 // IsInt<16> must be passed a signed value. 2187 if (!IsInt<16>(offset) || 2188 (type == kStoreDoubleword && !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2189 LoadConst32(AT, offset); 2190 Addu(AT, AT, base); 2191 base = AT; 2192 offset = 0; 2193 } 2194 2195 switch (type) { 2196 case kStoreByte: 2197 Sb(reg, base, offset); 2198 break; 2199 case kStoreHalfword: 2200 Sh(reg, base, offset); 2201 break; 2202 case kStoreWord: 2203 Sw(reg, base, offset); 2204 break; 2205 case kStoreDoubleword: 2206 CHECK_NE(reg, base); 2207 CHECK_NE(static_cast<Register>(reg + 1), base); 2208 Sw(reg, base, offset); 2209 Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize); 2210 break; 2211 default: 2212 LOG(FATAL) << "UNREACHABLE"; 2213 } 2214} 2215 2216void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { 2217 if (!IsInt<16>(offset)) { 2218 LoadConst32(AT, offset); 2219 Addu(AT, AT, base); 2220 base = AT; 2221 offset = 0; 2222 } 2223 2224 Swc1(reg, base, offset); 2225} 2226 2227void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) { 2228 // IsInt<16> must be passed a signed value. 2229 if (!IsInt<16>(offset) || 2230 (!IsAligned<kMipsDoublewordSize>(offset) && 2231 !IsInt<16>(static_cast<int32_t>(offset + kMipsWordSize)))) { 2232 LoadConst32(AT, offset); 2233 Addu(AT, AT, base); 2234 base = AT; 2235 offset = 0; 2236 } 2237 2238 if (offset & 0x7) { 2239 if (Is32BitFPU()) { 2240 Swc1(reg, base, offset); 2241 Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize); 2242 } else { 2243 // 64-bit FPU. 2244 Mfhc1(T8, reg); 2245 Swc1(reg, base, offset); 2246 Sw(T8, base, offset + kMipsWordSize); 2247 } 2248 } else { 2249 Sdc1(reg, base, offset); 2250 } 2251} 2252 2253static dwarf::Reg DWARFReg(Register reg) { 2254 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 2255} 2256 2257constexpr size_t kFramePointerSize = 4; 2258 2259void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, 2260 const std::vector<ManagedRegister>& callee_save_regs, 2261 const ManagedRegisterEntrySpills& entry_spills) { 2262 CHECK_ALIGNED(frame_size, kStackAlignment); 2263 DCHECK(!overwriting_); 2264 2265 // Increase frame to required size. 2266 IncreaseFrameSize(frame_size); 2267 2268 // Push callee saves and return address. 2269 int stack_offset = frame_size - kFramePointerSize; 2270 StoreToOffset(kStoreWord, RA, SP, stack_offset); 2271 cfi_.RelOffset(DWARFReg(RA), stack_offset); 2272 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 2273 stack_offset -= kFramePointerSize; 2274 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 2275 StoreToOffset(kStoreWord, reg, SP, stack_offset); 2276 cfi_.RelOffset(DWARFReg(reg), stack_offset); 2277 } 2278 2279 // Write out Method*. 2280 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); 2281 2282 // Write out entry spills. 2283 int32_t offset = frame_size + kFramePointerSize; 2284 for (size_t i = 0; i < entry_spills.size(); ++i) { 2285 MipsManagedRegister reg = entry_spills.at(i).AsMips(); 2286 if (reg.IsNoRegister()) { 2287 ManagedRegisterSpill spill = entry_spills.at(i); 2288 offset += spill.getSize(); 2289 } else if (reg.IsCoreRegister()) { 2290 StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); 2291 offset += kMipsWordSize; 2292 } else if (reg.IsFRegister()) { 2293 StoreSToOffset(reg.AsFRegister(), SP, offset); 2294 offset += kMipsWordSize; 2295 } else if (reg.IsDRegister()) { 2296 StoreDToOffset(reg.AsOverlappingDRegisterLow(), SP, offset); 2297 offset += kMipsDoublewordSize; 2298 } 2299 } 2300} 2301 2302void MipsAssembler::RemoveFrame(size_t frame_size, 2303 const std::vector<ManagedRegister>& callee_save_regs) { 2304 CHECK_ALIGNED(frame_size, kStackAlignment); 2305 DCHECK(!overwriting_); 2306 cfi_.RememberState(); 2307 2308 // Pop callee saves and return address. 2309 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 2310 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 2311 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 2312 LoadFromOffset(kLoadWord, reg, SP, stack_offset); 2313 cfi_.Restore(DWARFReg(reg)); 2314 stack_offset += kFramePointerSize; 2315 } 2316 LoadFromOffset(kLoadWord, RA, SP, stack_offset); 2317 cfi_.Restore(DWARFReg(RA)); 2318 2319 // Decrease frame to required size. 2320 DecreaseFrameSize(frame_size); 2321 2322 // Then jump to the return address. 2323 Jr(RA); 2324 Nop(); 2325 2326 // The CFI should be restored for any code that follows the exit block. 2327 cfi_.RestoreState(); 2328 cfi_.DefCFAOffset(frame_size); 2329} 2330 2331void MipsAssembler::IncreaseFrameSize(size_t adjust) { 2332 CHECK_ALIGNED(adjust, kFramePointerSize); 2333 Addiu32(SP, SP, -adjust); 2334 cfi_.AdjustCFAOffset(adjust); 2335 if (overwriting_) { 2336 cfi_.OverrideDelayedPC(overwrite_location_); 2337 } 2338} 2339 2340void MipsAssembler::DecreaseFrameSize(size_t adjust) { 2341 CHECK_ALIGNED(adjust, kFramePointerSize); 2342 Addiu32(SP, SP, adjust); 2343 cfi_.AdjustCFAOffset(-adjust); 2344 if (overwriting_) { 2345 cfi_.OverrideDelayedPC(overwrite_location_); 2346 } 2347} 2348 2349void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 2350 MipsManagedRegister src = msrc.AsMips(); 2351 if (src.IsNoRegister()) { 2352 CHECK_EQ(0u, size); 2353 } else if (src.IsCoreRegister()) { 2354 CHECK_EQ(kMipsWordSize, size); 2355 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2356 } else if (src.IsRegisterPair()) { 2357 CHECK_EQ(kMipsDoublewordSize, size); 2358 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); 2359 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), 2360 SP, dest.Int32Value() + kMipsWordSize); 2361 } else if (src.IsFRegister()) { 2362 if (size == kMipsWordSize) { 2363 StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); 2364 } else { 2365 CHECK_EQ(kMipsDoublewordSize, size); 2366 StoreDToOffset(src.AsFRegister(), SP, dest.Int32Value()); 2367 } 2368 } 2369} 2370 2371void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 2372 MipsManagedRegister src = msrc.AsMips(); 2373 CHECK(src.IsCoreRegister()); 2374 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2375} 2376 2377void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 2378 MipsManagedRegister src = msrc.AsMips(); 2379 CHECK(src.IsCoreRegister()); 2380 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2381} 2382 2383void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 2384 ManagedRegister mscratch) { 2385 MipsManagedRegister scratch = mscratch.AsMips(); 2386 CHECK(scratch.IsCoreRegister()) << scratch; 2387 LoadConst32(scratch.AsCoreRegister(), imm); 2388 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2389} 2390 2391void MipsAssembler::StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, uint32_t imm, 2392 ManagedRegister mscratch) { 2393 MipsManagedRegister scratch = mscratch.AsMips(); 2394 CHECK(scratch.IsCoreRegister()) << scratch; 2395 // Is this function even referenced anywhere else in the code? 2396 LoadConst32(scratch.AsCoreRegister(), imm); 2397 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value()); 2398} 2399 2400void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs, 2401 FrameOffset fr_offs, 2402 ManagedRegister mscratch) { 2403 MipsManagedRegister scratch = mscratch.AsMips(); 2404 CHECK(scratch.IsCoreRegister()) << scratch; 2405 Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); 2406 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2407 S1, thr_offs.Int32Value()); 2408} 2409 2410void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) { 2411 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 2412} 2413 2414void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 2415 FrameOffset in_off, ManagedRegister mscratch) { 2416 MipsManagedRegister src = msrc.AsMips(); 2417 MipsManagedRegister scratch = mscratch.AsMips(); 2418 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 2419 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); 2420 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 2421} 2422 2423void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 2424 return EmitLoad(mdest, SP, src.Int32Value(), size); 2425} 2426 2427void MipsAssembler::LoadFromThread32(ManagedRegister mdest, 2428 ThreadOffset<kMipsWordSize> src, size_t size) { 2429 return EmitLoad(mdest, S1, src.Int32Value(), size); 2430} 2431 2432void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 2433 MipsManagedRegister dest = mdest.AsMips(); 2434 CHECK(dest.IsCoreRegister()); 2435 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); 2436} 2437 2438void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 2439 bool unpoison_reference) { 2440 MipsManagedRegister dest = mdest.AsMips(); 2441 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 2442 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 2443 base.AsMips().AsCoreRegister(), offs.Int32Value()); 2444 if (kPoisonHeapReferences && unpoison_reference) { 2445 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister()); 2446 } 2447} 2448 2449void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) { 2450 MipsManagedRegister dest = mdest.AsMips(); 2451 CHECK(dest.IsCoreRegister() && base.AsMips().IsCoreRegister()); 2452 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 2453 base.AsMips().AsCoreRegister(), offs.Int32Value()); 2454} 2455 2456void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest, 2457 ThreadOffset<kMipsWordSize> offs) { 2458 MipsManagedRegister dest = mdest.AsMips(); 2459 CHECK(dest.IsCoreRegister()); 2460 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); 2461} 2462 2463void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2464 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 2465} 2466 2467void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 2468 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 2469} 2470 2471void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 2472 MipsManagedRegister dest = mdest.AsMips(); 2473 MipsManagedRegister src = msrc.AsMips(); 2474 if (!dest.Equals(src)) { 2475 if (dest.IsCoreRegister()) { 2476 CHECK(src.IsCoreRegister()) << src; 2477 Move(dest.AsCoreRegister(), src.AsCoreRegister()); 2478 } else if (dest.IsFRegister()) { 2479 CHECK(src.IsFRegister()) << src; 2480 if (size == kMipsWordSize) { 2481 MovS(dest.AsFRegister(), src.AsFRegister()); 2482 } else { 2483 CHECK_EQ(kMipsDoublewordSize, size); 2484 MovD(dest.AsFRegister(), src.AsFRegister()); 2485 } 2486 } else if (dest.IsDRegister()) { 2487 CHECK(src.IsDRegister()) << src; 2488 MovD(dest.AsOverlappingDRegisterLow(), src.AsOverlappingDRegisterLow()); 2489 } else { 2490 CHECK(dest.IsRegisterPair()) << dest; 2491 CHECK(src.IsRegisterPair()) << src; 2492 // Ensure that the first move doesn't clobber the input of the second. 2493 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { 2494 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 2495 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 2496 } else { 2497 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 2498 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 2499 } 2500 } 2501 } 2502} 2503 2504void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { 2505 MipsManagedRegister scratch = mscratch.AsMips(); 2506 CHECK(scratch.IsCoreRegister()) << scratch; 2507 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2508 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2509} 2510 2511void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs, 2512 ThreadOffset<kMipsWordSize> thr_offs, 2513 ManagedRegister mscratch) { 2514 MipsManagedRegister scratch = mscratch.AsMips(); 2515 CHECK(scratch.IsCoreRegister()) << scratch; 2516 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2517 S1, thr_offs.Int32Value()); 2518 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2519 SP, fr_offs.Int32Value()); 2520} 2521 2522void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs, 2523 FrameOffset fr_offs, 2524 ManagedRegister mscratch) { 2525 MipsManagedRegister scratch = mscratch.AsMips(); 2526 CHECK(scratch.IsCoreRegister()) << scratch; 2527 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2528 SP, fr_offs.Int32Value()); 2529 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 2530 S1, thr_offs.Int32Value()); 2531} 2532 2533void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) { 2534 MipsManagedRegister scratch = mscratch.AsMips(); 2535 CHECK(scratch.IsCoreRegister()) << scratch; 2536 CHECK(size == kMipsWordSize || size == kMipsDoublewordSize) << size; 2537 if (size == kMipsWordSize) { 2538 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2539 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2540 } else if (size == kMipsDoublewordSize) { 2541 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 2542 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 2543 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + kMipsWordSize); 2544 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + kMipsWordSize); 2545 } 2546} 2547 2548void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 2549 ManagedRegister mscratch, size_t size) { 2550 Register scratch = mscratch.AsMips().AsCoreRegister(); 2551 CHECK_EQ(size, kMipsWordSize); 2552 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); 2553 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); 2554} 2555 2556void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 2557 ManagedRegister mscratch, size_t size) { 2558 Register scratch = mscratch.AsMips().AsCoreRegister(); 2559 CHECK_EQ(size, kMipsWordSize); 2560 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 2561 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 2562} 2563 2564void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2565 FrameOffset src_base ATTRIBUTE_UNUSED, 2566 Offset src_offset ATTRIBUTE_UNUSED, 2567 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2568 size_t size ATTRIBUTE_UNUSED) { 2569 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2570} 2571 2572void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, 2573 ManagedRegister src, Offset src_offset, 2574 ManagedRegister mscratch, size_t size) { 2575 CHECK_EQ(size, kMipsWordSize); 2576 Register scratch = mscratch.AsMips().AsCoreRegister(); 2577 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); 2578 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 2579} 2580 2581void MipsAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED, 2582 Offset dest_offset ATTRIBUTE_UNUSED, 2583 FrameOffset src ATTRIBUTE_UNUSED, 2584 Offset src_offset ATTRIBUTE_UNUSED, 2585 ManagedRegister mscratch ATTRIBUTE_UNUSED, 2586 size_t size ATTRIBUTE_UNUSED) { 2587 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2588} 2589 2590void MipsAssembler::MemoryBarrier(ManagedRegister) { 2591 // TODO: sync? 2592 UNIMPLEMENTED(FATAL) << "no MIPS implementation"; 2593} 2594 2595void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 2596 FrameOffset handle_scope_offset, 2597 ManagedRegister min_reg, 2598 bool null_allowed) { 2599 MipsManagedRegister out_reg = mout_reg.AsMips(); 2600 MipsManagedRegister in_reg = min_reg.AsMips(); 2601 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; 2602 CHECK(out_reg.IsCoreRegister()) << out_reg; 2603 if (null_allowed) { 2604 MipsLabel null_arg; 2605 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2606 // the address in the handle scope holding the reference. 2607 // E.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset). 2608 if (in_reg.IsNoRegister()) { 2609 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 2610 SP, handle_scope_offset.Int32Value()); 2611 in_reg = out_reg; 2612 } 2613 if (!out_reg.Equals(in_reg)) { 2614 LoadConst32(out_reg.AsCoreRegister(), 0); 2615 } 2616 Beqz(in_reg.AsCoreRegister(), &null_arg); 2617 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2618 Bind(&null_arg); 2619 } else { 2620 Addiu32(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2621 } 2622} 2623 2624void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, 2625 FrameOffset handle_scope_offset, 2626 ManagedRegister mscratch, 2627 bool null_allowed) { 2628 MipsManagedRegister scratch = mscratch.AsMips(); 2629 CHECK(scratch.IsCoreRegister()) << scratch; 2630 if (null_allowed) { 2631 MipsLabel null_arg; 2632 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2633 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 2634 // the address in the handle scope holding the reference. 2635 // E.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset). 2636 Beqz(scratch.AsCoreRegister(), &null_arg); 2637 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2638 Bind(&null_arg); 2639 } else { 2640 Addiu32(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 2641 } 2642 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); 2643} 2644 2645// Given a handle scope entry, load the associated reference. 2646void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 2647 ManagedRegister min_reg) { 2648 MipsManagedRegister out_reg = mout_reg.AsMips(); 2649 MipsManagedRegister in_reg = min_reg.AsMips(); 2650 CHECK(out_reg.IsCoreRegister()) << out_reg; 2651 CHECK(in_reg.IsCoreRegister()) << in_reg; 2652 MipsLabel null_arg; 2653 if (!out_reg.Equals(in_reg)) { 2654 LoadConst32(out_reg.AsCoreRegister(), 0); 2655 } 2656 Beqz(in_reg.AsCoreRegister(), &null_arg); 2657 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 2658 in_reg.AsCoreRegister(), 0); 2659 Bind(&null_arg); 2660} 2661 2662void MipsAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED, 2663 bool could_be_null ATTRIBUTE_UNUSED) { 2664 // TODO: not validating references. 2665} 2666 2667void MipsAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED, 2668 bool could_be_null ATTRIBUTE_UNUSED) { 2669 // TODO: not validating references. 2670} 2671 2672void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 2673 MipsManagedRegister base = mbase.AsMips(); 2674 MipsManagedRegister scratch = mscratch.AsMips(); 2675 CHECK(base.IsCoreRegister()) << base; 2676 CHECK(scratch.IsCoreRegister()) << scratch; 2677 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2678 base.AsCoreRegister(), offset.Int32Value()); 2679 Jalr(scratch.AsCoreRegister()); 2680 Nop(); 2681 // TODO: place reference map on call. 2682} 2683 2684void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 2685 MipsManagedRegister scratch = mscratch.AsMips(); 2686 CHECK(scratch.IsCoreRegister()) << scratch; 2687 // Call *(*(SP + base) + offset) 2688 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, base.Int32Value()); 2689 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2690 scratch.AsCoreRegister(), offset.Int32Value()); 2691 Jalr(scratch.AsCoreRegister()); 2692 Nop(); 2693 // TODO: place reference map on call. 2694} 2695 2696void MipsAssembler::CallFromThread32(ThreadOffset<kMipsWordSize> offset ATTRIBUTE_UNUSED, 2697 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2698 UNIMPLEMENTED(FATAL) << "no mips implementation"; 2699} 2700 2701void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 2702 Move(tr.AsMips().AsCoreRegister(), S1); 2703} 2704 2705void MipsAssembler::GetCurrentThread(FrameOffset offset, 2706 ManagedRegister mscratch ATTRIBUTE_UNUSED) { 2707 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 2708} 2709 2710void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 2711 MipsManagedRegister scratch = mscratch.AsMips(); 2712 exception_blocks_.emplace_back(scratch, stack_adjust); 2713 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 2714 S1, Thread::ExceptionOffset<kMipsWordSize>().Int32Value()); 2715 // TODO: on MIPS32R6 prefer Bnezc(scratch.AsCoreRegister(), slow.Entry()); 2716 // as the NAL instruction (occurring in long R2 branches) may become deprecated. 2717 // For now use common for R2 and R6 instructions as this code must execute on both. 2718 Bnez(scratch.AsCoreRegister(), exception_blocks_.back().Entry()); 2719} 2720 2721void MipsAssembler::EmitExceptionPoll(MipsExceptionSlowPath* exception) { 2722 Bind(exception->Entry()); 2723 if (exception->stack_adjust_ != 0) { // Fix up the frame. 2724 DecreaseFrameSize(exception->stack_adjust_); 2725 } 2726 // Pass exception object as argument. 2727 // Don't care about preserving A0 as this call won't return. 2728 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); 2729 Move(A0, exception->scratch_.AsCoreRegister()); 2730 // Set up call to Thread::Current()->pDeliverException. 2731 LoadFromOffset(kLoadWord, T9, S1, 2732 QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, pDeliverException).Int32Value()); 2733 Jr(T9); 2734 Nop(); 2735 2736 // Call never returns. 2737 Break(); 2738} 2739 2740} // namespace mips 2741} // namespace art 2742