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 FreeTemp(TargetReg(kHiddenArg)); 421 } 422 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 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 */ 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 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 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 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 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 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 558 bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) { 559 return (lir->opcode == kMipsB); 560 } 561 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 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 585 Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, 586 ArenaAllocator* const arena) { 587 return new MipsMir2Lir(cu, mir_graph, arena); 588 } 589 590 uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) { 591 DCHECK(!IsPseudoLirOp(opcode)); 592 return MipsMir2Lir::EncodingMap[opcode].flags; 593 } 594 595 const char* MipsMir2Lir::GetTargetInstName(int opcode) { 596 DCHECK(!IsPseudoLirOp(opcode)); 597 return MipsMir2Lir::EncodingMap[opcode].name; 598 } 599 600 const char* MipsMir2Lir::GetTargetInstFmt(int opcode) { 601 DCHECK(!IsPseudoLirOp(opcode)); 602 return MipsMir2Lir::EncodingMap[opcode].fmt; 603 } 604 605 } // namespace art 606