target_arm.cc revision 8325296769a77ecf3ab647b5ab516f439f5b3206
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 26namespace art { 27 28static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10, 29 r11, r12, rARM_SP, rARM_LR, rARM_PC}; 30static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC}; 31static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, 32 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15, 33 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23, 34 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31}; 35static int core_temps[] = {r0, r1, r2, r3, r12}; 36static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, 37 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15}; 38 39RegLocation ArmMir2Lir::LocCReturn() { 40 return arm_loc_c_return; 41} 42 43RegLocation ArmMir2Lir::LocCReturnWide() { 44 return arm_loc_c_return_wide; 45} 46 47RegLocation ArmMir2Lir::LocCReturnFloat() { 48 return arm_loc_c_return_float; 49} 50 51RegLocation ArmMir2Lir::LocCReturnDouble() { 52 return arm_loc_c_return_double; 53} 54 55// Return a target-dependent special register. 56RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) { 57 int res_reg = RegStorage::kInvalidRegVal; 58 switch (reg) { 59 case kSelf: res_reg = rARM_SELF; break; 60 case kSuspend: res_reg = rARM_SUSPEND; break; 61 case kLr: res_reg = rARM_LR; break; 62 case kPc: res_reg = rARM_PC; break; 63 case kSp: res_reg = rARM_SP; break; 64 case kArg0: res_reg = rARM_ARG0; break; 65 case kArg1: res_reg = rARM_ARG1; break; 66 case kArg2: res_reg = rARM_ARG2; break; 67 case kArg3: res_reg = rARM_ARG3; break; 68 case kFArg0: res_reg = rARM_FARG0; break; 69 case kFArg1: res_reg = rARM_FARG1; break; 70 case kFArg2: res_reg = rARM_FARG2; break; 71 case kFArg3: res_reg = rARM_FARG3; break; 72 case kRet0: res_reg = rARM_RET0; break; 73 case kRet1: res_reg = rARM_RET1; break; 74 case kInvokeTgt: res_reg = rARM_INVOKE_TGT; break; 75 case kHiddenArg: res_reg = r12; break; 76 case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break; 77 case kCount: res_reg = rARM_COUNT; break; 78 } 79 return RegStorage::Solo32(res_reg); 80} 81 82RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) { 83 // For the 32-bit internal ABI, the first 3 arguments are passed in registers. 84 switch (arg_num) { 85 case 0: 86 return rs_rARM_ARG1; 87 case 1: 88 return rs_rARM_ARG2; 89 case 2: 90 return rs_rARM_ARG3; 91 default: 92 return RegStorage::InvalidReg(); 93 } 94} 95 96// Create a double from a pair of singles. 97int ArmMir2Lir::S2d(int low_reg, int high_reg) { 98 return ARM_S2D(low_reg, high_reg); 99} 100 101// Return mask to strip off fp reg flags and bias. 102uint32_t ArmMir2Lir::FpRegMask() { 103 return ARM_FP_REG_MASK; 104} 105 106// True if both regs single, both core or both double. 107bool ArmMir2Lir::SameRegType(int reg1, int reg2) { 108 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2)); 109} 110 111/* 112 * Decode the register id. 113 */ 114uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) { 115 uint64_t seed; 116 int shift; 117 int reg_id; 118 119 120 reg_id = reg & 0x1f; 121 /* Each double register is equal to a pair of single-precision FP registers */ 122 seed = ARM_DOUBLEREG(reg) ? 3 : 1; 123 /* FP register starts at bit position 16 */ 124 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0; 125 /* Expand the double register id into single offset */ 126 shift += reg_id; 127 return (seed << shift); 128} 129 130uint64_t ArmMir2Lir::GetPCUseDefEncoding() { 131 return ENCODE_ARM_REG_PC; 132} 133 134// Thumb2 specific setup. TODO: inline?: 135void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { 136 DCHECK_EQ(cu_->instruction_set, kThumb2); 137 DCHECK(!lir->flags.use_def_invalid); 138 139 int opcode = lir->opcode; 140 141 // These flags are somewhat uncommon - bypass if we can. 142 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 | 143 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 | 144 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) { 145 if (flags & REG_DEF_SP) { 146 lir->u.m.def_mask |= ENCODE_ARM_REG_SP; 147 } 148 149 if (flags & REG_USE_SP) { 150 lir->u.m.use_mask |= ENCODE_ARM_REG_SP; 151 } 152 153 if (flags & REG_DEF_LIST0) { 154 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); 155 } 156 157 if (flags & REG_DEF_LIST1) { 158 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); 159 } 160 161 if (flags & REG_DEF_FPCS_LIST0) { 162 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); 163 } 164 165 if (flags & REG_DEF_FPCS_LIST2) { 166 for (int i = 0; i < lir->operands[2]; i++) { 167 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i); 168 } 169 } 170 171 if (flags & REG_USE_PC) { 172 lir->u.m.use_mask |= ENCODE_ARM_REG_PC; 173 } 174 175 /* Conservatively treat the IT block */ 176 if (flags & IS_IT) { 177 lir->u.m.def_mask = ENCODE_ALL; 178 } 179 180 if (flags & REG_USE_LIST0) { 181 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); 182 } 183 184 if (flags & REG_USE_LIST1) { 185 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); 186 } 187 188 if (flags & REG_USE_FPCS_LIST0) { 189 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); 190 } 191 192 if (flags & REG_USE_FPCS_LIST2) { 193 for (int i = 0; i < lir->operands[2]; i++) { 194 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i); 195 } 196 } 197 /* Fixup for kThumbPush/lr and kThumbPop/pc */ 198 if (opcode == kThumbPush || opcode == kThumbPop) { 199 uint64_t r8Mask = GetRegMaskCommon(r8); 200 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) { 201 lir->u.m.use_mask &= ~r8Mask; 202 lir->u.m.use_mask |= ENCODE_ARM_REG_LR; 203 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) { 204 lir->u.m.def_mask &= ~r8Mask; 205 lir->u.m.def_mask |= ENCODE_ARM_REG_PC; 206 } 207 } 208 if (flags & REG_DEF_LR) { 209 lir->u.m.def_mask |= ENCODE_ARM_REG_LR; 210 } 211 } 212} 213 214ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) { 215 ArmConditionCode res; 216 switch (ccode) { 217 case kCondEq: res = kArmCondEq; break; 218 case kCondNe: res = kArmCondNe; break; 219 case kCondCs: res = kArmCondCs; break; 220 case kCondCc: res = kArmCondCc; break; 221 case kCondUlt: res = kArmCondCc; break; 222 case kCondUge: res = kArmCondCs; break; 223 case kCondMi: res = kArmCondMi; break; 224 case kCondPl: res = kArmCondPl; break; 225 case kCondVs: res = kArmCondVs; break; 226 case kCondVc: res = kArmCondVc; break; 227 case kCondHi: res = kArmCondHi; break; 228 case kCondLs: res = kArmCondLs; break; 229 case kCondGe: res = kArmCondGe; break; 230 case kCondLt: res = kArmCondLt; break; 231 case kCondGt: res = kArmCondGt; break; 232 case kCondLe: res = kArmCondLe; break; 233 case kCondAl: res = kArmCondAl; break; 234 case kCondNv: res = kArmCondNv; break; 235 default: 236 LOG(FATAL) << "Bad condition code " << ccode; 237 res = static_cast<ArmConditionCode>(0); // Quiet gcc 238 } 239 return res; 240} 241 242static const char* core_reg_names[16] = { 243 "r0", 244 "r1", 245 "r2", 246 "r3", 247 "r4", 248 "r5", 249 "r6", 250 "r7", 251 "r8", 252 "rSELF", 253 "r10", 254 "r11", 255 "r12", 256 "sp", 257 "lr", 258 "pc", 259}; 260 261 262static const char* shift_names[4] = { 263 "lsl", 264 "lsr", 265 "asr", 266 "ror"}; 267 268/* Decode and print a ARM register name */ 269static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) { 270 int i; 271 bool printed = false; 272 buf[0] = 0; 273 for (i = 0; i < 16; i++, vector >>= 1) { 274 if (vector & 0x1) { 275 int reg_id = i; 276 if (opcode == kThumbPush && i == 8) { 277 reg_id = r14lr; 278 } else if (opcode == kThumbPop && i == 8) { 279 reg_id = r15pc; 280 } 281 if (printed) { 282 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id); 283 } else { 284 printed = true; 285 snprintf(buf, buf_size, "r%d", reg_id); 286 } 287 } 288 } 289 return buf; 290} 291 292static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) { 293 snprintf(buf, buf_size, "s%d", base); 294 for (int i = 1; i < count; i++) { 295 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i); 296 } 297 return buf; 298} 299 300static int32_t ExpandImmediate(int value) { 301 int32_t mode = (value & 0xf00) >> 8; 302 uint32_t bits = value & 0xff; 303 switch (mode) { 304 case 0: 305 return bits; 306 case 1: 307 return (bits << 16) | bits; 308 case 2: 309 return (bits << 24) | (bits << 8); 310 case 3: 311 return (bits << 24) | (bits << 16) | (bits << 8) | bits; 312 default: 313 break; 314 } 315 bits = (bits | 0x80) << 24; 316 return bits >> (((value & 0xf80) >> 7) - 8); 317} 318 319const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 320 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"}; 321/* 322 * Interpret a format string and build a string no longer than size 323 * See format key in Assemble.c. 324 */ 325std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) { 326 std::string buf; 327 int i; 328 const char* fmt_end = &fmt[strlen(fmt)]; 329 char tbuf[256]; 330 const char* name; 331 char nc; 332 while (fmt < fmt_end) { 333 int operand; 334 if (*fmt == '!') { 335 fmt++; 336 DCHECK_LT(fmt, fmt_end); 337 nc = *fmt++; 338 if (nc == '!') { 339 strcpy(tbuf, "!"); 340 } else { 341 DCHECK_LT(fmt, fmt_end); 342 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U); 343 operand = lir->operands[nc-'0']; 344 switch (*fmt++) { 345 case 'H': 346 if (operand != 0) { 347 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2); 348 } else { 349 strcpy(tbuf, ""); 350 } 351 break; 352 case 'B': 353 switch (operand) { 354 case kSY: 355 name = "sy"; 356 break; 357 case kST: 358 name = "st"; 359 break; 360 case kISH: 361 name = "ish"; 362 break; 363 case kISHST: 364 name = "ishst"; 365 break; 366 case kNSH: 367 name = "nsh"; 368 break; 369 case kNSHST: 370 name = "shst"; 371 break; 372 default: 373 name = "DecodeError2"; 374 break; 375 } 376 strcpy(tbuf, name); 377 break; 378 case 'b': 379 strcpy(tbuf, "0000"); 380 for (i = 3; i >= 0; i--) { 381 tbuf[i] += operand & 1; 382 operand >>= 1; 383 } 384 break; 385 case 'n': 386 operand = ~ExpandImmediate(operand); 387 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand); 388 break; 389 case 'm': 390 operand = ExpandImmediate(operand); 391 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand); 392 break; 393 case 's': 394 snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK); 395 break; 396 case 'S': 397 snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1); 398 break; 399 case 'h': 400 snprintf(tbuf, arraysize(tbuf), "%04x", operand); 401 break; 402 case 'M': 403 case 'd': 404 snprintf(tbuf, arraysize(tbuf), "%d", operand); 405 break; 406 case 'C': 407 DCHECK_LT(operand, static_cast<int>( 408 sizeof(core_reg_names)/sizeof(core_reg_names[0]))); 409 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]); 410 break; 411 case 'E': 412 snprintf(tbuf, arraysize(tbuf), "%d", operand*4); 413 break; 414 case 'F': 415 snprintf(tbuf, arraysize(tbuf), "%d", operand*2); 416 break; 417 case 'c': 418 strcpy(tbuf, cc_names[operand]); 419 break; 420 case 't': 421 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)", 422 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1), 423 lir->target); 424 break; 425 case 'u': { 426 int offset_1 = lir->operands[0]; 427 int offset_2 = NEXT_LIR(lir)->operands[0]; 428 uintptr_t target = 429 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & 430 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) & 431 0xfffffffc; 432 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target)); 433 break; 434 } 435 436 /* Nothing to print for BLX_2 */ 437 case 'v': 438 strcpy(tbuf, "see above"); 439 break; 440 case 'R': 441 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf)); 442 break; 443 case 'P': 444 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf)); 445 break; 446 case 'Q': 447 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf)); 448 break; 449 default: 450 strcpy(tbuf, "DecodeError1"); 451 break; 452 } 453 buf += tbuf; 454 } 455 } else { 456 buf += *fmt++; 457 } 458 } 459 return buf; 460} 461 462void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) { 463 char buf[256]; 464 buf[0] = 0; 465 466 if (mask == ENCODE_ALL) { 467 strcpy(buf, "all"); 468 } else { 469 char num[8]; 470 int i; 471 472 for (i = 0; i < kArmRegEnd; i++) { 473 if (mask & (1ULL << i)) { 474 snprintf(num, arraysize(num), "%d ", i); 475 strcat(buf, num); 476 } 477 } 478 479 if (mask & ENCODE_CCODE) { 480 strcat(buf, "cc "); 481 } 482 if (mask & ENCODE_FP_STATUS) { 483 strcat(buf, "fpcc "); 484 } 485 486 /* Memory bits */ 487 if (arm_lir && (mask & ENCODE_DALVIK_REG)) { 488 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s", 489 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info), 490 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : ""); 491 } 492 if (mask & ENCODE_LITERAL) { 493 strcat(buf, "lit "); 494 } 495 496 if (mask & ENCODE_HEAP_REF) { 497 strcat(buf, "heap "); 498 } 499 if (mask & ENCODE_MUST_NOT_ALIAS) { 500 strcat(buf, "noalias "); 501 } 502 } 503 if (buf[0]) { 504 LOG(INFO) << prefix << ": " << buf; 505 } 506} 507 508bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) { 509 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond)); 510} 511 512ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena) 513 : Mir2Lir(cu, mir_graph, arena) { 514 // Sanity check - make sure encoding map lines up. 515 for (int i = 0; i < kArmLast; i++) { 516 if (ArmMir2Lir::EncodingMap[i].opcode != i) { 517 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name 518 << " is wrong: expecting " << i << ", seeing " 519 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode); 520 } 521 } 522} 523 524Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, 525 ArenaAllocator* const arena) { 526 return new ArmMir2Lir(cu, mir_graph, arena); 527} 528 529// Alloc a pair of core registers, or a double. 530RegStorage ArmMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) { 531 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { 532 return AllocTempDouble(); 533 } else { 534 RegStorage low_reg = AllocTemp(); 535 RegStorage high_reg = AllocTemp(); 536 return RegStorage::MakeRegPair(low_reg, high_reg); 537 } 538} 539 540RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) { 541 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) 542 return AllocTempFloat(); 543 return AllocTemp(); 544} 545 546void ArmMir2Lir::CompilerInitializeRegAlloc() { 547 int num_regs = sizeof(core_regs)/sizeof(*core_regs); 548 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs); 549 int num_temps = sizeof(core_temps)/sizeof(*core_temps); 550 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs); 551 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps); 552 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_), 553 kArenaAllocRegAlloc)); 554 reg_pool_->num_core_regs = num_regs; 555 reg_pool_->core_regs = reinterpret_cast<RegisterInfo*> 556 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc)); 557 reg_pool_->num_fp_regs = num_fp_regs; 558 reg_pool_->FPRegs = static_cast<RegisterInfo*> 559 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc)); 560 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs); 561 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs); 562 563 // Keep special registers from being allocated 564 // Don't reserve the r4 if we are doing implicit suspend checks. 565 // TODO: re-enable this when we can safely save r4 over the suspension code path. 566 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks(); 567 for (int i = 0; i < num_reserved; i++) { 568 if (no_suspend && (ReservedRegs[i] == rARM_SUSPEND)) { 569 // Don't reserve the suspend register. 570 continue; 571 } 572 MarkInUse(ReservedRegs[i]); 573 } 574 // Mark temp regs - all others not in use can be used for promotion 575 for (int i = 0; i < num_temps; i++) { 576 MarkTemp(core_temps[i]); 577 } 578 for (int i = 0; i < num_fp_temps; i++) { 579 MarkTemp(fp_temps[i]); 580 } 581 582 // Start allocation at r2 in an attempt to avoid clobbering return values 583 reg_pool_->next_core_reg = r2; 584} 585 586void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) { 587 DCHECK(rl_keep.wide); 588 DCHECK(rl_free.wide); 589 if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) && 590 (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) && 591 (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) && 592 (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) { 593 // No overlap, free. 594 FreeTemp(rl_free.reg); 595 } 596} 597 598/* 599 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some 600 * instructions might call out to C/assembly helper functions. Until 601 * machinery is in place, always spill lr. 602 */ 603 604void ArmMir2Lir::AdjustSpillMask() { 605 core_spill_mask_ |= (1 << rARM_LR); 606 num_core_spills_++; 607} 608 609/* 610 * Mark a callee-save fp register as promoted. Note that 611 * vpush/vpop uses contiguous register lists so we must 612 * include any holes in the mask. Associate holes with 613 * Dalvik register INVALID_VREG (0xFFFFU). 614 */ 615void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) { 616 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE); 617 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE; 618 // Ensure fp_vmap_table is large enough 619 int table_size = fp_vmap_table_.size(); 620 for (int i = table_size; i < (reg + 1); i++) { 621 fp_vmap_table_.push_back(INVALID_VREG); 622 } 623 // Add the current mapping 624 fp_vmap_table_[reg] = v_reg; 625 // Size of fp_vmap_table is high-water mark, use to set mask 626 num_fp_spills_ = fp_vmap_table_.size(); 627 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE; 628} 629 630void ArmMir2Lir::FlushRegWide(RegStorage reg) { 631 RegisterInfo* info1 = GetRegInfo(reg.GetLowReg()); 632 RegisterInfo* info2 = GetRegInfo(reg.GetHighReg()); 633 DCHECK(info1 && info2 && info1->pair && info2->pair && 634 (info1->partner == info2->reg) && 635 (info2->partner == info1->reg)); 636 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) { 637 if (!(info1->is_temp && info2->is_temp)) { 638 /* Should not happen. If it does, there's a problem in eval_loc */ 639 LOG(FATAL) << "Long half-temp, half-promoted"; 640 } 641 642 info1->dirty = false; 643 info2->dirty = false; 644 if (mir_graph_->SRegToVReg(info2->s_reg) < 645 mir_graph_->SRegToVReg(info1->s_reg)) 646 info1 = info2; 647 int v_reg = mir_graph_->SRegToVReg(info1->s_reg); 648 StoreBaseDispWide(rs_rARM_SP, VRegOffset(v_reg), 649 RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner)); 650 } 651} 652 653void ArmMir2Lir::FlushReg(RegStorage reg) { 654 DCHECK(!reg.IsPair()); 655 RegisterInfo* info = GetRegInfo(reg.GetReg()); 656 if (info->live && info->dirty) { 657 info->dirty = false; 658 int v_reg = mir_graph_->SRegToVReg(info->s_reg); 659 StoreBaseDisp(rs_rARM_SP, VRegOffset(v_reg), reg, kWord); 660 } 661} 662 663/* Give access to the target-dependent FP register encoding to common code */ 664bool ArmMir2Lir::IsFpReg(int reg) { 665 return ARM_FPREG(reg); 666} 667 668bool ArmMir2Lir::IsFpReg(RegStorage reg) { 669 return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg()); 670} 671 672/* Clobber all regs that might be used by an external C call */ 673void ArmMir2Lir::ClobberCallerSave() { 674 Clobber(r0); 675 Clobber(r1); 676 Clobber(r2); 677 Clobber(r3); 678 Clobber(r12); 679 Clobber(r14lr); 680 Clobber(fr0); 681 Clobber(fr1); 682 Clobber(fr2); 683 Clobber(fr3); 684 Clobber(fr4); 685 Clobber(fr5); 686 Clobber(fr6); 687 Clobber(fr7); 688 Clobber(fr8); 689 Clobber(fr9); 690 Clobber(fr10); 691 Clobber(fr11); 692 Clobber(fr12); 693 Clobber(fr13); 694 Clobber(fr14); 695 Clobber(fr15); 696} 697 698RegLocation ArmMir2Lir::GetReturnWideAlt() { 699 RegLocation res = LocCReturnWide(); 700 res.reg.SetReg(r2); 701 res.reg.SetHighReg(r3); 702 Clobber(r2); 703 Clobber(r3); 704 MarkInUse(r2); 705 MarkInUse(r3); 706 MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg()); 707 return res; 708} 709 710RegLocation ArmMir2Lir::GetReturnAlt() { 711 RegLocation res = LocCReturn(); 712 res.reg.SetReg(r1); 713 Clobber(r1); 714 MarkInUse(r1); 715 return res; 716} 717 718/* To be used when explicitly managing register use */ 719void ArmMir2Lir::LockCallTemps() { 720 LockTemp(r0); 721 LockTemp(r1); 722 LockTemp(r2); 723 LockTemp(r3); 724} 725 726/* To be used when explicitly managing register use */ 727void ArmMir2Lir::FreeCallTemps() { 728 FreeTemp(r0); 729 FreeTemp(r1); 730 FreeTemp(r2); 731 FreeTemp(r3); 732} 733 734RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) { 735 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR); 736 return rs_rARM_LR; 737} 738 739LIR* ArmMir2Lir::CheckSuspendUsingLoad() { 740 RegStorage tmp = rs_r0; 741 LoadWordDisp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp); 742 LIR* load2 = LoadWordDisp(tmp, 0, tmp); 743 return load2; 744} 745 746uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) { 747 DCHECK(!IsPseudoLirOp(opcode)); 748 return ArmMir2Lir::EncodingMap[opcode].flags; 749} 750 751const char* ArmMir2Lir::GetTargetInstName(int opcode) { 752 DCHECK(!IsPseudoLirOp(opcode)); 753 return ArmMir2Lir::EncodingMap[opcode].name; 754} 755 756const char* ArmMir2Lir::GetTargetInstFmt(int opcode) { 757 DCHECK(!IsPseudoLirOp(opcode)); 758 return ArmMir2Lir::EncodingMap[opcode].fmt; 759} 760 761} // namespace art 762