Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2012 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 "codegen_mips.h"
     18 
     19 #include <inttypes.h>
     20 
     21 #include <string>
     22 
     23 #include "dex/compiler_internals.h"
     24 #include "dex/quick/mir_to_lir-inl.h"
     25 #include "mips_lir.h"
     26 
     27 namespace art {
     28 
     29 static constexpr RegStorage core_regs_arr[] =
     30     {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
     31      rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
     32      rs_rS6, rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP, rs_rRA};
     33 static constexpr RegStorage sp_regs_arr[] =
     34     {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
     35      rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
     36 static constexpr RegStorage dp_regs_arr[] =
     37     {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
     38 static constexpr RegStorage reserved_regs_arr[] =
     39     {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
     40 static constexpr RegStorage core_temps_arr[] =
     41     {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
     42      rs_rT5, rs_rT6, rs_rT7, rs_rT8};
     43 static constexpr RegStorage sp_temps_arr[] =
     44     {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
     45      rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
     46 static constexpr RegStorage dp_temps_arr[] =
     47     {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
     48 
     49 static constexpr ArrayRef<const RegStorage> empty_pool;
     50 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
     51 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
     52 static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
     53 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
     54 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
     55 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
     56 static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
     57 
     58 RegLocation MipsMir2Lir::LocCReturn() {
     59   return mips_loc_c_return;
     60 }
     61 
     62 RegLocation MipsMir2Lir::LocCReturnRef() {
     63   return mips_loc_c_return;
     64 }
     65 
     66 RegLocation MipsMir2Lir::LocCReturnWide() {
     67   return mips_loc_c_return_wide;
     68 }
     69 
     70 RegLocation MipsMir2Lir::LocCReturnFloat() {
     71   return mips_loc_c_return_float;
     72 }
     73 
     74 RegLocation MipsMir2Lir::LocCReturnDouble() {
     75   return mips_loc_c_return_double;
     76 }
     77 
     78 // Convert k64BitSolo into k64BitPair
     79 RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
     80     DCHECK(reg.IsDouble());
     81     int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
     82     return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
     83 }
     84 
     85 // Return a target-dependent special register.
     86 RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
     87   RegStorage res_reg;
     88   switch (reg) {
     89     case kSelf: res_reg = rs_rMIPS_SELF; break;
     90     case kSuspend: res_reg =  rs_rMIPS_SUSPEND; break;
     91     case kLr: res_reg =  rs_rMIPS_LR; break;
     92     case kPc: res_reg =  rs_rMIPS_PC; break;
     93     case kSp: res_reg =  rs_rMIPS_SP; break;
     94     case kArg0: res_reg = rs_rMIPS_ARG0; break;
     95     case kArg1: res_reg = rs_rMIPS_ARG1; break;
     96     case kArg2: res_reg = rs_rMIPS_ARG2; break;
     97     case kArg3: res_reg = rs_rMIPS_ARG3; break;
     98     case kFArg0: res_reg = rs_rMIPS_FARG0; break;
     99     case kFArg1: res_reg = rs_rMIPS_FARG1; break;
    100     case kFArg2: res_reg = rs_rMIPS_FARG2; break;
    101     case kFArg3: res_reg = rs_rMIPS_FARG3; break;
    102     case kRet0: res_reg = rs_rMIPS_RET0; break;
    103     case kRet1: res_reg = rs_rMIPS_RET1; break;
    104     case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
    105     case kHiddenArg: res_reg = rs_rT0; break;
    106     case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
    107     case kCount: res_reg = rs_rMIPS_COUNT; break;
    108     default: res_reg = RegStorage::InvalidReg();
    109   }
    110   return res_reg;
    111 }
    112 
    113 RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
    114   // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
    115   switch (arg_num) {
    116     case 0:
    117       return rs_rMIPS_ARG1;
    118     case 1:
    119       return rs_rMIPS_ARG2;
    120     case 2:
    121       return rs_rMIPS_ARG3;
    122     default:
    123       return RegStorage::InvalidReg();
    124   }
    125 }
    126 
    127 /*
    128  * Decode the register id.
    129  */
    130 ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
    131   return reg.IsDouble()
    132       /* Each double register is equal to a pair of single-precision FP registers */
    133 #if (FR_BIT == 0)
    134       ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
    135 #else
    136       ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
    137 #endif
    138       : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
    139 }
    140 
    141 ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
    142   return ResourceMask::Bit(kMipsRegPC);
    143 }
    144 
    145 
    146 void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
    147                                            ResourceMask* use_mask, ResourceMask* def_mask) {
    148   DCHECK_EQ(cu_->instruction_set, kMips);
    149   DCHECK(!lir->flags.use_def_invalid);
    150 
    151   // Mips-specific resource map setup here.
    152   if (flags & REG_DEF_SP) {
    153     def_mask->SetBit(kMipsRegSP);
    154   }
    155 
    156   if (flags & REG_USE_SP) {
    157     use_mask->SetBit(kMipsRegSP);
    158   }
    159 
    160   if (flags & REG_DEF_LR) {
    161     def_mask->SetBit(kMipsRegLR);
    162   }
    163 
    164   if (flags & REG_DEF_HI) {
    165     def_mask->SetBit(kMipsRegHI);
    166   }
    167 
    168   if (flags & REG_DEF_LO) {
    169     def_mask->SetBit(kMipsRegLO);
    170   }
    171 
    172   if (flags & REG_USE_HI) {
    173     use_mask->SetBit(kMipsRegHI);
    174   }
    175 
    176   if (flags & REG_USE_LO) {
    177     use_mask->SetBit(kMipsRegLO);
    178   }
    179 }
    180 
    181 /* For dumping instructions */
    182 #define MIPS_REG_COUNT 32
    183 static const char *mips_reg_name[MIPS_REG_COUNT] = {
    184   "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
    185   "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
    186   "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
    187   "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
    188 };
    189 
    190 /*
    191  * Interpret a format string and build a string no longer than size
    192  * See format key in Assemble.c.
    193  */
    194 std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
    195   std::string buf;
    196   int i;
    197   const char *fmt_end = &fmt[strlen(fmt)];
    198   char tbuf[256];
    199   char nc;
    200   while (fmt < fmt_end) {
    201     int operand;
    202     if (*fmt == '!') {
    203       fmt++;
    204       DCHECK_LT(fmt, fmt_end);
    205       nc = *fmt++;
    206       if (nc == '!') {
    207         strcpy(tbuf, "!");
    208       } else {
    209          DCHECK_LT(fmt, fmt_end);
    210          DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
    211          operand = lir->operands[nc-'0'];
    212          switch (*fmt++) {
    213            case 'b':
    214              strcpy(tbuf, "0000");
    215              for (i = 3; i >= 0; i--) {
    216                tbuf[i] += operand & 1;
    217                operand >>= 1;
    218              }
    219              break;
    220            case 's':
    221              snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
    222              break;
    223            case 'S':
    224              DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
    225              snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
    226              break;
    227            case 'h':
    228              snprintf(tbuf, arraysize(tbuf), "%04x", operand);
    229              break;
    230            case 'M':
    231            case 'd':
    232              snprintf(tbuf, arraysize(tbuf), "%d", operand);
    233              break;
    234            case 'D':
    235              snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
    236              break;
    237            case 'E':
    238              snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
    239              break;
    240            case 'F':
    241              snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
    242              break;
    243            case 't':
    244              snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
    245                  reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
    246                  lir->target);
    247              break;
    248            case 'T':
    249              snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
    250              break;
    251            case 'u': {
    252              int offset_1 = lir->operands[0];
    253              int offset_2 = NEXT_LIR(lir)->operands[0];
    254              uintptr_t target =
    255                  (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
    256                  (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
    257              snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
    258              break;
    259           }
    260 
    261            /* Nothing to print for BLX_2 */
    262            case 'v':
    263              strcpy(tbuf, "see above");
    264              break;
    265            case 'r':
    266              DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
    267              strcpy(tbuf, mips_reg_name[operand]);
    268              break;
    269            case 'N':
    270              // Placeholder for delay slot handling
    271              strcpy(tbuf, ";  nop");
    272              break;
    273            default:
    274              strcpy(tbuf, "DecodeError");
    275              break;
    276          }
    277          buf += tbuf;
    278       }
    279     } else {
    280        buf += *fmt++;
    281     }
    282   }
    283   return buf;
    284 }
    285 
    286 // FIXME: need to redo resource maps for MIPS - fix this at that time
    287 void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
    288   char buf[256];
    289   buf[0] = 0;
    290 
    291   if (mask.Equals(kEncodeAll)) {
    292     strcpy(buf, "all");
    293   } else {
    294     char num[8];
    295     int i;
    296 
    297     for (i = 0; i < kMipsRegEnd; i++) {
    298       if (mask.HasBit(i)) {
    299         snprintf(num, arraysize(num), "%d ", i);
    300         strcat(buf, num);
    301       }
    302     }
    303 
    304     if (mask.HasBit(ResourceMask::kCCode)) {
    305       strcat(buf, "cc ");
    306     }
    307     if (mask.HasBit(ResourceMask::kFPStatus)) {
    308       strcat(buf, "fpcc ");
    309     }
    310     /* Memory bits */
    311     if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
    312       snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
    313                DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
    314                DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
    315     }
    316     if (mask.HasBit(ResourceMask::kLiteral)) {
    317       strcat(buf, "lit ");
    318     }
    319 
    320     if (mask.HasBit(ResourceMask::kHeapRef)) {
    321       strcat(buf, "heap ");
    322     }
    323     if (mask.HasBit(ResourceMask::kMustNotAlias)) {
    324       strcat(buf, "noalias ");
    325     }
    326   }
    327   if (buf[0]) {
    328     LOG(INFO) << prefix << ": " <<  buf;
    329   }
    330 }
    331 
    332 /*
    333  * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
    334  * instructions might call out to C/assembly helper functions.  Until
    335  * machinery is in place, always spill lr.
    336  */
    337 
    338 void MipsMir2Lir::AdjustSpillMask() {
    339   core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
    340   num_core_spills_++;
    341 }
    342 
    343 /* Clobber all regs that might be used by an external C call */
    344 void MipsMir2Lir::ClobberCallerSave() {
    345   Clobber(rs_rZERO);
    346   Clobber(rs_rAT);
    347   Clobber(rs_rV0);
    348   Clobber(rs_rV1);
    349   Clobber(rs_rA0);
    350   Clobber(rs_rA1);
    351   Clobber(rs_rA2);
    352   Clobber(rs_rA3);
    353   Clobber(rs_rT0);
    354   Clobber(rs_rT1);
    355   Clobber(rs_rT2);
    356   Clobber(rs_rT3);
    357   Clobber(rs_rT4);
    358   Clobber(rs_rT5);
    359   Clobber(rs_rT6);
    360   Clobber(rs_rT7);
    361   Clobber(rs_rT8);
    362   Clobber(rs_rT9);
    363   Clobber(rs_rK0);
    364   Clobber(rs_rK1);
    365   Clobber(rs_rGP);
    366   Clobber(rs_rFP);
    367   Clobber(rs_rRA);
    368   Clobber(rs_rF0);
    369   Clobber(rs_rF1);
    370   Clobber(rs_rF2);
    371   Clobber(rs_rF3);
    372   Clobber(rs_rF4);
    373   Clobber(rs_rF5);
    374   Clobber(rs_rF6);
    375   Clobber(rs_rF7);
    376   Clobber(rs_rF8);
    377   Clobber(rs_rF9);
    378   Clobber(rs_rF10);
    379   Clobber(rs_rF11);
    380   Clobber(rs_rF12);
    381   Clobber(rs_rF13);
    382   Clobber(rs_rF14);
    383   Clobber(rs_rF15);
    384   Clobber(rs_rD0);
    385   Clobber(rs_rD1);
    386   Clobber(rs_rD2);
    387   Clobber(rs_rD3);
    388   Clobber(rs_rD4);
    389   Clobber(rs_rD5);
    390   Clobber(rs_rD6);
    391   Clobber(rs_rD7);
    392 }
    393 
    394 RegLocation MipsMir2Lir::GetReturnWideAlt() {
    395   UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
    396   RegLocation res = LocCReturnWide();
    397   return res;
    398 }
    399 
    400 RegLocation MipsMir2Lir::GetReturnAlt() {
    401   UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
    402   RegLocation res = LocCReturn();
    403   return res;
    404 }
    405 
    406 /* To be used when explicitly managing register use */
    407 void MipsMir2Lir::LockCallTemps() {
    408   LockTemp(rs_rMIPS_ARG0);
    409   LockTemp(rs_rMIPS_ARG1);
    410   LockTemp(rs_rMIPS_ARG2);
    411   LockTemp(rs_rMIPS_ARG3);
    412 }
    413 
    414 /* To be used when explicitly managing register use */
    415 void MipsMir2Lir::FreeCallTemps() {
    416   FreeTemp(rs_rMIPS_ARG0);
    417   FreeTemp(rs_rMIPS_ARG1);
    418   FreeTemp(rs_rMIPS_ARG2);
    419   FreeTemp(rs_rMIPS_ARG3);
    420   FreeTemp(TargetReg(kHiddenArg));
    421 }
    422 
    423 bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
    424 #if ANDROID_SMP != 0
    425   NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
    426   return true;
    427 #else
    428   return false;
    429 #endif
    430 }
    431 
    432 void MipsMir2Lir::CompilerInitializeRegAlloc() {
    433   reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
    434                                         dp_regs, reserved_regs, empty_pool /* reserved64 */,
    435                                         core_temps, empty_pool /* core64_temps */, sp_temps,
    436                                         dp_temps);
    437 
    438   // Target-specific adjustments.
    439 
    440   // Alias single precision floats to appropriate half of overlapping double.
    441   GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
    442   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
    443     int sp_reg_num = info->GetReg().GetRegNum();
    444 #if (FR_BIT == 0)
    445     int dp_reg_num = sp_reg_num & ~1;
    446 #else
    447     int dp_reg_num = sp_reg_num >> 1;
    448 #endif
    449     RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
    450     RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
    451     // Double precision register's master storage should refer to itself.
    452     DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
    453     // Redirect single precision's master storage to master.
    454     info->SetMaster(dp_reg_info);
    455     // Singles should show a single 32-bit mask bit, at first referring to the low half.
    456     DCHECK_EQ(info->StorageMask(), 0x1U);
    457     if (sp_reg_num & 1) {
    458       // For odd singles, change to user the high word of the backing double.
    459       info->SetStorageMask(0x2);
    460     }
    461   }
    462 
    463   // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
    464   // TODO: adjust when we roll to hard float calling convention.
    465   reg_pool_->next_core_reg_ = 2;
    466   reg_pool_->next_sp_reg_ = 2;
    467 #if (FR_BIT == 0)
    468   reg_pool_->next_dp_reg_ = 2;
    469 #else
    470   reg_pool_->next_dp_reg_ = 1;
    471 #endif
    472 }
    473 
    474 /*
    475  * In the Arm code a it is typical to use the link register
    476  * to hold the target address.  However, for Mips we must
    477  * ensure that all branch instructions can be restarted if
    478  * there is a trap in the shadow.  Allocate a temp register.
    479  */
    480 RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
    481   // NOTE: native pointer.
    482   LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
    483   return rs_rT9;
    484 }
    485 
    486 LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
    487   RegStorage tmp = AllocTemp();
    488   // NOTE: native pointer.
    489   LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
    490   LIR *inst = LoadWordDisp(tmp, 0, tmp);
    491   FreeTemp(tmp);
    492   return inst;
    493 }
    494 
    495 LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
    496   DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadStore().
    497   DCHECK(r_dest.IsPair());
    498   ClobberCallerSave();
    499   LockCallTemps();  // Using fixed registers
    500   RegStorage reg_ptr = TargetReg(kArg0);
    501   OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
    502   RegStorage r_tgt = LoadHelper(kQuickA64Load);
    503   LIR *ret = OpReg(kOpBlx, r_tgt);
    504   RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
    505   OpRegCopyWide(r_dest, reg_ret);
    506   return ret;
    507 }
    508 
    509 LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
    510   DCHECK(!r_src.IsFloat());  // See RegClassForFieldLoadStore().
    511   DCHECK(r_src.IsPair());
    512   ClobberCallerSave();
    513   LockCallTemps();  // Using fixed registers
    514   RegStorage temp_ptr = AllocTemp();
    515   OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
    516   RegStorage temp_value = AllocTempWide();
    517   OpRegCopyWide(temp_value, r_src);
    518   RegStorage reg_ptr = TargetReg(kArg0);
    519   OpRegCopy(reg_ptr, temp_ptr);
    520   RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
    521   OpRegCopyWide(reg_value, temp_value);
    522   FreeTemp(temp_ptr);
    523   FreeTemp(temp_value);
    524   RegStorage r_tgt = LoadHelper(kQuickA64Store);
    525   return OpReg(kOpBlx, r_tgt);
    526 }
    527 
    528 void MipsMir2Lir::SpillCoreRegs() {
    529   if (num_core_spills_ == 0) {
    530     return;
    531   }
    532   uint32_t mask = core_spill_mask_;
    533   int offset = num_core_spills_ * 4;
    534   OpRegImm(kOpSub, rs_rSP, offset);
    535   for (int reg = 0; mask; mask >>= 1, reg++) {
    536     if (mask & 0x1) {
    537       offset -= 4;
    538       Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
    539     }
    540   }
    541 }
    542 
    543 void MipsMir2Lir::UnSpillCoreRegs() {
    544   if (num_core_spills_ == 0) {
    545     return;
    546   }
    547   uint32_t mask = core_spill_mask_;
    548   int offset = frame_size_;
    549   for (int reg = 0; mask; mask >>= 1, reg++) {
    550     if (mask & 0x1) {
    551       offset -= 4;
    552       Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
    553     }
    554   }
    555   OpRegImm(kOpAdd, rs_rSP, frame_size_);
    556 }
    557 
    558 bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
    559   return (lir->opcode == kMipsB);
    560 }
    561 
    562 RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
    563   if (UNLIKELY(is_volatile)) {
    564     // On Mips, atomic 64-bit load/store requires a core register.
    565     // Smaller aligned load/store is atomic for both core and fp registers.
    566     if (size == k64 || size == kDouble) {
    567       return kCoreReg;
    568     }
    569   }
    570   // TODO: Verify that both core and fp registers are suitable for smaller sizes.
    571   return RegClassBySize(size);
    572 }
    573 
    574 MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
    575     : Mir2Lir(cu, mir_graph, arena) {
    576   for (int i = 0; i < kMipsLast; i++) {
    577     if (MipsMir2Lir::EncodingMap[i].opcode != i) {
    578       LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
    579                  << " is wrong: expecting " << i << ", seeing "
    580                  << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
    581     }
    582   }
    583 }
    584 
    585 Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
    586                            ArenaAllocator* const arena) {
    587   return new MipsMir2Lir(cu, mir_graph, arena);
    588 }
    589 
    590 uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
    591   DCHECK(!IsPseudoLirOp(opcode));
    592   return MipsMir2Lir::EncodingMap[opcode].flags;
    593 }
    594 
    595 const char* MipsMir2Lir::GetTargetInstName(int opcode) {
    596   DCHECK(!IsPseudoLirOp(opcode));
    597   return MipsMir2Lir::EncodingMap[opcode].name;
    598 }
    599 
    600 const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
    601   DCHECK(!IsPseudoLirOp(opcode));
    602   return MipsMir2Lir::EncodingMap[opcode].fmt;
    603 }
    604 
    605 }  // namespace art
    606