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 }
    421 
    422 bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
    423 #if ANDROID_SMP != 0
    424   NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
    425   return true;
    426 #else
    427   return false;
    428 #endif
    429 }
    430 
    431 void MipsMir2Lir::CompilerInitializeRegAlloc() {
    432   reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
    433                                         dp_regs, reserved_regs, empty_pool /* reserved64 */,
    434                                         core_temps, empty_pool /* core64_temps */, sp_temps,
    435                                         dp_temps);
    436 
    437   // Target-specific adjustments.
    438 
    439   // Alias single precision floats to appropriate half of overlapping double.
    440   GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
    441   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
    442     int sp_reg_num = info->GetReg().GetRegNum();
    443 #if (FR_BIT == 0)
    444     int dp_reg_num = sp_reg_num & ~1;
    445 #else
    446     int dp_reg_num = sp_reg_num >> 1;
    447 #endif
    448     RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
    449     RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
    450     // Double precision register's master storage should refer to itself.
    451     DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
    452     // Redirect single precision's master storage to master.
    453     info->SetMaster(dp_reg_info);
    454     // Singles should show a single 32-bit mask bit, at first referring to the low half.
    455     DCHECK_EQ(info->StorageMask(), 0x1U);
    456     if (sp_reg_num & 1) {
    457       // For odd singles, change to user the high word of the backing double.
    458       info->SetStorageMask(0x2);
    459     }
    460   }
    461 
    462   // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
    463   // TODO: adjust when we roll to hard float calling convention.
    464   reg_pool_->next_core_reg_ = 2;
    465   reg_pool_->next_sp_reg_ = 2;
    466 #if (FR_BIT == 0)
    467   reg_pool_->next_dp_reg_ = 2;
    468 #else
    469   reg_pool_->next_dp_reg_ = 1;
    470 #endif
    471 }
    472 
    473 /*
    474  * In the Arm code a it is typical to use the link register
    475  * to hold the target address.  However, for Mips we must
    476  * ensure that all branch instructions can be restarted if
    477  * there is a trap in the shadow.  Allocate a temp register.
    478  */
    479 RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
    480   // NOTE: native pointer.
    481   LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
    482   return rs_rT9;
    483 }
    484 
    485 LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
    486   RegStorage tmp = AllocTemp();
    487   // NOTE: native pointer.
    488   LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
    489   LIR *inst = LoadWordDisp(tmp, 0, tmp);
    490   FreeTemp(tmp);
    491   return inst;
    492 }
    493 
    494 LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
    495   DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadStore().
    496   DCHECK(r_dest.IsPair());
    497   ClobberCallerSave();
    498   LockCallTemps();  // Using fixed registers
    499   RegStorage reg_ptr = TargetReg(kArg0);
    500   OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
    501   RegStorage r_tgt = LoadHelper(kQuickA64Load);
    502   LIR *ret = OpReg(kOpBlx, r_tgt);
    503   RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
    504   OpRegCopyWide(r_dest, reg_ret);
    505   return ret;
    506 }
    507 
    508 LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
    509   DCHECK(!r_src.IsFloat());  // See RegClassForFieldLoadStore().
    510   DCHECK(r_src.IsPair());
    511   ClobberCallerSave();
    512   LockCallTemps();  // Using fixed registers
    513   RegStorage temp_ptr = AllocTemp();
    514   OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
    515   RegStorage temp_value = AllocTempWide();
    516   OpRegCopyWide(temp_value, r_src);
    517   RegStorage reg_ptr = TargetReg(kArg0);
    518   OpRegCopy(reg_ptr, temp_ptr);
    519   RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
    520   OpRegCopyWide(reg_value, temp_value);
    521   FreeTemp(temp_ptr);
    522   FreeTemp(temp_value);
    523   RegStorage r_tgt = LoadHelper(kQuickA64Store);
    524   return OpReg(kOpBlx, r_tgt);
    525 }
    526 
    527 void MipsMir2Lir::SpillCoreRegs() {
    528   if (num_core_spills_ == 0) {
    529     return;
    530   }
    531   uint32_t mask = core_spill_mask_;
    532   int offset = num_core_spills_ * 4;
    533   OpRegImm(kOpSub, rs_rSP, offset);
    534   for (int reg = 0; mask; mask >>= 1, reg++) {
    535     if (mask & 0x1) {
    536       offset -= 4;
    537       Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
    538     }
    539   }
    540 }
    541 
    542 void MipsMir2Lir::UnSpillCoreRegs() {
    543   if (num_core_spills_ == 0) {
    544     return;
    545   }
    546   uint32_t mask = core_spill_mask_;
    547   int offset = frame_size_;
    548   for (int reg = 0; mask; mask >>= 1, reg++) {
    549     if (mask & 0x1) {
    550       offset -= 4;
    551       Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
    552     }
    553   }
    554   OpRegImm(kOpAdd, rs_rSP, frame_size_);
    555 }
    556 
    557 bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
    558   return (lir->opcode == kMipsB);
    559 }
    560 
    561 RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
    562   if (UNLIKELY(is_volatile)) {
    563     // On Mips, atomic 64-bit load/store requires a core register.
    564     // Smaller aligned load/store is atomic for both core and fp registers.
    565     if (size == k64 || size == kDouble) {
    566       return kCoreReg;
    567     }
    568   }
    569   // TODO: Verify that both core and fp registers are suitable for smaller sizes.
    570   return RegClassBySize(size);
    571 }
    572 
    573 MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
    574     : Mir2Lir(cu, mir_graph, arena) {
    575   for (int i = 0; i < kMipsLast; i++) {
    576     if (MipsMir2Lir::EncodingMap[i].opcode != i) {
    577       LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
    578                  << " is wrong: expecting " << i << ", seeing "
    579                  << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
    580     }
    581   }
    582 }
    583 
    584 Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
    585                            ArenaAllocator* const arena) {
    586   return new MipsMir2Lir(cu, mir_graph, arena);
    587 }
    588 
    589 uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
    590   DCHECK(!IsPseudoLirOp(opcode));
    591   return MipsMir2Lir::EncodingMap[opcode].flags;
    592 }
    593 
    594 const char* MipsMir2Lir::GetTargetInstName(int opcode) {
    595   DCHECK(!IsPseudoLirOp(opcode));
    596   return MipsMir2Lir::EncodingMap[opcode].name;
    597 }
    598 
    599 const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
    600   DCHECK(!IsPseudoLirOp(opcode));
    601   return MipsMir2Lir::EncodingMap[opcode].fmt;
    602 }
    603 
    604 }  // namespace art
    605