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