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 "memory_region.h" 23#include "thread.h" 24 25namespace art { 26namespace mips { 27 28std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { 29 if (rhs >= D0 && rhs < kNumberOfDRegisters) { 30 os << "d" << static_cast<int>(rhs); 31 } else { 32 os << "DRegister[" << static_cast<int>(rhs) << "]"; 33 } 34 return os; 35} 36 37void MipsAssembler::Emit(int32_t value) { 38 AssemblerBuffer::EnsureCapacity ensured(&buffer_); 39 buffer_.Emit<int32_t>(value); 40} 41 42void MipsAssembler::EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct) { 43 CHECK_NE(rs, kNoRegister); 44 CHECK_NE(rt, kNoRegister); 45 CHECK_NE(rd, kNoRegister); 46 int32_t encoding = opcode << kOpcodeShift | 47 static_cast<int32_t>(rs) << kRsShift | 48 static_cast<int32_t>(rt) << kRtShift | 49 static_cast<int32_t>(rd) << kRdShift | 50 shamt << kShamtShift | 51 funct; 52 Emit(encoding); 53} 54 55void MipsAssembler::EmitI(int opcode, Register rs, Register rt, uint16_t imm) { 56 CHECK_NE(rs, kNoRegister); 57 CHECK_NE(rt, kNoRegister); 58 int32_t encoding = opcode << kOpcodeShift | 59 static_cast<int32_t>(rs) << kRsShift | 60 static_cast<int32_t>(rt) << kRtShift | 61 imm; 62 Emit(encoding); 63} 64 65void MipsAssembler::EmitJ(int opcode, int address) { 66 int32_t encoding = opcode << kOpcodeShift | 67 address; 68 Emit(encoding); 69} 70 71void MipsAssembler::EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct) { 72 CHECK_NE(ft, kNoFRegister); 73 CHECK_NE(fs, kNoFRegister); 74 CHECK_NE(fd, kNoFRegister); 75 int32_t encoding = opcode << kOpcodeShift | 76 fmt << kFmtShift | 77 static_cast<int32_t>(ft) << kFtShift | 78 static_cast<int32_t>(fs) << kFsShift | 79 static_cast<int32_t>(fd) << kFdShift | 80 funct; 81 Emit(encoding); 82} 83 84void MipsAssembler::EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm) { 85 CHECK_NE(rt, kNoFRegister); 86 int32_t encoding = opcode << kOpcodeShift | 87 fmt << kFmtShift | 88 static_cast<int32_t>(rt) << kRtShift | 89 imm; 90 Emit(encoding); 91} 92 93void MipsAssembler::EmitBranch(Register rt, Register rs, Label* label, bool equal) { 94 int offset; 95 if (label->IsBound()) { 96 offset = label->Position() - buffer_.Size(); 97 } else { 98 // Use the offset field of the branch instruction for linking the sites. 99 offset = label->position_; 100 label->LinkTo(buffer_.Size()); 101 } 102 if (equal) { 103 Beq(rt, rs, (offset >> 2) & kBranchOffsetMask); 104 } else { 105 Bne(rt, rs, (offset >> 2) & kBranchOffsetMask); 106 } 107} 108 109void MipsAssembler::EmitJump(Label* label, bool link) { 110 int offset; 111 if (label->IsBound()) { 112 offset = label->Position() - buffer_.Size(); 113 } else { 114 // Use the offset field of the jump instruction for linking the sites. 115 offset = label->position_; 116 label->LinkTo(buffer_.Size()); 117 } 118 if (link) { 119 Jal((offset >> 2) & kJumpOffsetMask); 120 } else { 121 J((offset >> 2) & kJumpOffsetMask); 122 } 123} 124 125int32_t MipsAssembler::EncodeBranchOffset(int offset, int32_t inst, bool is_jump) { 126 CHECK_ALIGNED(offset, 4); 127 CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset; 128 129 // Properly preserve only the bits supported in the instruction. 130 offset >>= 2; 131 if (is_jump) { 132 offset &= kJumpOffsetMask; 133 return (inst & ~kJumpOffsetMask) | offset; 134 } else { 135 offset &= kBranchOffsetMask; 136 return (inst & ~kBranchOffsetMask) | offset; 137 } 138} 139 140int MipsAssembler::DecodeBranchOffset(int32_t inst, bool is_jump) { 141 // Sign-extend, then left-shift by 2. 142 if (is_jump) { 143 return (((inst & kJumpOffsetMask) << 6) >> 4); 144 } else { 145 return (((inst & kBranchOffsetMask) << 16) >> 14); 146 } 147} 148 149void MipsAssembler::Bind(Label* label, bool is_jump) { 150 CHECK(!label->IsBound()); 151 int bound_pc = buffer_.Size(); 152 while (label->IsLinked()) { 153 int32_t position = label->Position(); 154 int32_t next = buffer_.Load<int32_t>(position); 155 int32_t offset = is_jump ? bound_pc - position : bound_pc - position - 4; 156 int32_t encoded = MipsAssembler::EncodeBranchOffset(offset, next, is_jump); 157 buffer_.Store<int32_t>(position, encoded); 158 label->position_ = MipsAssembler::DecodeBranchOffset(next, is_jump); 159 } 160 label->BindTo(bound_pc); 161} 162 163void MipsAssembler::Add(Register rd, Register rs, Register rt) { 164 EmitR(0, rs, rt, rd, 0, 0x20); 165} 166 167void MipsAssembler::Addu(Register rd, Register rs, Register rt) { 168 EmitR(0, rs, rt, rd, 0, 0x21); 169} 170 171void MipsAssembler::Addi(Register rt, Register rs, uint16_t imm16) { 172 EmitI(0x8, rs, rt, imm16); 173} 174 175void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) { 176 EmitI(0x9, rs, rt, imm16); 177} 178 179void MipsAssembler::Sub(Register rd, Register rs, Register rt) { 180 EmitR(0, rs, rt, rd, 0, 0x22); 181} 182 183void MipsAssembler::Subu(Register rd, Register rs, Register rt) { 184 EmitR(0, rs, rt, rd, 0, 0x23); 185} 186 187void MipsAssembler::Mult(Register rs, Register rt) { 188 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18); 189} 190 191void MipsAssembler::Multu(Register rs, Register rt) { 192 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19); 193} 194 195void MipsAssembler::Div(Register rs, Register rt) { 196 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a); 197} 198 199void MipsAssembler::Divu(Register rs, Register rt) { 200 EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b); 201} 202 203void MipsAssembler::And(Register rd, Register rs, Register rt) { 204 EmitR(0, rs, rt, rd, 0, 0x24); 205} 206 207void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) { 208 EmitI(0xc, rs, rt, imm16); 209} 210 211void MipsAssembler::Or(Register rd, Register rs, Register rt) { 212 EmitR(0, rs, rt, rd, 0, 0x25); 213} 214 215void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) { 216 EmitI(0xd, rs, rt, imm16); 217} 218 219void MipsAssembler::Xor(Register rd, Register rs, Register rt) { 220 EmitR(0, rs, rt, rd, 0, 0x26); 221} 222 223void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) { 224 EmitI(0xe, rs, rt, imm16); 225} 226 227void MipsAssembler::Nor(Register rd, Register rs, Register rt) { 228 EmitR(0, rs, rt, rd, 0, 0x27); 229} 230 231void MipsAssembler::Sll(Register rd, Register rs, int shamt) { 232 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x00); 233} 234 235void MipsAssembler::Srl(Register rd, Register rs, int shamt) { 236 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x02); 237} 238 239void MipsAssembler::Sra(Register rd, Register rs, int shamt) { 240 EmitR(0, rs, static_cast<Register>(0), rd, shamt, 0x03); 241} 242 243void MipsAssembler::Sllv(Register rd, Register rs, Register rt) { 244 EmitR(0, rs, rt, rd, 0, 0x04); 245} 246 247void MipsAssembler::Srlv(Register rd, Register rs, Register rt) { 248 EmitR(0, rs, rt, rd, 0, 0x06); 249} 250 251void MipsAssembler::Srav(Register rd, Register rs, Register rt) { 252 EmitR(0, rs, rt, rd, 0, 0x07); 253} 254 255void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) { 256 EmitI(0x20, rs, rt, imm16); 257} 258 259void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) { 260 EmitI(0x21, rs, rt, imm16); 261} 262 263void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) { 264 EmitI(0x23, rs, rt, imm16); 265} 266 267void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) { 268 EmitI(0x24, rs, rt, imm16); 269} 270 271void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) { 272 EmitI(0x25, rs, rt, imm16); 273} 274 275void MipsAssembler::Lui(Register rt, uint16_t imm16) { 276 EmitI(0xf, static_cast<Register>(0), rt, imm16); 277} 278 279void MipsAssembler::Mfhi(Register rd) { 280 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x10); 281} 282 283void MipsAssembler::Mflo(Register rd) { 284 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rd, 0, 0x12); 285} 286 287void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) { 288 EmitI(0x28, rs, rt, imm16); 289} 290 291void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) { 292 EmitI(0x29, rs, rt, imm16); 293} 294 295void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) { 296 EmitI(0x2b, rs, rt, imm16); 297} 298 299void MipsAssembler::Slt(Register rd, Register rs, Register rt) { 300 EmitR(0, rs, rt, rd, 0, 0x2a); 301} 302 303void MipsAssembler::Sltu(Register rd, Register rs, Register rt) { 304 EmitR(0, rs, rt, rd, 0, 0x2b); 305} 306 307void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) { 308 EmitI(0xa, rs, rt, imm16); 309} 310 311void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) { 312 EmitI(0xb, rs, rt, imm16); 313} 314 315void MipsAssembler::Beq(Register rt, Register rs, uint16_t imm16) { 316 EmitI(0x4, rs, rt, imm16); 317 Nop(); 318} 319 320void MipsAssembler::Bne(Register rt, Register rs, uint16_t imm16) { 321 EmitI(0x5, rs, rt, imm16); 322 Nop(); 323} 324 325void MipsAssembler::J(uint32_t address) { 326 EmitJ(0x2, address); 327 Nop(); 328} 329 330void MipsAssembler::Jal(uint32_t address) { 331 EmitJ(0x2, address); 332 Nop(); 333} 334 335void MipsAssembler::Jr(Register rs) { 336 EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x09); // Jalr zero, rs 337 Nop(); 338} 339 340void MipsAssembler::Jalr(Register rs) { 341 EmitR(0, rs, static_cast<Register>(0), RA, 0, 0x09); 342 Nop(); 343} 344 345void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) { 346 EmitFR(0x11, 0x10, ft, fs, fd, 0x0); 347} 348 349void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) { 350 EmitFR(0x11, 0x10, ft, fs, fd, 0x1); 351} 352 353void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) { 354 EmitFR(0x11, 0x10, ft, fs, fd, 0x2); 355} 356 357void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { 358 EmitFR(0x11, 0x10, ft, fs, fd, 0x3); 359} 360 361void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) { 362 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), 363 static_cast<FRegister>(fd), 0x0); 364} 365 366void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) { 367 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), 368 static_cast<FRegister>(fd), 0x1); 369} 370 371void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) { 372 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), 373 static_cast<FRegister>(fd), 0x2); 374} 375 376void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) { 377 EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), 378 static_cast<FRegister>(fd), 0x3); 379} 380 381void MipsAssembler::MovS(FRegister fd, FRegister fs) { 382 EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6); 383} 384 385void MipsAssembler::MovD(DRegister fd, DRegister fs) { 386 EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs), 387 static_cast<FRegister>(fd), 0x6); 388} 389 390void MipsAssembler::Mfc1(Register rt, FRegister fs) { 391 EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); 392} 393 394void MipsAssembler::Mtc1(FRegister ft, Register rs) { 395 EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0); 396} 397 398void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { 399 EmitI(0x31, rs, static_cast<Register>(ft), imm16); 400} 401 402void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) { 403 EmitI(0x35, rs, static_cast<Register>(ft), imm16); 404} 405 406void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { 407 EmitI(0x39, rs, static_cast<Register>(ft), imm16); 408} 409 410void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) { 411 EmitI(0x3d, rs, static_cast<Register>(ft), imm16); 412} 413 414void MipsAssembler::Break() { 415 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), 416 static_cast<Register>(0), 0, 0xD); 417} 418 419void MipsAssembler::Nop() { 420 EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0); 421} 422 423void MipsAssembler::Move(Register rt, Register rs) { 424 EmitI(0x9, rs, rt, 0); // Addiu 425} 426 427void MipsAssembler::Clear(Register rt) { 428 EmitR(0, static_cast<Register>(0), static_cast<Register>(0), rt, 0, 0x20); 429} 430 431void MipsAssembler::Not(Register rt, Register rs) { 432 EmitR(0, static_cast<Register>(0), rs, rt, 0, 0x27); 433} 434 435void MipsAssembler::Mul(Register rd, Register rs, Register rt) { 436 Mult(rs, rt); 437 Mflo(rd); 438} 439 440void MipsAssembler::Div(Register rd, Register rs, Register rt) { 441 Div(rs, rt); 442 Mflo(rd); 443} 444 445void MipsAssembler::Rem(Register rd, Register rs, Register rt) { 446 Div(rs, rt); 447 Mfhi(rd); 448} 449 450void MipsAssembler::AddConstant(Register rt, Register rs, int32_t value) { 451 Addiu(rt, rs, value); 452} 453 454void MipsAssembler::LoadImmediate(Register rt, int32_t value) { 455 Addiu(rt, ZERO, value); 456} 457 458void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, 459 size_t size) { 460 MipsManagedRegister dst = m_dst.AsMips(); 461 if (dst.IsNoRegister()) { 462 CHECK_EQ(0u, size) << dst; 463 } else if (dst.IsCoreRegister()) { 464 CHECK_EQ(4u, size) << dst; 465 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset); 466 } else if (dst.IsRegisterPair()) { 467 CHECK_EQ(8u, size) << dst; 468 LoadFromOffset(kLoadWord, dst.AsRegisterPairLow(), src_register, src_offset); 469 LoadFromOffset(kLoadWord, dst.AsRegisterPairHigh(), src_register, src_offset + 4); 470 } else if (dst.IsFRegister()) { 471 LoadSFromOffset(dst.AsFRegister(), src_register, src_offset); 472 } else { 473 CHECK(dst.IsDRegister()) << dst; 474 LoadDFromOffset(dst.AsDRegister(), src_register, src_offset); 475 } 476} 477 478void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base, 479 int32_t offset) { 480 switch (type) { 481 case kLoadSignedByte: 482 Lb(reg, base, offset); 483 break; 484 case kLoadUnsignedByte: 485 Lbu(reg, base, offset); 486 break; 487 case kLoadSignedHalfword: 488 Lh(reg, base, offset); 489 break; 490 case kLoadUnsignedHalfword: 491 Lhu(reg, base, offset); 492 break; 493 case kLoadWord: 494 Lw(reg, base, offset); 495 break; 496 case kLoadWordPair: 497 LOG(FATAL) << "UNREACHABLE"; 498 break; 499 default: 500 LOG(FATAL) << "UNREACHABLE"; 501 } 502} 503 504void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) { 505 Lwc1(reg, base, offset); 506} 507 508void MipsAssembler::LoadDFromOffset(DRegister reg, Register base, int32_t offset) { 509 Ldc1(reg, base, offset); 510} 511 512void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base, 513 int32_t offset) { 514 switch (type) { 515 case kStoreByte: 516 Sb(reg, base, offset); 517 break; 518 case kStoreHalfword: 519 Sh(reg, base, offset); 520 break; 521 case kStoreWord: 522 Sw(reg, base, offset); 523 break; 524 case kStoreWordPair: 525 LOG(FATAL) << "UNREACHABLE"; 526 break; 527 default: 528 LOG(FATAL) << "UNREACHABLE"; 529 } 530} 531 532void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) { 533 Swc1(reg, base, offset); 534} 535 536void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) { 537 Sdc1(reg, base, offset); 538} 539 540static dwarf::Reg DWARFReg(Register reg) { 541 return dwarf::Reg::MipsCore(static_cast<int>(reg)); 542} 543 544constexpr size_t kFramePointerSize = 4; 545 546void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, 547 const std::vector<ManagedRegister>& callee_save_regs, 548 const ManagedRegisterEntrySpills& entry_spills) { 549 CHECK_ALIGNED(frame_size, kStackAlignment); 550 551 // Increase frame to required size. 552 IncreaseFrameSize(frame_size); 553 554 // Push callee saves and return address 555 int stack_offset = frame_size - kFramePointerSize; 556 StoreToOffset(kStoreWord, RA, SP, stack_offset); 557 cfi_.RelOffset(DWARFReg(RA), stack_offset); 558 for (int i = callee_save_regs.size() - 1; i >= 0; --i) { 559 stack_offset -= kFramePointerSize; 560 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 561 StoreToOffset(kStoreWord, reg, SP, stack_offset); 562 cfi_.RelOffset(DWARFReg(reg), stack_offset); 563 } 564 565 // Write out Method*. 566 StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); 567 568 // Write out entry spills. 569 for (size_t i = 0; i < entry_spills.size(); ++i) { 570 Register reg = entry_spills.at(i).AsMips().AsCoreRegister(); 571 StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize)); 572 } 573} 574 575void MipsAssembler::RemoveFrame(size_t frame_size, 576 const std::vector<ManagedRegister>& callee_save_regs) { 577 CHECK_ALIGNED(frame_size, kStackAlignment); 578 cfi_.RememberState(); 579 580 // Pop callee saves and return address 581 int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; 582 for (size_t i = 0; i < callee_save_regs.size(); ++i) { 583 Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); 584 LoadFromOffset(kLoadWord, reg, SP, stack_offset); 585 cfi_.Restore(DWARFReg(reg)); 586 stack_offset += kFramePointerSize; 587 } 588 LoadFromOffset(kLoadWord, RA, SP, stack_offset); 589 cfi_.Restore(DWARFReg(RA)); 590 591 // Decrease frame to required size. 592 DecreaseFrameSize(frame_size); 593 594 // Then jump to the return address. 595 Jr(RA); 596 597 // The CFI should be restored for any code that follows the exit block. 598 cfi_.RestoreState(); 599 cfi_.DefCFAOffset(frame_size); 600} 601 602void MipsAssembler::IncreaseFrameSize(size_t adjust) { 603 CHECK_ALIGNED(adjust, kStackAlignment); 604 AddConstant(SP, SP, -adjust); 605 cfi_.AdjustCFAOffset(adjust); 606} 607 608void MipsAssembler::DecreaseFrameSize(size_t adjust) { 609 CHECK_ALIGNED(adjust, kStackAlignment); 610 AddConstant(SP, SP, adjust); 611 cfi_.AdjustCFAOffset(-adjust); 612} 613 614void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { 615 MipsManagedRegister src = msrc.AsMips(); 616 if (src.IsNoRegister()) { 617 CHECK_EQ(0u, size); 618 } else if (src.IsCoreRegister()) { 619 CHECK_EQ(4u, size); 620 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 621 } else if (src.IsRegisterPair()) { 622 CHECK_EQ(8u, size); 623 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value()); 624 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), 625 SP, dest.Int32Value() + 4); 626 } else if (src.IsFRegister()) { 627 StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value()); 628 } else { 629 CHECK(src.IsDRegister()); 630 StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value()); 631 } 632} 633 634void MipsAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 635 MipsManagedRegister src = msrc.AsMips(); 636 CHECK(src.IsCoreRegister()); 637 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 638} 639 640void MipsAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 641 MipsManagedRegister src = msrc.AsMips(); 642 CHECK(src.IsCoreRegister()); 643 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 644} 645 646void MipsAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, 647 ManagedRegister mscratch) { 648 MipsManagedRegister scratch = mscratch.AsMips(); 649 CHECK(scratch.IsCoreRegister()) << scratch; 650 LoadImmediate(scratch.AsCoreRegister(), imm); 651 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 652} 653 654void MipsAssembler::StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, 655 ManagedRegister mscratch) { 656 MipsManagedRegister scratch = mscratch.AsMips(); 657 CHECK(scratch.IsCoreRegister()) << scratch; 658 LoadImmediate(scratch.AsCoreRegister(), imm); 659 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value()); 660} 661 662void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, 663 FrameOffset fr_offs, 664 ManagedRegister mscratch) { 665 MipsManagedRegister scratch = mscratch.AsMips(); 666 CHECK(scratch.IsCoreRegister()) << scratch; 667 AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value()); 668 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 669 S1, thr_offs.Int32Value()); 670} 671 672void MipsAssembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs) { 673 StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value()); 674} 675 676void MipsAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc, 677 FrameOffset in_off, ManagedRegister mscratch) { 678 MipsManagedRegister src = msrc.AsMips(); 679 MipsManagedRegister scratch = mscratch.AsMips(); 680 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value()); 681 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value()); 682 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4); 683} 684 685void MipsAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 686 return EmitLoad(mdest, SP, src.Int32Value(), size); 687} 688 689void MipsAssembler::LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) { 690 return EmitLoad(mdest, S1, src.Int32Value(), size); 691} 692 693void MipsAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 694 MipsManagedRegister dest = mdest.AsMips(); 695 CHECK(dest.IsCoreRegister()); 696 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), SP, src.Int32Value()); 697} 698 699void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, 700 bool poison_reference) { 701 MipsManagedRegister dest = mdest.AsMips(); 702 CHECK(dest.IsCoreRegister() && dest.IsCoreRegister()); 703 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 704 base.AsMips().AsCoreRegister(), offs.Int32Value()); 705 if (kPoisonHeapReferences && poison_reference) { 706 Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister()); 707 } 708} 709 710void MipsAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, 711 Offset offs) { 712 MipsManagedRegister dest = mdest.AsMips(); 713 CHECK(dest.IsCoreRegister() && dest.IsCoreRegister()) << dest; 714 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), 715 base.AsMips().AsCoreRegister(), offs.Int32Value()); 716} 717 718void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest, 719 ThreadOffset<4> offs) { 720 MipsManagedRegister dest = mdest.AsMips(); 721 CHECK(dest.IsCoreRegister()); 722 LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value()); 723} 724 725void MipsAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 726 UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips"; 727} 728 729void MipsAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) { 730 UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips"; 731} 732 733void MipsAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t /*size*/) { 734 MipsManagedRegister dest = mdest.AsMips(); 735 MipsManagedRegister src = msrc.AsMips(); 736 if (!dest.Equals(src)) { 737 if (dest.IsCoreRegister()) { 738 CHECK(src.IsCoreRegister()) << src; 739 Move(dest.AsCoreRegister(), src.AsCoreRegister()); 740 } else if (dest.IsFRegister()) { 741 CHECK(src.IsFRegister()) << src; 742 MovS(dest.AsFRegister(), src.AsFRegister()); 743 } else if (dest.IsDRegister()) { 744 CHECK(src.IsDRegister()) << src; 745 MovD(dest.AsDRegister(), src.AsDRegister()); 746 } else { 747 CHECK(dest.IsRegisterPair()) << dest; 748 CHECK(src.IsRegisterPair()) << src; 749 // Ensure that the first move doesn't clobber the input of the second 750 if (src.AsRegisterPairHigh() != dest.AsRegisterPairLow()) { 751 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 752 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 753 } else { 754 Move(dest.AsRegisterPairHigh(), src.AsRegisterPairHigh()); 755 Move(dest.AsRegisterPairLow(), src.AsRegisterPairLow()); 756 } 757 } 758 } 759} 760 761void MipsAssembler::CopyRef(FrameOffset dest, FrameOffset src, 762 ManagedRegister mscratch) { 763 MipsManagedRegister scratch = mscratch.AsMips(); 764 CHECK(scratch.IsCoreRegister()) << scratch; 765 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 766 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 767} 768 769void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs, 770 ThreadOffset<4> thr_offs, 771 ManagedRegister mscratch) { 772 MipsManagedRegister scratch = mscratch.AsMips(); 773 CHECK(scratch.IsCoreRegister()) << scratch; 774 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 775 S1, thr_offs.Int32Value()); 776 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 777 SP, fr_offs.Int32Value()); 778} 779 780void MipsAssembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs, 781 FrameOffset fr_offs, 782 ManagedRegister mscratch) { 783 MipsManagedRegister scratch = mscratch.AsMips(); 784 CHECK(scratch.IsCoreRegister()) << scratch; 785 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 786 SP, fr_offs.Int32Value()); 787 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), 788 S1, thr_offs.Int32Value()); 789} 790 791void MipsAssembler::Copy(FrameOffset dest, FrameOffset src, 792 ManagedRegister mscratch, size_t size) { 793 MipsManagedRegister scratch = mscratch.AsMips(); 794 CHECK(scratch.IsCoreRegister()) << scratch; 795 CHECK(size == 4 || size == 8) << size; 796 if (size == 4) { 797 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 798 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 799 } else if (size == 8) { 800 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value()); 801 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value()); 802 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + 4); 803 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4); 804 } 805} 806 807void MipsAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, 808 ManagedRegister mscratch, size_t size) { 809 Register scratch = mscratch.AsMips().AsCoreRegister(); 810 CHECK_EQ(size, 4u); 811 LoadFromOffset(kLoadWord, scratch, src_base.AsMips().AsCoreRegister(), src_offset.Int32Value()); 812 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value()); 813} 814 815void MipsAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, 816 ManagedRegister mscratch, size_t size) { 817 Register scratch = mscratch.AsMips().AsCoreRegister(); 818 CHECK_EQ(size, 4u); 819 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value()); 820 StoreToOffset(kStoreWord, scratch, dest_base.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 821} 822 823void MipsAssembler::Copy(FrameOffset /*dest*/, FrameOffset /*src_base*/, Offset /*src_offset*/, 824 ManagedRegister /*mscratch*/, size_t /*size*/) { 825 UNIMPLEMENTED(FATAL) << "no mips implementation"; 826} 827 828void MipsAssembler::Copy(ManagedRegister dest, Offset dest_offset, 829 ManagedRegister src, Offset src_offset, 830 ManagedRegister mscratch, size_t size) { 831 CHECK_EQ(size, 4u); 832 Register scratch = mscratch.AsMips().AsCoreRegister(); 833 LoadFromOffset(kLoadWord, scratch, src.AsMips().AsCoreRegister(), src_offset.Int32Value()); 834 StoreToOffset(kStoreWord, scratch, dest.AsMips().AsCoreRegister(), dest_offset.Int32Value()); 835} 836 837void MipsAssembler::Copy(FrameOffset /*dest*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/, 838 ManagedRegister /*mscratch*/, size_t /*size*/) { 839 UNIMPLEMENTED(FATAL) << "no mips implementation"; 840} 841 842void MipsAssembler::MemoryBarrier(ManagedRegister) { 843 UNIMPLEMENTED(FATAL) << "no mips implementation"; 844} 845 846void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 847 FrameOffset handle_scope_offset, 848 ManagedRegister min_reg, bool null_allowed) { 849 MipsManagedRegister out_reg = mout_reg.AsMips(); 850 MipsManagedRegister in_reg = min_reg.AsMips(); 851 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg; 852 CHECK(out_reg.IsCoreRegister()) << out_reg; 853 if (null_allowed) { 854 Label null_arg; 855 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 856 // the address in the handle scope holding the reference. 857 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset) 858 if (in_reg.IsNoRegister()) { 859 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 860 SP, handle_scope_offset.Int32Value()); 861 in_reg = out_reg; 862 } 863 if (!out_reg.Equals(in_reg)) { 864 LoadImmediate(out_reg.AsCoreRegister(), 0); 865 } 866 EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true); 867 AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 868 Bind(&null_arg, false); 869 } else { 870 AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 871 } 872} 873 874void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off, 875 FrameOffset handle_scope_offset, 876 ManagedRegister mscratch, 877 bool null_allowed) { 878 MipsManagedRegister scratch = mscratch.AsMips(); 879 CHECK(scratch.IsCoreRegister()) << scratch; 880 if (null_allowed) { 881 Label null_arg; 882 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, 883 handle_scope_offset.Int32Value()); 884 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 885 // the address in the handle scope holding the reference. 886 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) 887 EmitBranch(scratch.AsCoreRegister(), ZERO, &null_arg, true); 888 AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 889 Bind(&null_arg, false); 890 } else { 891 AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value()); 892 } 893 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value()); 894} 895 896// Given a handle scope entry, load the associated reference. 897void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 898 ManagedRegister min_reg) { 899 MipsManagedRegister out_reg = mout_reg.AsMips(); 900 MipsManagedRegister in_reg = min_reg.AsMips(); 901 CHECK(out_reg.IsCoreRegister()) << out_reg; 902 CHECK(in_reg.IsCoreRegister()) << in_reg; 903 Label null_arg; 904 if (!out_reg.Equals(in_reg)) { 905 LoadImmediate(out_reg.AsCoreRegister(), 0); 906 } 907 EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true); 908 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(), 909 in_reg.AsCoreRegister(), 0); 910 Bind(&null_arg, false); 911} 912 913void MipsAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) { 914 // TODO: not validating references 915} 916 917void MipsAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) { 918 // TODO: not validating references 919} 920 921void MipsAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) { 922 MipsManagedRegister base = mbase.AsMips(); 923 MipsManagedRegister scratch = mscratch.AsMips(); 924 CHECK(base.IsCoreRegister()) << base; 925 CHECK(scratch.IsCoreRegister()) << scratch; 926 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 927 base.AsCoreRegister(), offset.Int32Value()); 928 Jalr(scratch.AsCoreRegister()); 929 // TODO: place reference map on call 930} 931 932void MipsAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 933 MipsManagedRegister scratch = mscratch.AsMips(); 934 CHECK(scratch.IsCoreRegister()) << scratch; 935 // Call *(*(SP + base) + offset) 936 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 937 SP, base.Int32Value()); 938 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 939 scratch.AsCoreRegister(), offset.Int32Value()); 940 Jalr(scratch.AsCoreRegister()); 941 // TODO: place reference map on call 942} 943 944void MipsAssembler::CallFromThread32(ThreadOffset<4> /*offset*/, ManagedRegister /*mscratch*/) { 945 UNIMPLEMENTED(FATAL) << "no mips implementation"; 946} 947 948void MipsAssembler::GetCurrentThread(ManagedRegister tr) { 949 Move(tr.AsMips().AsCoreRegister(), S1); 950} 951 952void MipsAssembler::GetCurrentThread(FrameOffset offset, 953 ManagedRegister /*mscratch*/) { 954 StoreToOffset(kStoreWord, S1, SP, offset.Int32Value()); 955} 956 957void MipsAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) { 958 MipsManagedRegister scratch = mscratch.AsMips(); 959 MipsExceptionSlowPath* slow = new MipsExceptionSlowPath(scratch, stack_adjust); 960 buffer_.EnqueueSlowPath(slow); 961 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), 962 S1, Thread::ExceptionOffset<4>().Int32Value()); 963 EmitBranch(scratch.AsCoreRegister(), ZERO, slow->Entry(), false); 964} 965 966void MipsExceptionSlowPath::Emit(Assembler* sasm) { 967 MipsAssembler* sp_asm = down_cast<MipsAssembler*>(sasm); 968#define __ sp_asm-> 969 __ Bind(&entry_, false); 970 if (stack_adjust_ != 0) { // Fix up the frame. 971 __ DecreaseFrameSize(stack_adjust_); 972 } 973 // Pass exception object as argument 974 // Don't care about preserving A0 as this call won't return 975 __ Move(A0, scratch_.AsCoreRegister()); 976 // Set up call to Thread::Current()->pDeliverException 977 __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value()); 978 __ Jr(T9); 979 // Call never returns 980 __ Break(); 981#undef __ 982} 983 984} // namespace mips 985} // namespace art 986