target_mips.cc revision 984305917bf57b3f8d92965e4715a0370cc5bcfb
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
27namespace art {
28
29static 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};
33static 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};
36static constexpr RegStorage dp_regs_arr[] =
37    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
38static constexpr RegStorage reserved_regs_arr[] =
39    {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
40static 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};
43static 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};
46static constexpr RegStorage dp_temps_arr[] =
47    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
48
49static constexpr ArrayRef<const RegStorage> empty_pool;
50static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
51static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
52static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
53static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
54static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
55static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
56static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
57
58RegLocation MipsMir2Lir::LocCReturn() {
59  return mips_loc_c_return;
60}
61
62RegLocation MipsMir2Lir::LocCReturnRef() {
63  return mips_loc_c_return;
64}
65
66RegLocation MipsMir2Lir::LocCReturnWide() {
67  return mips_loc_c_return_wide;
68}
69
70RegLocation MipsMir2Lir::LocCReturnFloat() {
71  return mips_loc_c_return_float;
72}
73
74RegLocation MipsMir2Lir::LocCReturnDouble() {
75  return mips_loc_c_return_double;
76}
77
78// Convert k64BitSolo into k64BitPair
79RegStorage 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.
86RegStorage 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
113RegStorage 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 */
130ResourceMask 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
141ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
142  return ResourceMask::Bit(kMipsRegPC);
143}
144
145
146void 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
183static 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 */
194std::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
287void 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
338void 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 */
344void 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
394RegLocation MipsMir2Lir::GetReturnWideAlt() {
395  UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
396  RegLocation res = LocCReturnWide();
397  return res;
398}
399
400RegLocation 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 */
407void 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 */
415void MipsMir2Lir::FreeCallTemps() {
416  FreeTemp(rs_rMIPS_ARG0);
417  FreeTemp(rs_rMIPS_ARG1);
418  FreeTemp(rs_rMIPS_ARG2);
419  FreeTemp(rs_rMIPS_ARG3);
420}
421
422bool 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
431void 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 */
479RegStorage 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
485LIR* 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
494LIR* 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
508LIR* 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
527void 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
542void 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
557bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
558  return (lir->opcode == kMipsB);
559}
560
561RegisterClass 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
573MipsMir2Lir::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
584Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
585                           ArenaAllocator* const arena) {
586  return new MipsMir2Lir(cu, mir_graph, arena);
587}
588
589uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
590  DCHECK(!IsPseudoLirOp(opcode));
591  return MipsMir2Lir::EncodingMap[opcode].flags;
592}
593
594const char* MipsMir2Lir::GetTargetInstName(int opcode) {
595  DCHECK(!IsPseudoLirOp(opcode));
596  return MipsMir2Lir::EncodingMap[opcode].name;
597}
598
599const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
600  DCHECK(!IsPseudoLirOp(opcode));
601  return MipsMir2Lir::EncodingMap[opcode].fmt;
602}
603
604}  // namespace art
605