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 
LocCReturn()58 RegLocation MipsMir2Lir::LocCReturn() {
59   return mips_loc_c_return;
60 }
61 
LocCReturnRef()62 RegLocation MipsMir2Lir::LocCReturnRef() {
63   return mips_loc_c_return;
64 }
65 
LocCReturnWide()66 RegLocation MipsMir2Lir::LocCReturnWide() {
67   return mips_loc_c_return_wide;
68 }
69 
LocCReturnFloat()70 RegLocation MipsMir2Lir::LocCReturnFloat() {
71   return mips_loc_c_return_float;
72 }
73 
LocCReturnDouble()74 RegLocation MipsMir2Lir::LocCReturnDouble() {
75   return mips_loc_c_return_double;
76 }
77 
78 // Convert k64BitSolo into k64BitPair
Solo64ToPair64(RegStorage reg)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.
TargetReg(SpecialTargetRegister reg)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 
GetArgMappingToPhysicalReg(int arg_num)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  */
GetRegMaskCommon(const RegStorage & reg) const130 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 
GetPCUseDefEncoding() const141 ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
142   return ResourceMask::Bit(kMipsRegPC);
143 }
144 
145 
SetupTargetResourceMasks(LIR * lir,uint64_t flags,ResourceMask * use_mask,ResourceMask * def_mask)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  */
BuildInsnString(const char * fmt,LIR * lir,unsigned char * base_addr)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
DumpResourceMask(LIR * mips_lir,const ResourceMask & mask,const char * prefix)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 
AdjustSpillMask()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 */
ClobberCallerSave()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 
GetReturnWideAlt()394 RegLocation MipsMir2Lir::GetReturnWideAlt() {
395   UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
396   RegLocation res = LocCReturnWide();
397   return res;
398 }
399 
GetReturnAlt()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 */
LockCallTemps()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 */
FreeCallTemps()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 
GenMemBarrier(MemBarrierKind barrier_kind)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 
CompilerInitializeRegAlloc()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  */
LoadHelper(QuickEntrypointEnum trampoline)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 
CheckSuspendUsingLoad()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 
GenAtomic64Load(RegStorage r_base,int displacement,RegStorage r_dest)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 
GenAtomic64Store(RegStorage r_base,int displacement,RegStorage r_src)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 
SpillCoreRegs()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 
UnSpillCoreRegs()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 
IsUnconditionalBranch(LIR * lir)558 bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
559   return (lir->opcode == kMipsB);
560 }
561 
RegClassForFieldLoadStore(OpSize size,bool is_volatile)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 
MipsMir2Lir(CompilationUnit * cu,MIRGraph * mir_graph,ArenaAllocator * arena)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 
MipsCodeGenerator(CompilationUnit * const cu,MIRGraph * const mir_graph,ArenaAllocator * const arena)585 Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
586                            ArenaAllocator* const arena) {
587   return new MipsMir2Lir(cu, mir_graph, arena);
588 }
589 
GetTargetInstFlags(int opcode)590 uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
591   DCHECK(!IsPseudoLirOp(opcode));
592   return MipsMir2Lir::EncodingMap[opcode].flags;
593 }
594 
GetTargetInstName(int opcode)595 const char* MipsMir2Lir::GetTargetInstName(int opcode) {
596   DCHECK(!IsPseudoLirOp(opcode));
597   return MipsMir2Lir::EncodingMap[opcode].name;
598 }
599 
GetTargetInstFmt(int opcode)600 const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
601   DCHECK(!IsPseudoLirOp(opcode));
602   return MipsMir2Lir::EncodingMap[opcode].fmt;
603 }
604 
605 }  // namespace art
606