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 /* This file contains register alloction support. */ 18 19 #include "mir_to_lir-inl.h" 20 21 #include "dex/compiler_ir.h" 22 #include "dex/dataflow_iterator-inl.h" 23 #include "dex/mir_graph.h" 24 #include "driver/compiler_driver.h" 25 #include "driver/dex_compilation_unit.h" 26 #include "utils/dex_cache_arrays_layout-inl.h" 27 28 namespace art { 29 30 /* 31 * Free all allocated temps in the temp pools. Note that this does 32 * not affect the "liveness" of a temp register, which will stay 33 * live until it is either explicitly killed or reallocated. 34 */ 35 void Mir2Lir::ResetRegPool() { 36 for (RegisterInfo* info : tempreg_info_) { 37 info->MarkFree(); 38 } 39 // Reset temp tracking sanity check. 40 if (kIsDebugBuild) { 41 live_sreg_ = INVALID_SREG; 42 } 43 } 44 45 Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, const ResourceMask& mask) 46 : reg_(r), is_temp_(false), wide_value_(false), dirty_(false), aliased_(false), partner_(r), 47 s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this), def_start_(nullptr), 48 def_end_(nullptr), alias_chain_(nullptr) { 49 switch (r.StorageSize()) { 50 case 0: storage_mask_ = 0xffffffff; break; 51 case 4: storage_mask_ = 0x00000001; break; 52 case 8: storage_mask_ = 0x00000003; break; 53 case 16: storage_mask_ = 0x0000000f; break; 54 case 32: storage_mask_ = 0x000000ff; break; 55 case 64: storage_mask_ = 0x0000ffff; break; 56 case 128: storage_mask_ = 0xffffffff; break; 57 } 58 used_storage_ = r.Valid() ? ~storage_mask_ : storage_mask_; 59 liveness_ = used_storage_; 60 } 61 62 Mir2Lir::RegisterPool::RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena, 63 const ArrayRef<const RegStorage>& core_regs, 64 const ArrayRef<const RegStorage>& core64_regs, 65 const ArrayRef<const RegStorage>& sp_regs, 66 const ArrayRef<const RegStorage>& dp_regs, 67 const ArrayRef<const RegStorage>& reserved_regs, 68 const ArrayRef<const RegStorage>& reserved64_regs, 69 const ArrayRef<const RegStorage>& core_temps, 70 const ArrayRef<const RegStorage>& core64_temps, 71 const ArrayRef<const RegStorage>& sp_temps, 72 const ArrayRef<const RegStorage>& dp_temps) : 73 core_regs_(arena->Adapter()), next_core_reg_(0), 74 core64_regs_(arena->Adapter()), next_core64_reg_(0), 75 sp_regs_(arena->Adapter()), next_sp_reg_(0), 76 dp_regs_(arena->Adapter()), next_dp_reg_(0), m2l_(m2l) { 77 // Initialize the fast lookup map. 78 m2l_->reginfo_map_.clear(); 79 m2l_->reginfo_map_.resize(RegStorage::kMaxRegs, nullptr); 80 81 // Construct the register pool. 82 core_regs_.reserve(core_regs.size()); 83 for (const RegStorage& reg : core_regs) { 84 RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg)); 85 m2l_->reginfo_map_[reg.GetReg()] = info; 86 core_regs_.push_back(info); 87 } 88 core64_regs_.reserve(core64_regs.size()); 89 for (const RegStorage& reg : core64_regs) { 90 RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg)); 91 m2l_->reginfo_map_[reg.GetReg()] = info; 92 core64_regs_.push_back(info); 93 } 94 sp_regs_.reserve(sp_regs.size()); 95 for (const RegStorage& reg : sp_regs) { 96 RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg)); 97 m2l_->reginfo_map_[reg.GetReg()] = info; 98 sp_regs_.push_back(info); 99 } 100 dp_regs_.reserve(dp_regs.size()); 101 for (const RegStorage& reg : dp_regs) { 102 RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg)); 103 m2l_->reginfo_map_[reg.GetReg()] = info; 104 dp_regs_.push_back(info); 105 } 106 107 // Keep special registers from being allocated. 108 for (RegStorage reg : reserved_regs) { 109 m2l_->MarkInUse(reg); 110 } 111 for (RegStorage reg : reserved64_regs) { 112 m2l_->MarkInUse(reg); 113 } 114 115 // Mark temp regs - all others not in use can be used for promotion 116 for (RegStorage reg : core_temps) { 117 m2l_->MarkTemp(reg); 118 } 119 for (RegStorage reg : core64_temps) { 120 m2l_->MarkTemp(reg); 121 } 122 for (RegStorage reg : sp_temps) { 123 m2l_->MarkTemp(reg); 124 } 125 for (RegStorage reg : dp_temps) { 126 m2l_->MarkTemp(reg); 127 } 128 129 // Add an entry for InvalidReg with zero'd mask. 130 RegisterInfo* invalid_reg = new (arena) RegisterInfo(RegStorage::InvalidReg(), kEncodeNone); 131 m2l_->reginfo_map_[RegStorage::InvalidReg().GetReg()] = invalid_reg; 132 133 // Existence of core64 registers implies wide references. 134 if (core64_regs_.size() != 0) { 135 ref_regs_ = &core64_regs_; 136 next_ref_reg_ = &next_core64_reg_; 137 } else { 138 ref_regs_ = &core_regs_; 139 next_ref_reg_ = &next_core_reg_; 140 } 141 } 142 143 void Mir2Lir::DumpRegPool(ArenaVector<RegisterInfo*>* regs) { 144 LOG(INFO) << "================================================"; 145 for (RegisterInfo* info : *regs) { 146 LOG(INFO) << StringPrintf( 147 "R[%d:%d:%c]: T:%d, U:%d, W:%d, p:%d, LV:%d, D:%d, SR:%d, DEF:%d", 148 info->GetReg().GetReg(), info->GetReg().GetRegNum(), info->GetReg().IsFloat() ? 'f' : 'c', 149 info->IsTemp(), info->InUse(), info->IsWide(), info->Partner().GetReg(), info->IsLive(), 150 info->IsDirty(), info->SReg(), info->DefStart() != nullptr); 151 } 152 LOG(INFO) << "================================================"; 153 } 154 155 void Mir2Lir::DumpCoreRegPool() { 156 DumpRegPool(®_pool_->core_regs_); 157 DumpRegPool(®_pool_->core64_regs_); 158 } 159 160 void Mir2Lir::DumpFpRegPool() { 161 DumpRegPool(®_pool_->sp_regs_); 162 DumpRegPool(®_pool_->dp_regs_); 163 } 164 165 void Mir2Lir::DumpRegPools() { 166 LOG(INFO) << "Core registers"; 167 DumpCoreRegPool(); 168 LOG(INFO) << "FP registers"; 169 DumpFpRegPool(); 170 } 171 172 void Mir2Lir::Clobber(RegStorage reg) { 173 if (UNLIKELY(reg.IsPair())) { 174 DCHECK(!GetRegInfo(reg.GetLow())->IsAliased()); 175 Clobber(reg.GetLow()); 176 DCHECK(!GetRegInfo(reg.GetHigh())->IsAliased()); 177 Clobber(reg.GetHigh()); 178 } else { 179 RegisterInfo* info = GetRegInfo(reg); 180 if (info->IsTemp() && !info->IsDead()) { 181 if (info->GetReg().NotExactlyEquals(info->Partner())) { 182 ClobberBody(GetRegInfo(info->Partner())); 183 } 184 ClobberBody(info); 185 if (info->IsAliased()) { 186 ClobberAliases(info, info->StorageMask()); 187 } else { 188 RegisterInfo* master = info->Master(); 189 if (info != master) { 190 ClobberBody(info->Master()); 191 ClobberAliases(info->Master(), info->StorageMask()); 192 } 193 } 194 } 195 } 196 } 197 198 void Mir2Lir::ClobberAliases(RegisterInfo* info, uint32_t clobber_mask) { 199 for (RegisterInfo* alias = info->GetAliasChain(); alias != nullptr; 200 alias = alias->GetAliasChain()) { 201 DCHECK(!alias->IsAliased()); // Only the master should be marked as alised. 202 // Only clobber if we have overlap. 203 if ((alias->StorageMask() & clobber_mask) != 0) { 204 ClobberBody(alias); 205 } 206 } 207 } 208 209 /* 210 * Break the association between a Dalvik vreg and a physical temp register of either register 211 * class. 212 * TODO: Ideally, the public version of this code should not exist. Besides its local usage 213 * in the register utilities, is is also used by code gen routines to work around a deficiency in 214 * local register allocation, which fails to distinguish between the "in" and "out" identities 215 * of Dalvik vregs. This can result in useless register copies when the same Dalvik vreg 216 * is used both as the source and destination register of an operation in which the type 217 * changes (for example: INT_TO_FLOAT v1, v1). Revisit when improved register allocation is 218 * addressed. 219 */ 220 void Mir2Lir::ClobberSReg(int s_reg) { 221 if (s_reg != INVALID_SREG) { 222 if (kIsDebugBuild && s_reg == live_sreg_) { 223 live_sreg_ = INVALID_SREG; 224 } 225 for (RegisterInfo* info : tempreg_info_) { 226 if (info->SReg() == s_reg) { 227 if (info->GetReg().NotExactlyEquals(info->Partner())) { 228 // Dealing with a pair - clobber the other half. 229 DCHECK(!info->IsAliased()); 230 ClobberBody(GetRegInfo(info->Partner())); 231 } 232 ClobberBody(info); 233 if (info->IsAliased()) { 234 ClobberAliases(info, info->StorageMask()); 235 } 236 } 237 } 238 } 239 } 240 241 /* 242 * SSA names associated with the initial definitions of Dalvik 243 * registers are the same as the Dalvik register number (and 244 * thus take the same position in the promotion_map. However, 245 * the special Method* and compiler temp resisters use negative 246 * v_reg numbers to distinguish them and can have an arbitrary 247 * ssa name (above the last original Dalvik register). This function 248 * maps SSA names to positions in the promotion_map array. 249 */ 250 int Mir2Lir::SRegToPMap(int s_reg) { 251 DCHECK_LT(s_reg, mir_graph_->GetNumSSARegs()); 252 DCHECK_GE(s_reg, 0); 253 int v_reg = mir_graph_->SRegToVReg(s_reg); 254 return v_reg; 255 } 256 257 // TODO: refactor following Alloc/Record routines - much commonality. 258 void Mir2Lir::RecordCorePromotion(RegStorage reg, int s_reg) { 259 int p_map_idx = SRegToPMap(s_reg); 260 int v_reg = mir_graph_->SRegToVReg(s_reg); 261 int reg_num = reg.GetRegNum(); 262 GetRegInfo(reg)->MarkInUse(); 263 core_spill_mask_ |= (1 << reg_num); 264 // Include reg for later sort 265 core_vmap_table_.push_back(reg_num << VREG_NUM_WIDTH | (v_reg & ((1 << VREG_NUM_WIDTH) - 1))); 266 num_core_spills_++; 267 promotion_map_[p_map_idx].core_location = kLocPhysReg; 268 promotion_map_[p_map_idx].core_reg = reg_num; 269 } 270 271 /* Reserve a callee-save register. Return InvalidReg if none available */ 272 RegStorage Mir2Lir::AllocPreservedCoreReg(int s_reg) { 273 RegStorage res; 274 /* 275 * Note: it really doesn't matter much whether we allocate from the core or core64 276 * pool for 64-bit targets - but for some targets it does matter whether allocations 277 * happens from the single or double pool. This entire section of code could stand 278 * a good refactoring. 279 */ 280 for (RegisterInfo* info : reg_pool_->core_regs_) { 281 if (!info->IsTemp() && !info->InUse()) { 282 res = info->GetReg(); 283 RecordCorePromotion(res, s_reg); 284 break; 285 } 286 } 287 return res; 288 } 289 290 void Mir2Lir::RecordFpPromotion(RegStorage reg, int s_reg) { 291 DCHECK_NE(cu_->instruction_set, kThumb2); 292 int p_map_idx = SRegToPMap(s_reg); 293 int v_reg = mir_graph_->SRegToVReg(s_reg); 294 int reg_num = reg.GetRegNum(); 295 GetRegInfo(reg)->MarkInUse(); 296 fp_spill_mask_ |= (1 << reg_num); 297 // Include reg for later sort 298 fp_vmap_table_.push_back(reg_num << VREG_NUM_WIDTH | (v_reg & ((1 << VREG_NUM_WIDTH) - 1))); 299 num_fp_spills_++; 300 promotion_map_[p_map_idx].fp_location = kLocPhysReg; 301 promotion_map_[p_map_idx].fp_reg = reg.GetReg(); 302 } 303 304 // Reserve a callee-save floating point. 305 RegStorage Mir2Lir::AllocPreservedFpReg(int s_reg) { 306 /* 307 * For targets other than Thumb2, it doesn't matter whether we allocate from 308 * the sp_regs_ or dp_regs_ pool. Some refactoring is in order here. 309 */ 310 DCHECK_NE(cu_->instruction_set, kThumb2); 311 RegStorage res; 312 for (RegisterInfo* info : reg_pool_->sp_regs_) { 313 if (!info->IsTemp() && !info->InUse()) { 314 res = info->GetReg(); 315 RecordFpPromotion(res, s_reg); 316 break; 317 } 318 } 319 return res; 320 } 321 322 // TODO: this is Thumb2 only. Remove when DoPromotion refactored. 323 RegStorage Mir2Lir::AllocPreservedDouble(int s_reg) { 324 UNUSED(s_reg); 325 UNIMPLEMENTED(FATAL) << "Unexpected use of AllocPreservedDouble"; 326 UNREACHABLE(); 327 } 328 329 // TODO: this is Thumb2 only. Remove when DoPromotion refactored. 330 RegStorage Mir2Lir::AllocPreservedSingle(int s_reg) { 331 UNUSED(s_reg); 332 UNIMPLEMENTED(FATAL) << "Unexpected use of AllocPreservedSingle"; 333 UNREACHABLE(); 334 } 335 336 337 RegStorage Mir2Lir::AllocTempBody(ArenaVector<RegisterInfo*>& regs, int* next_temp, bool required) { 338 int num_regs = regs.size(); 339 int next = *next_temp; 340 for (int i = 0; i< num_regs; i++) { 341 if (next >= num_regs) { 342 next = 0; 343 } 344 RegisterInfo* info = regs[next]; 345 // Try to allocate a register that doesn't hold a live value. 346 if (info->IsTemp() && !info->InUse() && info->IsDead()) { 347 // If it's wide, split it up. 348 if (info->IsWide()) { 349 // If the pair was associated with a wide value, unmark the partner as well. 350 if (info->SReg() != INVALID_SREG) { 351 RegisterInfo* partner = GetRegInfo(info->Partner()); 352 DCHECK_EQ(info->GetReg().GetRegNum(), partner->Partner().GetRegNum()); 353 DCHECK(partner->IsWide()); 354 partner->SetIsWide(false); 355 } 356 info->SetIsWide(false); 357 } 358 Clobber(info->GetReg()); 359 info->MarkInUse(); 360 *next_temp = next + 1; 361 return info->GetReg(); 362 } 363 next++; 364 } 365 next = *next_temp; 366 // No free non-live regs. Anything we can kill? 367 for (int i = 0; i< num_regs; i++) { 368 if (next >= num_regs) { 369 next = 0; 370 } 371 RegisterInfo* info = regs[next]; 372 if (info->IsTemp() && !info->InUse()) { 373 // Got one. Kill it. 374 ClobberSReg(info->SReg()); 375 Clobber(info->GetReg()); 376 info->MarkInUse(); 377 if (info->IsWide()) { 378 RegisterInfo* partner = GetRegInfo(info->Partner()); 379 DCHECK_EQ(info->GetReg().GetRegNum(), partner->Partner().GetRegNum()); 380 DCHECK(partner->IsWide()); 381 info->SetIsWide(false); 382 partner->SetIsWide(false); 383 } 384 *next_temp = next + 1; 385 return info->GetReg(); 386 } 387 next++; 388 } 389 if (required) { 390 CodegenDump(); 391 DumpRegPools(); 392 LOG(FATAL) << "No free temp registers"; 393 } 394 return RegStorage::InvalidReg(); // No register available 395 } 396 397 RegStorage Mir2Lir::AllocTemp(bool required) { 398 return AllocTempBody(reg_pool_->core_regs_, ®_pool_->next_core_reg_, required); 399 } 400 401 RegStorage Mir2Lir::AllocTempWide(bool required) { 402 RegStorage res; 403 if (reg_pool_->core64_regs_.size() != 0) { 404 res = AllocTempBody(reg_pool_->core64_regs_, ®_pool_->next_core64_reg_, required); 405 } else { 406 RegStorage low_reg = AllocTemp(); 407 RegStorage high_reg = AllocTemp(); 408 res = RegStorage::MakeRegPair(low_reg, high_reg); 409 } 410 if (required) { 411 CheckRegStorage(res, WidenessCheck::kCheckWide, RefCheck::kIgnoreRef, FPCheck::kCheckNotFP); 412 } 413 return res; 414 } 415 416 RegStorage Mir2Lir::AllocTempRef(bool required) { 417 RegStorage res = AllocTempBody(*reg_pool_->ref_regs_, reg_pool_->next_ref_reg_, required); 418 if (required) { 419 DCHECK(!res.IsPair()); 420 CheckRegStorage(res, WidenessCheck::kCheckNotWide, RefCheck::kCheckRef, FPCheck::kCheckNotFP); 421 } 422 return res; 423 } 424 425 RegStorage Mir2Lir::AllocTempSingle(bool required) { 426 RegStorage res = AllocTempBody(reg_pool_->sp_regs_, ®_pool_->next_sp_reg_, required); 427 if (required) { 428 DCHECK(res.IsSingle()) << "Reg: 0x" << std::hex << res.GetRawBits(); 429 CheckRegStorage(res, WidenessCheck::kCheckNotWide, RefCheck::kCheckNotRef, FPCheck::kIgnoreFP); 430 } 431 return res; 432 } 433 434 RegStorage Mir2Lir::AllocTempDouble(bool required) { 435 RegStorage res = AllocTempBody(reg_pool_->dp_regs_, ®_pool_->next_dp_reg_, required); 436 if (required) { 437 DCHECK(res.IsDouble()) << "Reg: 0x" << std::hex << res.GetRawBits(); 438 CheckRegStorage(res, WidenessCheck::kCheckWide, RefCheck::kCheckNotRef, FPCheck::kIgnoreFP); 439 } 440 return res; 441 } 442 443 RegStorage Mir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class, bool required) { 444 DCHECK_NE(reg_class, kRefReg); // NOTE: the Dalvik width of a reference is always 32 bits. 445 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { 446 return AllocTempDouble(required); 447 } 448 return AllocTempWide(required); 449 } 450 451 RegStorage Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class, bool required) { 452 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { 453 return AllocTempSingle(required); 454 } else if (reg_class == kRefReg) { 455 return AllocTempRef(required); 456 } 457 return AllocTemp(required); 458 } 459 460 RegStorage Mir2Lir::FindLiveReg(ArenaVector<RegisterInfo*>& regs, int s_reg) { 461 RegStorage res; 462 for (RegisterInfo* info : regs) { 463 if ((info->SReg() == s_reg) && info->IsLive()) { 464 res = info->GetReg(); 465 break; 466 } 467 } 468 return res; 469 } 470 471 RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) { 472 RegStorage reg; 473 if (reg_class == kRefReg) { 474 reg = FindLiveReg(*reg_pool_->ref_regs_, s_reg); 475 CheckRegStorage(reg, WidenessCheck::kCheckNotWide, RefCheck::kCheckRef, FPCheck::kCheckNotFP); 476 } 477 if (!reg.Valid() && ((reg_class == kAnyReg) || (reg_class == kFPReg))) { 478 reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg); 479 } 480 if (!reg.Valid() && (reg_class != kFPReg)) { 481 if (cu_->target64) { 482 reg = FindLiveReg(wide || reg_class == kRefReg ? reg_pool_->core64_regs_ : 483 reg_pool_->core_regs_, s_reg); 484 } else { 485 reg = FindLiveReg(reg_pool_->core_regs_, s_reg); 486 } 487 } 488 if (reg.Valid()) { 489 if (wide && !reg.IsFloat() && !cu_->target64) { 490 // Only allow reg pairs for core regs on 32-bit targets. 491 RegStorage high_reg = FindLiveReg(reg_pool_->core_regs_, s_reg + 1); 492 if (high_reg.Valid()) { 493 reg = RegStorage::MakeRegPair(reg, high_reg); 494 MarkWide(reg); 495 } else { 496 // Only half available. 497 reg = RegStorage::InvalidReg(); 498 } 499 } 500 if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) { 501 // Width mismatch - don't try to reuse. 502 reg = RegStorage::InvalidReg(); 503 } 504 } 505 if (reg.Valid()) { 506 if (reg.IsPair()) { 507 RegisterInfo* info_low = GetRegInfo(reg.GetLow()); 508 RegisterInfo* info_high = GetRegInfo(reg.GetHigh()); 509 if (info_low->IsTemp()) { 510 info_low->MarkInUse(); 511 } 512 if (info_high->IsTemp()) { 513 info_high->MarkInUse(); 514 } 515 } else { 516 RegisterInfo* info = GetRegInfo(reg); 517 if (info->IsTemp()) { 518 info->MarkInUse(); 519 } 520 } 521 } else { 522 // Either not found, or something didn't match up. Clobber to prevent any stale instances. 523 ClobberSReg(s_reg); 524 if (wide) { 525 ClobberSReg(s_reg + 1); 526 } 527 } 528 CheckRegStorage(reg, WidenessCheck::kIgnoreWide, 529 reg_class == kRefReg ? RefCheck::kCheckRef : RefCheck::kIgnoreRef, 530 FPCheck::kIgnoreFP); 531 return reg; 532 } 533 534 void Mir2Lir::FreeTemp(RegStorage reg) { 535 if (reg.IsPair()) { 536 FreeTemp(reg.GetLow()); 537 FreeTemp(reg.GetHigh()); 538 } else { 539 RegisterInfo* p = GetRegInfo(reg); 540 if (p->IsTemp()) { 541 p->MarkFree(); 542 p->SetIsWide(false); 543 p->SetPartner(reg); 544 } 545 } 546 } 547 548 void Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) { 549 DCHECK(rl_keep.wide); 550 DCHECK(rl_free.wide); 551 int free_low = rl_free.reg.GetLowReg(); 552 int free_high = rl_free.reg.GetHighReg(); 553 int keep_low = rl_keep.reg.GetLowReg(); 554 int keep_high = rl_keep.reg.GetHighReg(); 555 if ((free_low != keep_low) && (free_low != keep_high) && 556 (free_high != keep_low) && (free_high != keep_high)) { 557 // No overlap, free both 558 FreeTemp(rl_free.reg); 559 } 560 } 561 562 bool Mir2Lir::IsLive(RegStorage reg) { 563 bool res; 564 if (reg.IsPair()) { 565 RegisterInfo* p_lo = GetRegInfo(reg.GetLow()); 566 RegisterInfo* p_hi = GetRegInfo(reg.GetHigh()); 567 DCHECK_EQ(p_lo->IsLive(), p_hi->IsLive()); 568 res = p_lo->IsLive() || p_hi->IsLive(); 569 } else { 570 RegisterInfo* p = GetRegInfo(reg); 571 res = p->IsLive(); 572 } 573 return res; 574 } 575 576 bool Mir2Lir::IsTemp(RegStorage reg) { 577 bool res; 578 if (reg.IsPair()) { 579 RegisterInfo* p_lo = GetRegInfo(reg.GetLow()); 580 RegisterInfo* p_hi = GetRegInfo(reg.GetHigh()); 581 res = p_lo->IsTemp() || p_hi->IsTemp(); 582 } else { 583 RegisterInfo* p = GetRegInfo(reg); 584 res = p->IsTemp(); 585 } 586 return res; 587 } 588 589 bool Mir2Lir::IsPromoted(RegStorage reg) { 590 bool res; 591 if (reg.IsPair()) { 592 RegisterInfo* p_lo = GetRegInfo(reg.GetLow()); 593 RegisterInfo* p_hi = GetRegInfo(reg.GetHigh()); 594 res = !p_lo->IsTemp() || !p_hi->IsTemp(); 595 } else { 596 RegisterInfo* p = GetRegInfo(reg); 597 res = !p->IsTemp(); 598 } 599 return res; 600 } 601 602 bool Mir2Lir::IsDirty(RegStorage reg) { 603 bool res; 604 if (reg.IsPair()) { 605 RegisterInfo* p_lo = GetRegInfo(reg.GetLow()); 606 RegisterInfo* p_hi = GetRegInfo(reg.GetHigh()); 607 res = p_lo->IsDirty() || p_hi->IsDirty(); 608 } else { 609 RegisterInfo* p = GetRegInfo(reg); 610 res = p->IsDirty(); 611 } 612 return res; 613 } 614 615 /* 616 * Similar to AllocTemp(), but forces the allocation of a specific 617 * register. No check is made to see if the register was previously 618 * allocated. Use with caution. 619 */ 620 void Mir2Lir::LockTemp(RegStorage reg) { 621 DCHECK(IsTemp(reg)); 622 if (reg.IsPair()) { 623 RegisterInfo* p_lo = GetRegInfo(reg.GetLow()); 624 RegisterInfo* p_hi = GetRegInfo(reg.GetHigh()); 625 p_lo->MarkInUse(); 626 p_lo->MarkDead(); 627 p_hi->MarkInUse(); 628 p_hi->MarkDead(); 629 } else { 630 RegisterInfo* p = GetRegInfo(reg); 631 p->MarkInUse(); 632 p->MarkDead(); 633 } 634 } 635 636 void Mir2Lir::ResetDef(RegStorage reg) { 637 if (reg.IsPair()) { 638 GetRegInfo(reg.GetLow())->ResetDefBody(); 639 GetRegInfo(reg.GetHigh())->ResetDefBody(); 640 } else { 641 GetRegInfo(reg)->ResetDefBody(); 642 } 643 } 644 645 void Mir2Lir::NullifyRange(RegStorage reg, int s_reg) { 646 RegisterInfo* info = nullptr; 647 RegStorage rs = reg.IsPair() ? reg.GetLow() : reg; 648 if (IsTemp(rs)) { 649 info = GetRegInfo(reg); 650 } 651 if ((info != nullptr) && (info->DefStart() != nullptr) && (info->DefEnd() != nullptr)) { 652 DCHECK_EQ(info->SReg(), s_reg); // Make sure we're on the same page. 653 for (LIR* p = info->DefStart();; p = p->next) { 654 NopLIR(p); 655 if (p == info->DefEnd()) { 656 break; 657 } 658 } 659 } 660 } 661 662 /* 663 * Mark the beginning and end LIR of a def sequence. Note that 664 * on entry start points to the LIR prior to the beginning of the 665 * sequence. 666 */ 667 void Mir2Lir::MarkDef(RegLocation rl, LIR *start, LIR *finish) { 668 DCHECK(!rl.wide); 669 DCHECK(start && start->next); 670 DCHECK(finish); 671 RegisterInfo* p = GetRegInfo(rl.reg); 672 p->SetDefStart(start->next); 673 p->SetDefEnd(finish); 674 } 675 676 /* 677 * Mark the beginning and end LIR of a def sequence. Note that 678 * on entry start points to the LIR prior to the beginning of the 679 * sequence. 680 */ 681 void Mir2Lir::MarkDefWide(RegLocation rl, LIR *start, LIR *finish) { 682 DCHECK(rl.wide); 683 DCHECK(start && start->next); 684 DCHECK(finish); 685 RegisterInfo* p; 686 if (rl.reg.IsPair()) { 687 p = GetRegInfo(rl.reg.GetLow()); 688 ResetDef(rl.reg.GetHigh()); // Only track low of pair 689 } else { 690 p = GetRegInfo(rl.reg); 691 } 692 p->SetDefStart(start->next); 693 p->SetDefEnd(finish); 694 } 695 696 void Mir2Lir::ResetDefLoc(RegLocation rl) { 697 DCHECK(!rl.wide); 698 if (IsTemp(rl.reg) && !(cu_->disable_opt & (1 << kSuppressLoads))) { 699 NullifyRange(rl.reg, rl.s_reg_low); 700 } 701 ResetDef(rl.reg); 702 } 703 704 void Mir2Lir::ResetDefLocWide(RegLocation rl) { 705 DCHECK(rl.wide); 706 // If pair, only track low reg of pair. 707 RegStorage rs = rl.reg.IsPair() ? rl.reg.GetLow() : rl.reg; 708 if (IsTemp(rs) && !(cu_->disable_opt & (1 << kSuppressLoads))) { 709 NullifyRange(rs, rl.s_reg_low); 710 } 711 ResetDef(rs); 712 } 713 714 void Mir2Lir::ResetDefTracking() { 715 for (RegisterInfo* info : tempreg_info_) { 716 info->ResetDefBody(); 717 } 718 } 719 720 void Mir2Lir::ClobberAllTemps() { 721 for (RegisterInfo* info : tempreg_info_) { 722 ClobberBody(info); 723 } 724 } 725 726 void Mir2Lir::FlushRegWide(RegStorage reg) { 727 if (reg.IsPair()) { 728 RegisterInfo* info1 = GetRegInfo(reg.GetLow()); 729 RegisterInfo* info2 = GetRegInfo(reg.GetHigh()); 730 DCHECK(info1 && info2 && info1->IsWide() && info2->IsWide() && 731 (info1->Partner().ExactlyEquals(info2->GetReg())) && 732 (info2->Partner().ExactlyEquals(info1->GetReg()))); 733 if ((info1->IsLive() && info1->IsDirty()) || (info2->IsLive() && info2->IsDirty())) { 734 if (!(info1->IsTemp() && info2->IsTemp())) { 735 /* Should not happen. If it does, there's a problem in eval_loc */ 736 LOG(FATAL) << "Long half-temp, half-promoted"; 737 } 738 739 info1->SetIsDirty(false); 740 info2->SetIsDirty(false); 741 if (mir_graph_->SRegToVReg(info2->SReg()) < mir_graph_->SRegToVReg(info1->SReg())) { 742 info1 = info2; 743 } 744 int v_reg = mir_graph_->SRegToVReg(info1->SReg()); 745 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 746 StoreBaseDisp(TargetPtrReg(kSp), VRegOffset(v_reg), reg, k64, kNotVolatile); 747 } 748 } else { 749 RegisterInfo* info = GetRegInfo(reg); 750 if (info->IsLive() && info->IsDirty()) { 751 info->SetIsDirty(false); 752 int v_reg = mir_graph_->SRegToVReg(info->SReg()); 753 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 754 StoreBaseDisp(TargetPtrReg(kSp), VRegOffset(v_reg), reg, k64, kNotVolatile); 755 } 756 } 757 } 758 759 void Mir2Lir::FlushReg(RegStorage reg) { 760 DCHECK(!reg.IsPair()); 761 RegisterInfo* info = GetRegInfo(reg); 762 if (info->IsLive() && info->IsDirty()) { 763 info->SetIsDirty(false); 764 int v_reg = mir_graph_->SRegToVReg(info->SReg()); 765 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 766 StoreBaseDisp(TargetPtrReg(kSp), VRegOffset(v_reg), reg, kWord, kNotVolatile); 767 } 768 } 769 770 void Mir2Lir::FlushSpecificReg(RegisterInfo* info) { 771 if (info->IsWide()) { 772 FlushRegWide(info->GetReg()); 773 } else { 774 FlushReg(info->GetReg()); 775 } 776 } 777 778 void Mir2Lir::FlushAllRegs() { 779 for (RegisterInfo* info : tempreg_info_) { 780 if (info->IsDirty() && info->IsLive()) { 781 FlushSpecificReg(info); 782 } 783 info->MarkDead(); 784 info->SetIsWide(false); 785 } 786 } 787 788 789 bool Mir2Lir::RegClassMatches(int reg_class, RegStorage reg) { 790 if (reg_class == kAnyReg) { 791 return true; 792 } else if ((reg_class == kCoreReg) || (reg_class == kRefReg)) { 793 /* 794 * For this purpose, consider Core and Ref to be the same class. We aren't dealing 795 * with width here - that should be checked at a higher level (if needed). 796 */ 797 return !reg.IsFloat(); 798 } else { 799 return reg.IsFloat(); 800 } 801 } 802 803 void Mir2Lir::MarkLive(RegLocation loc) { 804 RegStorage reg = loc.reg; 805 if (!IsTemp(reg)) { 806 return; 807 } 808 int s_reg = loc.s_reg_low; 809 if (s_reg == INVALID_SREG) { 810 // Can't be live if no associated sreg. 811 if (reg.IsPair()) { 812 GetRegInfo(reg.GetLow())->MarkDead(); 813 GetRegInfo(reg.GetHigh())->MarkDead(); 814 } else { 815 GetRegInfo(reg)->MarkDead(); 816 } 817 } else { 818 if (reg.IsPair()) { 819 RegisterInfo* info_lo = GetRegInfo(reg.GetLow()); 820 RegisterInfo* info_hi = GetRegInfo(reg.GetHigh()); 821 if (info_lo->IsLive() && (info_lo->SReg() == s_reg) && info_hi->IsLive() && 822 (info_hi->SReg() == s_reg)) { 823 return; // Already live. 824 } 825 ClobberSReg(s_reg); 826 ClobberSReg(s_reg + 1); 827 info_lo->MarkLive(s_reg); 828 info_hi->MarkLive(s_reg + 1); 829 } else { 830 RegisterInfo* info = GetRegInfo(reg); 831 if (info->IsLive() && (info->SReg() == s_reg)) { 832 return; // Already live. 833 } 834 ClobberSReg(s_reg); 835 if (loc.wide) { 836 ClobberSReg(s_reg + 1); 837 } 838 info->MarkLive(s_reg); 839 } 840 if (loc.wide) { 841 MarkWide(reg); 842 } else { 843 MarkNarrow(reg); 844 } 845 } 846 } 847 848 void Mir2Lir::MarkTemp(RegStorage reg) { 849 DCHECK(!reg.IsPair()); 850 RegisterInfo* info = GetRegInfo(reg); 851 tempreg_info_.push_back(info); 852 info->SetIsTemp(true); 853 } 854 855 void Mir2Lir::UnmarkTemp(RegStorage reg) { 856 DCHECK(!reg.IsPair()); 857 RegisterInfo* info = GetRegInfo(reg); 858 auto pos = std::find(tempreg_info_.begin(), tempreg_info_.end(), info); 859 DCHECK(pos != tempreg_info_.end()); 860 tempreg_info_.erase(pos); 861 info->SetIsTemp(false); 862 } 863 864 void Mir2Lir::MarkWide(RegStorage reg) { 865 if (reg.IsPair()) { 866 RegisterInfo* info_lo = GetRegInfo(reg.GetLow()); 867 RegisterInfo* info_hi = GetRegInfo(reg.GetHigh()); 868 // Unpair any old partners. 869 if (info_lo->IsWide() && info_lo->Partner().NotExactlyEquals(info_hi->GetReg())) { 870 GetRegInfo(info_lo->Partner())->SetIsWide(false); 871 } 872 if (info_hi->IsWide() && info_hi->Partner().NotExactlyEquals(info_lo->GetReg())) { 873 GetRegInfo(info_hi->Partner())->SetIsWide(false); 874 } 875 info_lo->SetIsWide(true); 876 info_hi->SetIsWide(true); 877 info_lo->SetPartner(reg.GetHigh()); 878 info_hi->SetPartner(reg.GetLow()); 879 } else { 880 RegisterInfo* info = GetRegInfo(reg); 881 info->SetIsWide(true); 882 info->SetPartner(reg); 883 } 884 } 885 886 void Mir2Lir::MarkNarrow(RegStorage reg) { 887 DCHECK(!reg.IsPair()); 888 RegisterInfo* info = GetRegInfo(reg); 889 info->SetIsWide(false); 890 info->SetPartner(reg); 891 } 892 893 void Mir2Lir::MarkClean(RegLocation loc) { 894 if (loc.reg.IsPair()) { 895 RegisterInfo* info = GetRegInfo(loc.reg.GetLow()); 896 info->SetIsDirty(false); 897 info = GetRegInfo(loc.reg.GetHigh()); 898 info->SetIsDirty(false); 899 } else { 900 RegisterInfo* info = GetRegInfo(loc.reg); 901 info->SetIsDirty(false); 902 } 903 } 904 905 // FIXME: need to verify rules/assumptions about how wide values are treated in 64BitSolos. 906 void Mir2Lir::MarkDirty(RegLocation loc) { 907 if (loc.home) { 908 // If already home, can't be dirty 909 return; 910 } 911 if (loc.reg.IsPair()) { 912 RegisterInfo* info = GetRegInfo(loc.reg.GetLow()); 913 info->SetIsDirty(true); 914 info = GetRegInfo(loc.reg.GetHigh()); 915 info->SetIsDirty(true); 916 } else { 917 RegisterInfo* info = GetRegInfo(loc.reg); 918 info->SetIsDirty(true); 919 } 920 } 921 922 void Mir2Lir::MarkInUse(RegStorage reg) { 923 if (reg.IsPair()) { 924 GetRegInfo(reg.GetLow())->MarkInUse(); 925 GetRegInfo(reg.GetHigh())->MarkInUse(); 926 } else { 927 GetRegInfo(reg)->MarkInUse(); 928 } 929 } 930 931 bool Mir2Lir::CheckCorePoolSanity() { 932 for (RegisterInfo* info : tempreg_info_) { 933 int my_sreg = info->SReg(); 934 if (info->IsTemp() && info->IsLive() && info->IsWide() && my_sreg != INVALID_SREG) { 935 RegStorage my_reg = info->GetReg(); 936 RegStorage partner_reg = info->Partner(); 937 RegisterInfo* partner = GetRegInfo(partner_reg); 938 DCHECK(partner != nullptr); 939 DCHECK(partner->IsWide()); 940 DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg()); 941 DCHECK(partner->IsLive()); 942 int partner_sreg = partner->SReg(); 943 int diff = my_sreg - partner_sreg; 944 DCHECK((diff == 0) || (diff == -1) || (diff == 1)); 945 } 946 if (info->Master() != info) { 947 // Aliased. 948 if (info->IsLive() && (info->SReg() != INVALID_SREG)) { 949 // If I'm live, master should not be live, but should show liveness in alias set. 950 DCHECK_EQ(info->Master()->SReg(), INVALID_SREG); 951 DCHECK(!info->Master()->IsDead()); 952 } 953 // TODO: Add checks in !info->IsDead() case to ensure every live bit is owned by exactly 1 reg. 954 } 955 if (info->IsAliased()) { 956 // Has child aliases. 957 DCHECK_EQ(info->Master(), info); 958 if (info->IsLive() && (info->SReg() != INVALID_SREG)) { 959 // Master live, no child should be dead - all should show liveness in set. 960 for (RegisterInfo* p = info->GetAliasChain(); p != nullptr; p = p->GetAliasChain()) { 961 DCHECK(!p->IsDead()); 962 DCHECK_EQ(p->SReg(), INVALID_SREG); 963 } 964 } else if (!info->IsDead()) { 965 // Master not live, one or more aliases must be. 966 bool live_alias = false; 967 for (RegisterInfo* p = info->GetAliasChain(); p != nullptr; p = p->GetAliasChain()) { 968 live_alias |= p->IsLive(); 969 } 970 DCHECK(live_alias); 971 } 972 } 973 if (info->IsLive() && (info->SReg() == INVALID_SREG)) { 974 // If not fully live, should have INVALID_SREG and def's should be null. 975 DCHECK(info->DefStart() == nullptr); 976 DCHECK(info->DefEnd() == nullptr); 977 } 978 } 979 return true; 980 } 981 982 /* 983 * Return an updated location record with current in-register status. 984 * If the value lives in live temps, reflect that fact. No code 985 * is generated. If the live value is part of an older pair, 986 * clobber both low and high. 987 * TUNING: clobbering both is a bit heavy-handed, but the alternative 988 * is a bit complex when dealing with FP regs. Examine code to see 989 * if it's worthwhile trying to be more clever here. 990 */ 991 RegLocation Mir2Lir::UpdateLoc(RegLocation loc) { 992 DCHECK(!loc.wide); 993 DCHECK(CheckCorePoolSanity()); 994 if (loc.location != kLocPhysReg) { 995 DCHECK((loc.location == kLocDalvikFrame) || 996 (loc.location == kLocCompilerTemp)); 997 RegStorage reg = AllocLiveReg(loc.s_reg_low, loc.ref ? kRefReg : kAnyReg, false); 998 if (reg.Valid()) { 999 bool match = true; 1000 RegisterInfo* info = GetRegInfo(reg); 1001 match &= !reg.IsPair(); 1002 match &= !info->IsWide(); 1003 if (match) { 1004 loc.location = kLocPhysReg; 1005 loc.reg = reg; 1006 } else { 1007 Clobber(reg); 1008 FreeTemp(reg); 1009 } 1010 } 1011 CheckRegLocation(loc); 1012 } 1013 return loc; 1014 } 1015 1016 RegLocation Mir2Lir::UpdateLocWide(RegLocation loc) { 1017 DCHECK(loc.wide); 1018 DCHECK(CheckCorePoolSanity()); 1019 if (loc.location != kLocPhysReg) { 1020 DCHECK((loc.location == kLocDalvikFrame) || 1021 (loc.location == kLocCompilerTemp)); 1022 RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, true); 1023 if (reg.Valid()) { 1024 bool match = true; 1025 if (reg.IsPair()) { 1026 // If we've got a register pair, make sure that it was last used as the same pair. 1027 RegisterInfo* info_lo = GetRegInfo(reg.GetLow()); 1028 RegisterInfo* info_hi = GetRegInfo(reg.GetHigh()); 1029 match &= info_lo->IsWide(); 1030 match &= info_hi->IsWide(); 1031 match &= (info_lo->Partner().ExactlyEquals(info_hi->GetReg())); 1032 match &= (info_hi->Partner().ExactlyEquals(info_lo->GetReg())); 1033 } else { 1034 RegisterInfo* info = GetRegInfo(reg); 1035 match &= info->IsWide(); 1036 match &= (info->GetReg().ExactlyEquals(info->Partner())); 1037 } 1038 if (match) { 1039 loc.location = kLocPhysReg; 1040 loc.reg = reg; 1041 } else { 1042 Clobber(reg); 1043 FreeTemp(reg); 1044 } 1045 } 1046 CheckRegLocation(loc); 1047 } 1048 return loc; 1049 } 1050 1051 /* For use in cases we don't know (or care) width */ 1052 RegLocation Mir2Lir::UpdateRawLoc(RegLocation loc) { 1053 if (loc.wide) 1054 return UpdateLocWide(loc); 1055 else 1056 return UpdateLoc(loc); 1057 } 1058 1059 RegLocation Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { 1060 DCHECK(loc.wide); 1061 1062 loc = UpdateLocWide(loc); 1063 1064 /* If already in registers, we can assume proper form. Right reg class? */ 1065 if (loc.location == kLocPhysReg) { 1066 if (!RegClassMatches(reg_class, loc.reg)) { 1067 // Wrong register class. Reallocate and transfer ownership. 1068 RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class); 1069 // Clobber the old regs. 1070 Clobber(loc.reg); 1071 // ...and mark the new ones live. 1072 loc.reg = new_regs; 1073 MarkWide(loc.reg); 1074 MarkLive(loc); 1075 } 1076 CheckRegLocation(loc); 1077 return loc; 1078 } 1079 1080 DCHECK_NE(loc.s_reg_low, INVALID_SREG); 1081 DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG); 1082 1083 loc.reg = AllocTypedTempWide(loc.fp, reg_class); 1084 MarkWide(loc.reg); 1085 1086 if (update) { 1087 loc.location = kLocPhysReg; 1088 MarkLive(loc); 1089 } 1090 CheckRegLocation(loc); 1091 return loc; 1092 } 1093 1094 RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) { 1095 // Narrow reg_class if the loc is a ref. 1096 if (loc.ref && reg_class == kAnyReg) { 1097 reg_class = kRefReg; 1098 } 1099 1100 if (loc.wide) { 1101 return EvalLocWide(loc, reg_class, update); 1102 } 1103 1104 loc = UpdateLoc(loc); 1105 1106 if (loc.location == kLocPhysReg) { 1107 if (!RegClassMatches(reg_class, loc.reg)) { 1108 // Wrong register class. Reallocate and transfer ownership. 1109 RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class); 1110 // Clobber the old reg. 1111 Clobber(loc.reg); 1112 // ...and mark the new one live. 1113 loc.reg = new_reg; 1114 MarkLive(loc); 1115 } 1116 CheckRegLocation(loc); 1117 return loc; 1118 } 1119 1120 DCHECK_NE(loc.s_reg_low, INVALID_SREG); 1121 1122 loc.reg = AllocTypedTemp(loc.fp, reg_class); 1123 CheckRegLocation(loc); 1124 1125 if (update) { 1126 loc.location = kLocPhysReg; 1127 MarkLive(loc); 1128 } 1129 CheckRegLocation(loc); 1130 return loc; 1131 } 1132 1133 void Mir2Lir::AnalyzeMIR(RefCounts* core_counts, MIR* mir, uint32_t weight) { 1134 // NOTE: This should be in sync with functions that actually generate code for 1135 // the opcodes below. However, if we get this wrong, the generated code will 1136 // still be correct even if it may be sub-optimal. 1137 int opcode = mir->dalvikInsn.opcode; 1138 bool uses_method = false; 1139 bool uses_pc_rel_load = false; 1140 uint32_t dex_cache_array_offset = std::numeric_limits<uint32_t>::max(); 1141 switch (opcode) { 1142 case Instruction::CHECK_CAST: 1143 case Instruction::INSTANCE_OF: { 1144 if ((opcode == Instruction::CHECK_CAST) && 1145 (mir->optimization_flags & MIR_IGNORE_CHECK_CAST) != 0) { 1146 break; // No code generated. 1147 } 1148 uint32_t type_idx = 1149 (opcode == Instruction::CHECK_CAST) ? mir->dalvikInsn.vB : mir->dalvikInsn.vC; 1150 bool type_known_final, type_known_abstract, use_declaring_class; 1151 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks( 1152 cu_->method_idx, *cu_->dex_file, type_idx, 1153 &type_known_final, &type_known_abstract, &use_declaring_class); 1154 if (opcode == Instruction::CHECK_CAST && !needs_access_check && 1155 cu_->compiler_driver->IsSafeCast( 1156 mir_graph_->GetCurrentDexCompilationUnit(), mir->offset)) { 1157 break; // No code generated. 1158 } 1159 if (!needs_access_check && !use_declaring_class && CanUseOpPcRelDexCacheArrayLoad()) { 1160 uses_pc_rel_load = true; // And ignore method use in slow path. 1161 dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(type_idx); 1162 } else { 1163 uses_method = true; 1164 } 1165 break; 1166 } 1167 1168 case Instruction::CONST_CLASS: 1169 if (CanUseOpPcRelDexCacheArrayLoad() && 1170 cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, 1171 mir->dalvikInsn.vB)) { 1172 uses_pc_rel_load = true; // And ignore method use in slow path. 1173 dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(mir->dalvikInsn.vB); 1174 } else { 1175 uses_method = true; 1176 } 1177 break; 1178 1179 case Instruction::CONST_STRING: 1180 case Instruction::CONST_STRING_JUMBO: 1181 if (CanUseOpPcRelDexCacheArrayLoad()) { 1182 uses_pc_rel_load = true; // And ignore method use in slow path. 1183 dex_cache_array_offset = dex_cache_arrays_layout_.StringOffset(mir->dalvikInsn.vB); 1184 } else { 1185 uses_method = true; 1186 } 1187 break; 1188 1189 case Instruction::INVOKE_VIRTUAL: 1190 case Instruction::INVOKE_SUPER: 1191 case Instruction::INVOKE_DIRECT: 1192 case Instruction::INVOKE_STATIC: 1193 case Instruction::INVOKE_INTERFACE: 1194 case Instruction::INVOKE_VIRTUAL_RANGE: 1195 case Instruction::INVOKE_SUPER_RANGE: 1196 case Instruction::INVOKE_DIRECT_RANGE: 1197 case Instruction::INVOKE_STATIC_RANGE: 1198 case Instruction::INVOKE_INTERFACE_RANGE: 1199 case Instruction::INVOKE_VIRTUAL_QUICK: 1200 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { 1201 const MirMethodLoweringInfo& info = mir_graph_->GetMethodLoweringInfo(mir); 1202 InvokeType sharp_type = info.GetSharpType(); 1203 if (info.IsIntrinsic()) { 1204 // Nothing to do, if an intrinsic uses ArtMethod* it's in the slow-path - don't count it. 1205 } else if (!info.FastPath() || (sharp_type != kStatic && sharp_type != kDirect)) { 1206 // Nothing to do, the generated code or entrypoint uses method from the stack. 1207 } else if (info.DirectCode() != 0 && info.DirectMethod() != 0) { 1208 // Nothing to do, the generated code uses method from the stack. 1209 } else if (CanUseOpPcRelDexCacheArrayLoad()) { 1210 uses_pc_rel_load = true; 1211 dex_cache_array_offset = dex_cache_arrays_layout_.MethodOffset(mir->dalvikInsn.vB); 1212 } else { 1213 uses_method = true; 1214 } 1215 break; 1216 } 1217 1218 case Instruction::NEW_INSTANCE: 1219 case Instruction::NEW_ARRAY: 1220 case Instruction::FILLED_NEW_ARRAY: 1221 case Instruction::FILLED_NEW_ARRAY_RANGE: 1222 uses_method = true; 1223 break; 1224 case Instruction::FILL_ARRAY_DATA: 1225 // Nothing to do, the entrypoint uses method from the stack. 1226 break; 1227 case Instruction::THROW: 1228 // Nothing to do, the entrypoint uses method from the stack. 1229 break; 1230 1231 case Instruction::SGET: 1232 case Instruction::SGET_WIDE: 1233 case Instruction::SGET_OBJECT: 1234 case Instruction::SGET_BOOLEAN: 1235 case Instruction::SGET_BYTE: 1236 case Instruction::SGET_CHAR: 1237 case Instruction::SGET_SHORT: 1238 case Instruction::SPUT: 1239 case Instruction::SPUT_WIDE: 1240 case Instruction::SPUT_OBJECT: 1241 case Instruction::SPUT_BOOLEAN: 1242 case Instruction::SPUT_BYTE: 1243 case Instruction::SPUT_CHAR: 1244 case Instruction::SPUT_SHORT: { 1245 const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir); 1246 bool fast = IsInstructionSGet(static_cast<Instruction::Code>(opcode)) 1247 ? field_info.FastGet() 1248 : field_info.FastPut(); 1249 if (fast && (cu_->enable_debug & (1 << kDebugSlowFieldPath)) == 0) { 1250 if (!field_info.IsReferrersClass() && CanUseOpPcRelDexCacheArrayLoad()) { 1251 uses_pc_rel_load = true; // And ignore method use in slow path. 1252 dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(field_info.StorageIndex()); 1253 } else { 1254 uses_method = true; 1255 } 1256 } else { 1257 // Nothing to do, the entrypoint uses method from the stack. 1258 } 1259 break; 1260 } 1261 1262 default: 1263 break; 1264 } 1265 if (uses_method) { 1266 core_counts[SRegToPMap(mir_graph_->GetMethodLoc().s_reg_low)].count += weight; 1267 } 1268 if (uses_pc_rel_load) { 1269 if (pc_rel_temp_ != nullptr) { 1270 core_counts[SRegToPMap(pc_rel_temp_->s_reg_low)].count += weight; 1271 DCHECK_NE(dex_cache_array_offset, std::numeric_limits<uint32_t>::max()); 1272 dex_cache_arrays_min_offset_ = std::min(dex_cache_arrays_min_offset_, dex_cache_array_offset); 1273 } else { 1274 // Nothing to do, using PC-relative addressing without promoting base PC to register. 1275 } 1276 } 1277 } 1278 1279 /* USE SSA names to count references of base Dalvik v_regs. */ 1280 void Mir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) { 1281 for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) { 1282 RegLocation loc = mir_graph_->reg_location_[i]; 1283 RefCounts* counts = loc.fp ? fp_counts : core_counts; 1284 int p_map_idx = SRegToPMap(loc.s_reg_low); 1285 int use_count = mir_graph_->GetUseCount(i); 1286 if (loc.fp) { 1287 if (loc.wide) { 1288 if (WideFPRsAreAliases()) { 1289 // Floats and doubles can be counted together. 1290 counts[p_map_idx].count += use_count; 1291 } else { 1292 // Treat doubles as a unit, using upper half of fp_counts array. 1293 counts[p_map_idx + num_regs].count += use_count; 1294 } 1295 i++; 1296 } else { 1297 counts[p_map_idx].count += use_count; 1298 } 1299 } else { 1300 if (loc.wide && WideGPRsAreAliases()) { 1301 i++; 1302 } 1303 if (!IsInexpensiveConstant(loc)) { 1304 counts[p_map_idx].count += use_count; 1305 } 1306 } 1307 } 1308 1309 // Now analyze the ArtMethod* and pc_rel_temp_ uses. 1310 DCHECK_EQ(core_counts[SRegToPMap(mir_graph_->GetMethodLoc().s_reg_low)].count, 0); 1311 if (pc_rel_temp_ != nullptr) { 1312 DCHECK_EQ(core_counts[SRegToPMap(pc_rel_temp_->s_reg_low)].count, 0); 1313 } 1314 PreOrderDfsIterator iter(mir_graph_); 1315 for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) { 1316 if (bb->block_type == kDead) { 1317 continue; 1318 } 1319 uint32_t weight = mir_graph_->GetUseCountWeight(bb); 1320 for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { 1321 AnalyzeMIR(core_counts, mir, weight); 1322 } 1323 } 1324 } 1325 1326 /* qsort callback function, sort descending */ 1327 static int SortCounts(const void *val1, const void *val2) { 1328 const Mir2Lir::RefCounts* op1 = reinterpret_cast<const Mir2Lir::RefCounts*>(val1); 1329 const Mir2Lir::RefCounts* op2 = reinterpret_cast<const Mir2Lir::RefCounts*>(val2); 1330 // Note that we fall back to sorting on reg so we get stable output on differing qsort 1331 // implementations (such as on host and target or between local host and build servers). 1332 // Note also that if a wide val1 and a non-wide val2 have the same count, then val1 always 1333 // ``loses'' (as STARTING_WIDE_SREG is or-ed in val1->s_reg). 1334 return (op1->count == op2->count) 1335 ? (op1->s_reg - op2->s_reg) 1336 : (op1->count < op2->count ? 1 : -1); 1337 } 1338 1339 void Mir2Lir::DumpCounts(const RefCounts* arr, int size, const char* msg) { 1340 LOG(INFO) << msg; 1341 for (int i = 0; i < size; i++) { 1342 if ((arr[i].s_reg & STARTING_WIDE_SREG) != 0) { 1343 LOG(INFO) << "s_reg[64_" << (arr[i].s_reg & ~STARTING_WIDE_SREG) << "]: " << arr[i].count; 1344 } else { 1345 LOG(INFO) << "s_reg[32_" << arr[i].s_reg << "]: " << arr[i].count; 1346 } 1347 } 1348 } 1349 1350 /* 1351 * Note: some portions of this code required even if the kPromoteRegs 1352 * optimization is disabled. 1353 */ 1354 void Mir2Lir::DoPromotion() { 1355 int num_regs = mir_graph_->GetNumOfCodeAndTempVRs(); 1356 const int promotion_threshold = 1; 1357 // Allocate the promotion map - one entry for each Dalvik vReg or compiler temp 1358 promotion_map_ = arena_->AllocArray<PromotionMap>(num_regs, kArenaAllocRegAlloc); 1359 1360 // Allow target code to add any special registers 1361 AdjustSpillMask(); 1362 1363 /* 1364 * Simple register promotion. Just do a static count of the uses 1365 * of Dalvik registers. Note that we examine the SSA names, but 1366 * count based on original Dalvik register name. Count refs 1367 * separately based on type in order to give allocation 1368 * preference to fp doubles - which must be allocated sequential 1369 * physical single fp registers starting with an even-numbered 1370 * reg. 1371 * TUNING: replace with linear scan once we have the ability 1372 * to describe register live ranges for GC. 1373 */ 1374 size_t core_reg_count_size = WideGPRsAreAliases() ? num_regs : num_regs * 2; 1375 size_t fp_reg_count_size = WideFPRsAreAliases() ? num_regs : num_regs * 2; 1376 RefCounts *core_regs = arena_->AllocArray<RefCounts>(core_reg_count_size, kArenaAllocRegAlloc); 1377 RefCounts *fp_regs = arena_->AllocArray<RefCounts>(fp_reg_count_size, kArenaAllocRegAlloc); 1378 // Set ssa names for original Dalvik registers 1379 for (int i = 0; i < num_regs; i++) { 1380 core_regs[i].s_reg = fp_regs[i].s_reg = i; 1381 } 1382 1383 // Duplicate in upper half to represent possible wide starting sregs. 1384 for (size_t i = num_regs; i < fp_reg_count_size; i++) { 1385 fp_regs[i].s_reg = fp_regs[i - num_regs].s_reg | STARTING_WIDE_SREG; 1386 } 1387 for (size_t i = num_regs; i < core_reg_count_size; i++) { 1388 core_regs[i].s_reg = core_regs[i - num_regs].s_reg | STARTING_WIDE_SREG; 1389 } 1390 1391 // Sum use counts of SSA regs by original Dalvik vreg. 1392 CountRefs(core_regs, fp_regs, num_regs); 1393 1394 // Sort the count arrays 1395 qsort(core_regs, core_reg_count_size, sizeof(RefCounts), SortCounts); 1396 qsort(fp_regs, fp_reg_count_size, sizeof(RefCounts), SortCounts); 1397 1398 if (cu_->verbose) { 1399 DumpCounts(core_regs, core_reg_count_size, "Core regs after sort"); 1400 DumpCounts(fp_regs, fp_reg_count_size, "Fp regs after sort"); 1401 } 1402 1403 if (!(cu_->disable_opt & (1 << kPromoteRegs))) { 1404 // Promote fp regs 1405 for (size_t i = 0; (i < fp_reg_count_size) && (fp_regs[i].count >= promotion_threshold); i++) { 1406 int low_sreg = fp_regs[i].s_reg & ~STARTING_WIDE_SREG; 1407 size_t p_map_idx = SRegToPMap(low_sreg); 1408 RegStorage reg = RegStorage::InvalidReg(); 1409 if (promotion_map_[p_map_idx].fp_location != kLocPhysReg) { 1410 // TODO: break out the Thumb2-specific code. 1411 if (cu_->instruction_set == kThumb2) { 1412 bool wide = fp_regs[i].s_reg & STARTING_WIDE_SREG; 1413 if (wide) { 1414 if (promotion_map_[p_map_idx + 1].fp_location != kLocPhysReg) { 1415 // Ignore result - if can't alloc double may still be able to alloc singles. 1416 AllocPreservedDouble(low_sreg); 1417 } 1418 // Continue regardless of success - might still be able to grab a single. 1419 continue; 1420 } else { 1421 reg = AllocPreservedSingle(low_sreg); 1422 } 1423 } else { 1424 reg = AllocPreservedFpReg(low_sreg); 1425 } 1426 if (!reg.Valid()) { 1427 break; // No more left 1428 } 1429 } 1430 } 1431 1432 // Promote core regs 1433 for (size_t i = 0; (i < core_reg_count_size) && 1434 (core_regs[i].count >= promotion_threshold); i++) { 1435 int low_sreg = core_regs[i].s_reg & ~STARTING_WIDE_SREG; 1436 size_t p_map_idx = SRegToPMap(low_sreg); 1437 if (promotion_map_[p_map_idx].core_location != kLocPhysReg) { 1438 RegStorage reg = AllocPreservedCoreReg(low_sreg); 1439 if (!reg.Valid()) { 1440 break; // No more left 1441 } 1442 } 1443 } 1444 } 1445 1446 // Now, update SSA names to new home locations 1447 for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) { 1448 RegLocation *curr = &mir_graph_->reg_location_[i]; 1449 int p_map_idx = SRegToPMap(curr->s_reg_low); 1450 int reg_num = curr->fp ? promotion_map_[p_map_idx].fp_reg : promotion_map_[p_map_idx].core_reg; 1451 bool wide = curr->wide || (cu_->target64 && curr->ref); 1452 RegStorage reg = RegStorage::InvalidReg(); 1453 if (curr->fp && promotion_map_[p_map_idx].fp_location == kLocPhysReg) { 1454 if (wide && cu_->instruction_set == kThumb2) { 1455 if (promotion_map_[p_map_idx + 1].fp_location == kLocPhysReg) { 1456 int high_reg = promotion_map_[p_map_idx+1].fp_reg; 1457 // TODO: move target-specific restrictions out of here. 1458 if (((reg_num & 0x1) == 0) && ((reg_num + 1) == high_reg)) { 1459 reg = RegStorage::FloatSolo64(RegStorage::RegNum(reg_num) >> 1); 1460 } 1461 } 1462 } else { 1463 reg = wide ? RegStorage::FloatSolo64(reg_num) : RegStorage::FloatSolo32(reg_num); 1464 } 1465 } else if (!curr->fp && promotion_map_[p_map_idx].core_location == kLocPhysReg) { 1466 if (wide && !cu_->target64) { 1467 if (promotion_map_[p_map_idx + 1].core_location == kLocPhysReg) { 1468 int high_reg = promotion_map_[p_map_idx+1].core_reg; 1469 reg = RegStorage(RegStorage::k64BitPair, reg_num, high_reg); 1470 } 1471 } else { 1472 reg = wide ? RegStorage::Solo64(reg_num) : RegStorage::Solo32(reg_num); 1473 } 1474 } 1475 if (reg.Valid()) { 1476 curr->reg = reg; 1477 curr->location = kLocPhysReg; 1478 curr->home = true; 1479 } 1480 } 1481 if (cu_->verbose) { 1482 DumpPromotionMap(); 1483 } 1484 } 1485 1486 /* Returns sp-relative offset in bytes for a VReg */ 1487 int Mir2Lir::VRegOffset(int v_reg) { 1488 const DexFile::CodeItem* code_item = mir_graph_->GetCurrentDexCompilationUnit()->GetCodeItem(); 1489 return StackVisitor::GetVRegOffsetFromQuickCode(code_item, core_spill_mask_, 1490 fp_spill_mask_, frame_size_, v_reg, 1491 cu_->instruction_set); 1492 } 1493 1494 /* Returns sp-relative offset in bytes for a SReg */ 1495 int Mir2Lir::SRegOffset(int s_reg) { 1496 return VRegOffset(mir_graph_->SRegToVReg(s_reg)); 1497 } 1498 1499 /* Mark register usage state and return long retloc */ 1500 RegLocation Mir2Lir::GetReturnWide(RegisterClass reg_class) { 1501 RegLocation res; 1502 switch (reg_class) { 1503 case kRefReg: LOG(FATAL); break; 1504 case kFPReg: res = LocCReturnDouble(); break; 1505 default: res = LocCReturnWide(); break; 1506 } 1507 Clobber(res.reg); 1508 LockTemp(res.reg); 1509 MarkWide(res.reg); 1510 CheckRegLocation(res); 1511 return res; 1512 } 1513 1514 RegLocation Mir2Lir::GetReturn(RegisterClass reg_class) { 1515 RegLocation res; 1516 switch (reg_class) { 1517 case kRefReg: res = LocCReturnRef(); break; 1518 case kFPReg: res = LocCReturnFloat(); break; 1519 default: res = LocCReturn(); break; 1520 } 1521 Clobber(res.reg); 1522 if (cu_->instruction_set == kMips || cu_->instruction_set == kMips64) { 1523 MarkInUse(res.reg); 1524 } else { 1525 LockTemp(res.reg); 1526 } 1527 CheckRegLocation(res); 1528 return res; 1529 } 1530 1531 void Mir2Lir::SimpleRegAlloc() { 1532 DoPromotion(); 1533 1534 if (cu_->verbose && !(cu_->disable_opt & (1 << kPromoteRegs))) { 1535 LOG(INFO) << "After Promotion"; 1536 mir_graph_->DumpRegLocTable(mir_graph_->reg_location_, mir_graph_->GetNumSSARegs()); 1537 } 1538 1539 /* Set the frame size */ 1540 frame_size_ = ComputeFrameSize(); 1541 } 1542 1543 /* 1544 * Get the "real" sreg number associated with an s_reg slot. In general, 1545 * s_reg values passed through codegen are the SSA names created by 1546 * dataflow analysis and refer to slot numbers in the mir_graph_->reg_location 1547 * array. However, renaming is accomplished by simply replacing RegLocation 1548 * entries in the reglocation[] array. Therefore, when location 1549 * records for operands are first created, we need to ask the locRecord 1550 * identified by the dataflow pass what it's new name is. 1551 */ 1552 int Mir2Lir::GetSRegHi(int lowSreg) { 1553 return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1; 1554 } 1555 1556 bool Mir2Lir::LiveOut(int s_reg) { 1557 UNUSED(s_reg); 1558 // For now. 1559 return true; 1560 } 1561 1562 } // namespace art 1563