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(®_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