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