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 }
421
GenMemBarrier(MemBarrierKind barrier_kind)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
CompilerInitializeRegAlloc()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(®_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 */
LoadHelper(QuickEntrypointEnum trampoline)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
CheckSuspendUsingLoad()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
GenAtomic64Load(RegStorage r_base,int displacement,RegStorage r_dest)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
GenAtomic64Store(RegStorage r_base,int displacement,RegStorage r_src)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
SpillCoreRegs()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
UnSpillCoreRegs()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
IsUnconditionalBranch(LIR * lir)557 bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
558 return (lir->opcode == kMipsB);
559 }
560
RegClassForFieldLoadStore(OpSize size,bool is_volatile)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
MipsMir2Lir(CompilationUnit * cu,MIRGraph * mir_graph,ArenaAllocator * arena)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
MipsCodeGenerator(CompilationUnit * const cu,MIRGraph * const mir_graph,ArenaAllocator * const arena)584 Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
585 ArenaAllocator* const arena) {
586 return new MipsMir2Lir(cu, mir_graph, arena);
587 }
588
GetTargetInstFlags(int opcode)589 uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
590 DCHECK(!IsPseudoLirOp(opcode));
591 return MipsMir2Lir::EncodingMap[opcode].flags;
592 }
593
GetTargetInstName(int opcode)594 const char* MipsMir2Lir::GetTargetInstName(int opcode) {
595 DCHECK(!IsPseudoLirOp(opcode));
596 return MipsMir2Lir::EncodingMap[opcode].name;
597 }
598
GetTargetInstFmt(int opcode)599 const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
600 DCHECK(!IsPseudoLirOp(opcode));
601 return MipsMir2Lir::EncodingMap[opcode].fmt;
602 }
603
604 } // namespace art
605