1 /* 2 * Copyright (C) 2011 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_arm.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 26 namespace art { 27 28 #ifdef ARM_R4_SUSPEND_FLAG 29 static constexpr RegStorage core_regs_arr[] = 30 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF, 31 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC}; 32 #else 33 static constexpr RegStorage core_regs_arr[] = 34 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF, 35 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC}; 36 #endif 37 static constexpr RegStorage sp_regs_arr[] = 38 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10, 39 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20, 40 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30, 41 rs_fr31}; 42 static constexpr RegStorage dp_regs_arr[] = 43 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10, 44 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15}; 45 #ifdef ARM_R4_SUSPEND_FLAG 46 static constexpr RegStorage reserved_regs_arr[] = 47 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC}; 48 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12}; 49 #else 50 static constexpr RegStorage reserved_regs_arr[] = 51 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC}; 52 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12}; 53 #endif 54 static constexpr RegStorage sp_temps_arr[] = 55 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10, 56 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15}; 57 static constexpr RegStorage dp_temps_arr[] = 58 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7}; 59 60 static constexpr ArrayRef<const RegStorage> empty_pool; 61 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr); 62 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr); 63 static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr); 64 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr); 65 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr); 66 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr); 67 static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr); 68 69 RegLocation ArmMir2Lir::LocCReturn() { 70 return arm_loc_c_return; 71 } 72 73 RegLocation ArmMir2Lir::LocCReturnRef() { 74 return arm_loc_c_return; 75 } 76 77 RegLocation ArmMir2Lir::LocCReturnWide() { 78 return arm_loc_c_return_wide; 79 } 80 81 RegLocation ArmMir2Lir::LocCReturnFloat() { 82 return arm_loc_c_return_float; 83 } 84 85 RegLocation ArmMir2Lir::LocCReturnDouble() { 86 return arm_loc_c_return_double; 87 } 88 89 // Return a target-dependent special register. 90 RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) { 91 RegStorage res_reg = RegStorage::InvalidReg(); 92 switch (reg) { 93 case kSelf: res_reg = rs_rARM_SELF; break; 94 #ifdef ARM_R4_SUSPEND_FLAG 95 case kSuspend: res_reg = rs_rARM_SUSPEND; break; 96 #else 97 case kSuspend: res_reg = RegStorage::InvalidReg(); break; 98 #endif 99 case kLr: res_reg = rs_rARM_LR; break; 100 case kPc: res_reg = rs_rARM_PC; break; 101 case kSp: res_reg = rs_rARM_SP; break; 102 case kArg0: res_reg = rs_r0; break; 103 case kArg1: res_reg = rs_r1; break; 104 case kArg2: res_reg = rs_r2; break; 105 case kArg3: res_reg = rs_r3; break; 106 case kFArg0: res_reg = rs_r0; break; 107 case kFArg1: res_reg = rs_r1; break; 108 case kFArg2: res_reg = rs_r2; break; 109 case kFArg3: res_reg = rs_r3; break; 110 case kRet0: res_reg = rs_r0; break; 111 case kRet1: res_reg = rs_r1; break; 112 case kInvokeTgt: res_reg = rs_rARM_LR; break; 113 case kHiddenArg: res_reg = rs_r12; break; 114 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break; 115 case kCount: res_reg = RegStorage::InvalidReg(); break; 116 default: res_reg = RegStorage::InvalidReg(); 117 } 118 return res_reg; 119 } 120 121 RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) { 122 // For the 32-bit internal ABI, the first 3 arguments are passed in registers. 123 switch (arg_num) { 124 case 0: 125 return rs_r1; 126 case 1: 127 return rs_r2; 128 case 2: 129 return rs_r3; 130 default: 131 return RegStorage::InvalidReg(); 132 } 133 } 134 135 /* 136 * Decode the register id. 137 */ 138 ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const { 139 return GetRegMaskArm(reg); 140 } 141 142 constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) { 143 return reg.IsDouble() 144 /* Each double register is equal to a pair of single-precision FP registers */ 145 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0) 146 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum()); 147 } 148 149 constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) { 150 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u); 151 } 152 153 constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) { 154 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u); 155 } 156 157 ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const { 158 return ResourceMask::Bit(kArmRegPC); 159 } 160 161 // Thumb2 specific setup. TODO: inline?: 162 void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags, 163 ResourceMask* use_mask, ResourceMask* def_mask) { 164 DCHECK_EQ(cu_->instruction_set, kThumb2); 165 DCHECK(!lir->flags.use_def_invalid); 166 167 int opcode = lir->opcode; 168 169 // These flags are somewhat uncommon - bypass if we can. 170 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 | 171 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 | 172 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) { 173 if (flags & REG_DEF_SP) { 174 def_mask->SetBit(kArmRegSP); 175 } 176 177 if (flags & REG_USE_SP) { 178 use_mask->SetBit(kArmRegSP); 179 } 180 181 if (flags & REG_DEF_LIST0) { 182 def_mask->SetBits(EncodeArmRegList(lir->operands[0])); 183 } 184 185 if (flags & REG_DEF_LIST1) { 186 def_mask->SetBits(EncodeArmRegList(lir->operands[1])); 187 } 188 189 if (flags & REG_DEF_FPCS_LIST0) { 190 def_mask->SetBits(EncodeArmRegList(lir->operands[0])); 191 } 192 193 if (flags & REG_DEF_FPCS_LIST2) { 194 for (int i = 0; i < lir->operands[2]; i++) { 195 SetupRegMask(def_mask, lir->operands[1] + i); 196 } 197 } 198 199 if (flags & REG_USE_PC) { 200 use_mask->SetBit(kArmRegPC); 201 } 202 203 /* Conservatively treat the IT block */ 204 if (flags & IS_IT) { 205 *def_mask = kEncodeAll; 206 } 207 208 if (flags & REG_USE_LIST0) { 209 use_mask->SetBits(EncodeArmRegList(lir->operands[0])); 210 } 211 212 if (flags & REG_USE_LIST1) { 213 use_mask->SetBits(EncodeArmRegList(lir->operands[1])); 214 } 215 216 if (flags & REG_USE_FPCS_LIST0) { 217 use_mask->SetBits(EncodeArmRegList(lir->operands[0])); 218 } 219 220 if (flags & REG_USE_FPCS_LIST2) { 221 for (int i = 0; i < lir->operands[2]; i++) { 222 SetupRegMask(use_mask, lir->operands[1] + i); 223 } 224 } 225 /* Fixup for kThumbPush/lr and kThumbPop/pc */ 226 if (opcode == kThumbPush || opcode == kThumbPop) { 227 constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8); 228 if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) { 229 use_mask->ClearBits(r8Mask); 230 use_mask->SetBit(kArmRegLR); 231 } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) { 232 def_mask->ClearBits(r8Mask); 233 def_mask->SetBit(kArmRegPC);; 234 } 235 } 236 if (flags & REG_DEF_LR) { 237 def_mask->SetBit(kArmRegLR); 238 } 239 } 240 } 241 242 ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) { 243 ArmConditionCode res; 244 switch (ccode) { 245 case kCondEq: res = kArmCondEq; break; 246 case kCondNe: res = kArmCondNe; break; 247 case kCondCs: res = kArmCondCs; break; 248 case kCondCc: res = kArmCondCc; break; 249 case kCondUlt: res = kArmCondCc; break; 250 case kCondUge: res = kArmCondCs; break; 251 case kCondMi: res = kArmCondMi; break; 252 case kCondPl: res = kArmCondPl; break; 253 case kCondVs: res = kArmCondVs; break; 254 case kCondVc: res = kArmCondVc; break; 255 case kCondHi: res = kArmCondHi; break; 256 case kCondLs: res = kArmCondLs; break; 257 case kCondGe: res = kArmCondGe; break; 258 case kCondLt: res = kArmCondLt; break; 259 case kCondGt: res = kArmCondGt; break; 260 case kCondLe: res = kArmCondLe; break; 261 case kCondAl: res = kArmCondAl; break; 262 case kCondNv: res = kArmCondNv; break; 263 default: 264 LOG(FATAL) << "Bad condition code " << ccode; 265 res = static_cast<ArmConditionCode>(0); // Quiet gcc 266 } 267 return res; 268 } 269 270 static const char* core_reg_names[16] = { 271 "r0", 272 "r1", 273 "r2", 274 "r3", 275 "r4", 276 "r5", 277 "r6", 278 "r7", 279 "r8", 280 "rSELF", 281 "r10", 282 "r11", 283 "r12", 284 "sp", 285 "lr", 286 "pc", 287 }; 288 289 290 static const char* shift_names[4] = { 291 "lsl", 292 "lsr", 293 "asr", 294 "ror"}; 295 296 /* Decode and print a ARM register name */ 297 static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) { 298 int i; 299 bool printed = false; 300 buf[0] = 0; 301 for (i = 0; i < 16; i++, vector >>= 1) { 302 if (vector & 0x1) { 303 int reg_id = i; 304 if (opcode == kThumbPush && i == 8) { 305 reg_id = rs_rARM_LR.GetRegNum(); 306 } else if (opcode == kThumbPop && i == 8) { 307 reg_id = rs_rARM_PC.GetRegNum(); 308 } 309 if (printed) { 310 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id); 311 } else { 312 printed = true; 313 snprintf(buf, buf_size, "r%d", reg_id); 314 } 315 } 316 } 317 return buf; 318 } 319 320 static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) { 321 snprintf(buf, buf_size, "s%d", base); 322 for (int i = 1; i < count; i++) { 323 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i); 324 } 325 return buf; 326 } 327 328 static int32_t ExpandImmediate(int value) { 329 int32_t mode = (value & 0xf00) >> 8; 330 uint32_t bits = value & 0xff; 331 switch (mode) { 332 case 0: 333 return bits; 334 case 1: 335 return (bits << 16) | bits; 336 case 2: 337 return (bits << 24) | (bits << 8); 338 case 3: 339 return (bits << 24) | (bits << 16) | (bits << 8) | bits; 340 default: 341 break; 342 } 343 bits = (bits | 0x80) << 24; 344 return bits >> (((value & 0xf80) >> 7) - 8); 345 } 346 347 const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 348 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"}; 349 /* 350 * Interpret a format string and build a string no longer than size 351 * See format key in Assemble.c. 352 */ 353 std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) { 354 std::string buf; 355 int i; 356 const char* fmt_end = &fmt[strlen(fmt)]; 357 char tbuf[256]; 358 const char* name; 359 char nc; 360 while (fmt < fmt_end) { 361 int operand; 362 if (*fmt == '!') { 363 fmt++; 364 DCHECK_LT(fmt, fmt_end); 365 nc = *fmt++; 366 if (nc == '!') { 367 strcpy(tbuf, "!"); 368 } else { 369 DCHECK_LT(fmt, fmt_end); 370 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U); 371 operand = lir->operands[nc-'0']; 372 switch (*fmt++) { 373 case 'H': 374 if (operand != 0) { 375 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2); 376 } else { 377 strcpy(tbuf, ""); 378 } 379 break; 380 case 'B': 381 switch (operand) { 382 case kSY: 383 name = "sy"; 384 break; 385 case kST: 386 name = "st"; 387 break; 388 case kISH: 389 name = "ish"; 390 break; 391 case kISHST: 392 name = "ishst"; 393 break; 394 case kNSH: 395 name = "nsh"; 396 break; 397 case kNSHST: 398 name = "shst"; 399 break; 400 default: 401 name = "DecodeError2"; 402 break; 403 } 404 strcpy(tbuf, name); 405 break; 406 case 'b': 407 strcpy(tbuf, "0000"); 408 for (i = 3; i >= 0; i--) { 409 tbuf[i] += operand & 1; 410 operand >>= 1; 411 } 412 break; 413 case 'n': 414 operand = ~ExpandImmediate(operand); 415 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand); 416 break; 417 case 'm': 418 operand = ExpandImmediate(operand); 419 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand); 420 break; 421 case 's': 422 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand)); 423 break; 424 case 'S': 425 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand)); 426 break; 427 case 'h': 428 snprintf(tbuf, arraysize(tbuf), "%04x", operand); 429 break; 430 case 'M': 431 case 'd': 432 snprintf(tbuf, arraysize(tbuf), "%d", operand); 433 break; 434 case 'C': 435 operand = RegStorage::RegNum(operand); 436 DCHECK_LT(operand, static_cast<int>( 437 sizeof(core_reg_names)/sizeof(core_reg_names[0]))); 438 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]); 439 break; 440 case 'E': 441 snprintf(tbuf, arraysize(tbuf), "%d", operand*4); 442 break; 443 case 'F': 444 snprintf(tbuf, arraysize(tbuf), "%d", operand*2); 445 break; 446 case 'c': 447 strcpy(tbuf, cc_names[operand]); 448 break; 449 case 't': 450 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)", 451 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1), 452 lir->target); 453 break; 454 case 'u': { 455 int offset_1 = lir->operands[0]; 456 int offset_2 = NEXT_LIR(lir)->operands[0]; 457 uintptr_t target = 458 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & 459 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) & 460 0xfffffffc; 461 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target)); 462 break; 463 } 464 465 /* Nothing to print for BLX_2 */ 466 case 'v': 467 strcpy(tbuf, "see above"); 468 break; 469 case 'R': 470 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf)); 471 break; 472 case 'P': 473 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf)); 474 break; 475 case 'Q': 476 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf)); 477 break; 478 default: 479 strcpy(tbuf, "DecodeError1"); 480 break; 481 } 482 buf += tbuf; 483 } 484 } else { 485 buf += *fmt++; 486 } 487 } 488 return buf; 489 } 490 491 void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) { 492 char buf[256]; 493 buf[0] = 0; 494 495 if (mask.Equals(kEncodeAll)) { 496 strcpy(buf, "all"); 497 } else { 498 char num[8]; 499 int i; 500 501 for (i = 0; i < kArmRegEnd; i++) { 502 if (mask.HasBit(i)) { 503 snprintf(num, arraysize(num), "%d ", i); 504 strcat(buf, num); 505 } 506 } 507 508 if (mask.HasBit(ResourceMask::kCCode)) { 509 strcat(buf, "cc "); 510 } 511 if (mask.HasBit(ResourceMask::kFPStatus)) { 512 strcat(buf, "fpcc "); 513 } 514 515 /* Memory bits */ 516 if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) { 517 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s", 518 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info), 519 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : ""); 520 } 521 if (mask.HasBit(ResourceMask::kLiteral)) { 522 strcat(buf, "lit "); 523 } 524 525 if (mask.HasBit(ResourceMask::kHeapRef)) { 526 strcat(buf, "heap "); 527 } 528 if (mask.HasBit(ResourceMask::kMustNotAlias)) { 529 strcat(buf, "noalias "); 530 } 531 } 532 if (buf[0]) { 533 LOG(INFO) << prefix << ": " << buf; 534 } 535 } 536 537 bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) { 538 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond)); 539 } 540 541 RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) { 542 if (UNLIKELY(is_volatile)) { 543 // On arm, atomic 64-bit load/store requires a core register pair. 544 // Smaller aligned load/store is atomic for both core and fp registers. 545 if (size == k64 || size == kDouble) { 546 return kCoreReg; 547 } 548 } 549 return RegClassBySize(size); 550 } 551 552 ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena) 553 : Mir2Lir(cu, mir_graph, arena) { 554 // Sanity check - make sure encoding map lines up. 555 for (int i = 0; i < kArmLast; i++) { 556 if (ArmMir2Lir::EncodingMap[i].opcode != i) { 557 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name 558 << " is wrong: expecting " << i << ", seeing " 559 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode); 560 } 561 } 562 } 563 564 Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, 565 ArenaAllocator* const arena) { 566 return new ArmMir2Lir(cu, mir_graph, arena); 567 } 568 569 void ArmMir2Lir::CompilerInitializeRegAlloc() { 570 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs, 571 dp_regs, reserved_regs, empty_pool /* reserved64 */, 572 core_temps, empty_pool /* core64_temps */, sp_temps, 573 dp_temps); 574 575 // Target-specific adjustments. 576 577 // Alias single precision floats to appropriate half of overlapping double. 578 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_); 579 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { 580 int sp_reg_num = info->GetReg().GetRegNum(); 581 int dp_reg_num = sp_reg_num >> 1; 582 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num); 583 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg); 584 // Double precision register's master storage should refer to itself. 585 DCHECK_EQ(dp_reg_info, dp_reg_info->Master()); 586 // Redirect single precision's master storage to master. 587 info->SetMaster(dp_reg_info); 588 // Singles should show a single 32-bit mask bit, at first referring to the low half. 589 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask); 590 if (sp_reg_num & 1) { 591 // For odd singles, change to use the high word of the backing double. 592 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask); 593 } 594 } 595 596 #ifdef ARM_R4_SUSPEND_FLAG 597 // TODO: re-enable this when we can safely save r4 over the suspension code path. 598 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks(); 599 if (no_suspend) { 600 GetRegInfo(rs_rARM_SUSPEND)->MarkFree(); 601 } 602 #endif 603 604 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods. 605 // TODO: adjust when we roll to hard float calling convention. 606 reg_pool_->next_core_reg_ = 2; 607 reg_pool_->next_sp_reg_ = 0; 608 reg_pool_->next_dp_reg_ = 0; 609 } 610 611 /* 612 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some 613 * instructions might call out to C/assembly helper functions. Until 614 * machinery is in place, always spill lr. 615 */ 616 617 void ArmMir2Lir::AdjustSpillMask() { 618 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum()); 619 num_core_spills_++; 620 } 621 622 /* 623 * Mark a callee-save fp register as promoted. Note that 624 * vpush/vpop uses contiguous register lists so we must 625 * include any holes in the mask. Associate holes with 626 * Dalvik register INVALID_VREG (0xFFFFU). 627 */ 628 void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) { 629 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE); 630 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE; 631 // Ensure fp_vmap_table is large enough 632 int table_size = fp_vmap_table_.size(); 633 for (int i = table_size; i < (adjusted_reg_num + 1); i++) { 634 fp_vmap_table_.push_back(INVALID_VREG); 635 } 636 // Add the current mapping 637 fp_vmap_table_[adjusted_reg_num] = v_reg; 638 // Size of fp_vmap_table is high-water mark, use to set mask 639 num_fp_spills_ = fp_vmap_table_.size(); 640 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE; 641 } 642 643 void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) { 644 // TEMP: perform as 2 singles. 645 int reg_num = reg.GetRegNum() << 1; 646 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num); 647 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1); 648 MarkPreservedSingle(v_reg, lo); 649 MarkPreservedSingle(v_reg + 1, hi); 650 } 651 652 /* Clobber all regs that might be used by an external C call */ 653 void ArmMir2Lir::ClobberCallerSave() { 654 // TODO: rework this - it's gotten even more ugly. 655 Clobber(rs_r0); 656 Clobber(rs_r1); 657 Clobber(rs_r2); 658 Clobber(rs_r3); 659 Clobber(rs_r12); 660 Clobber(rs_r14lr); 661 Clobber(rs_fr0); 662 Clobber(rs_fr1); 663 Clobber(rs_fr2); 664 Clobber(rs_fr3); 665 Clobber(rs_fr4); 666 Clobber(rs_fr5); 667 Clobber(rs_fr6); 668 Clobber(rs_fr7); 669 Clobber(rs_fr8); 670 Clobber(rs_fr9); 671 Clobber(rs_fr10); 672 Clobber(rs_fr11); 673 Clobber(rs_fr12); 674 Clobber(rs_fr13); 675 Clobber(rs_fr14); 676 Clobber(rs_fr15); 677 Clobber(rs_dr0); 678 Clobber(rs_dr1); 679 Clobber(rs_dr2); 680 Clobber(rs_dr3); 681 Clobber(rs_dr4); 682 Clobber(rs_dr5); 683 Clobber(rs_dr6); 684 Clobber(rs_dr7); 685 } 686 687 RegLocation ArmMir2Lir::GetReturnWideAlt() { 688 RegLocation res = LocCReturnWide(); 689 res.reg.SetLowReg(rs_r2.GetReg()); 690 res.reg.SetHighReg(rs_r3.GetReg()); 691 Clobber(rs_r2); 692 Clobber(rs_r3); 693 MarkInUse(rs_r2); 694 MarkInUse(rs_r3); 695 MarkWide(res.reg); 696 return res; 697 } 698 699 RegLocation ArmMir2Lir::GetReturnAlt() { 700 RegLocation res = LocCReturn(); 701 res.reg.SetReg(rs_r1.GetReg()); 702 Clobber(rs_r1); 703 MarkInUse(rs_r1); 704 return res; 705 } 706 707 /* To be used when explicitly managing register use */ 708 void ArmMir2Lir::LockCallTemps() { 709 LockTemp(rs_r0); 710 LockTemp(rs_r1); 711 LockTemp(rs_r2); 712 LockTemp(rs_r3); 713 } 714 715 /* To be used when explicitly managing register use */ 716 void ArmMir2Lir::FreeCallTemps() { 717 FreeTemp(rs_r0); 718 FreeTemp(rs_r1); 719 FreeTemp(rs_r2); 720 FreeTemp(rs_r3); 721 } 722 723 RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) { 724 LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR); 725 return rs_rARM_LR; 726 } 727 728 LIR* ArmMir2Lir::CheckSuspendUsingLoad() { 729 RegStorage tmp = rs_r0; 730 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp); 731 LIR* load2 = Load32Disp(tmp, 0, tmp); 732 return load2; 733 } 734 735 uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) { 736 DCHECK(!IsPseudoLirOp(opcode)); 737 return ArmMir2Lir::EncodingMap[opcode].flags; 738 } 739 740 const char* ArmMir2Lir::GetTargetInstName(int opcode) { 741 DCHECK(!IsPseudoLirOp(opcode)); 742 return ArmMir2Lir::EncodingMap[opcode].name; 743 } 744 745 const char* ArmMir2Lir::GetTargetInstFmt(int opcode) { 746 DCHECK(!IsPseudoLirOp(opcode)); 747 return ArmMir2Lir::EncodingMap[opcode].fmt; 748 } 749 750 /* 751 * Somewhat messy code here. We want to allocate a pair of contiguous 752 * physical single-precision floating point registers starting with 753 * an even numbered reg. It is possible that the paired s_reg (s_reg+1) 754 * has already been allocated - try to fit if possible. Fail to 755 * allocate if we can't meet the requirements for the pair of 756 * s_reg<=sX[even] & (s_reg+1)<= sX+1. 757 */ 758 // TODO: needs rewrite to support non-backed 64-bit float regs. 759 RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) { 760 RegStorage res; 761 int v_reg = mir_graph_->SRegToVReg(s_reg); 762 int p_map_idx = SRegToPMap(s_reg); 763 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) { 764 // Upper reg is already allocated. Can we fit? 765 int high_reg = promotion_map_[p_map_idx+1].fp_reg; 766 if ((high_reg & 1) == 0) { 767 // High reg is even - fail. 768 return res; // Invalid. 769 } 770 // Is the low reg of the pair free? 771 // FIXME: rework. 772 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1)); 773 if (p->InUse() || p->IsTemp()) { 774 // Already allocated or not preserved - fail. 775 return res; // Invalid. 776 } 777 // OK - good to go. 778 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1); 779 p->MarkInUse(); 780 MarkPreservedSingle(v_reg, p->GetReg()); 781 } else { 782 /* 783 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to 784 * different underlying physical registers. 785 */ 786 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->dp_regs_); 787 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { 788 if (!info->IsTemp() && !info->InUse()) { 789 res = info->GetReg(); 790 info->MarkInUse(); 791 MarkPreservedDouble(v_reg, info->GetReg()); 792 break; 793 } 794 } 795 } 796 if (res.Valid()) { 797 RegisterInfo* info = GetRegInfo(res); 798 promotion_map_[p_map_idx].fp_location = kLocPhysReg; 799 promotion_map_[p_map_idx].fp_reg = 800 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg(); 801 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg; 802 promotion_map_[p_map_idx+1].fp_reg = 803 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg(); 804 } 805 return res; 806 } 807 808 // Reserve a callee-save sp single register. 809 RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) { 810 RegStorage res; 811 GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_); 812 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) { 813 if (!info->IsTemp() && !info->InUse()) { 814 res = info->GetReg(); 815 int p_map_idx = SRegToPMap(s_reg); 816 int v_reg = mir_graph_->SRegToVReg(s_reg); 817 GetRegInfo(res)->MarkInUse(); 818 MarkPreservedSingle(v_reg, res); 819 promotion_map_[p_map_idx].fp_location = kLocPhysReg; 820 promotion_map_[p_map_idx].fp_reg = res.GetReg(); 821 break; 822 } 823 } 824 return res; 825 } 826 827 } // namespace art 828