1 /* 2 * Copyright (C) 2014 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 #ifndef ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_ 18 #define ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_ 19 20 #include <iostream> 21 22 #include "nodes.h" 23 24 namespace art { 25 26 class CodeGenerator; 27 class SsaLivenessAnalysis; 28 29 static constexpr int kNoRegister = -1; 30 31 class BlockInfo : public ArenaObject<kArenaAllocSsaLiveness> { 32 public: BlockInfo(ArenaAllocator * allocator,const HBasicBlock & block,size_t number_of_ssa_values)33 BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values) 34 : block_(block), 35 live_in_(allocator, number_of_ssa_values, false, kArenaAllocSsaLiveness), 36 live_out_(allocator, number_of_ssa_values, false, kArenaAllocSsaLiveness), 37 kill_(allocator, number_of_ssa_values, false, kArenaAllocSsaLiveness) { 38 UNUSED(block_); 39 live_in_.ClearAllBits(); 40 live_out_.ClearAllBits(); 41 kill_.ClearAllBits(); 42 } 43 44 private: 45 const HBasicBlock& block_; 46 ArenaBitVector live_in_; 47 ArenaBitVector live_out_; 48 ArenaBitVector kill_; 49 50 friend class SsaLivenessAnalysis; 51 52 DISALLOW_COPY_AND_ASSIGN(BlockInfo); 53 }; 54 55 /** 56 * A live range contains the start and end of a range where an instruction or a temporary 57 * is live. 58 */ 59 class LiveRange FINAL : public ArenaObject<kArenaAllocSsaLiveness> { 60 public: LiveRange(size_t start,size_t end,LiveRange * next)61 LiveRange(size_t start, size_t end, LiveRange* next) : start_(start), end_(end), next_(next) { 62 DCHECK_LT(start, end); 63 DCHECK(next_ == nullptr || next_->GetStart() > GetEnd()); 64 } 65 GetStart()66 size_t GetStart() const { return start_; } GetEnd()67 size_t GetEnd() const { return end_; } GetNext()68 LiveRange* GetNext() const { return next_; } 69 IntersectsWith(const LiveRange & other)70 bool IntersectsWith(const LiveRange& other) const { 71 return (start_ >= other.start_ && start_ < other.end_) 72 || (other.start_ >= start_ && other.start_ < end_); 73 } 74 IsBefore(const LiveRange & other)75 bool IsBefore(const LiveRange& other) const { 76 return end_ <= other.start_; 77 } 78 Dump(std::ostream & stream)79 void Dump(std::ostream& stream) const { 80 stream << "[" << start_ << "," << end_ << ")"; 81 } 82 Dup(ArenaAllocator * allocator)83 LiveRange* Dup(ArenaAllocator* allocator) const { 84 return new (allocator) LiveRange( 85 start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator)); 86 } 87 GetLastRange()88 LiveRange* GetLastRange() { 89 return next_ == nullptr ? this : next_->GetLastRange(); 90 } 91 92 private: 93 size_t start_; 94 size_t end_; 95 LiveRange* next_; 96 97 friend class LiveInterval; 98 99 DISALLOW_COPY_AND_ASSIGN(LiveRange); 100 }; 101 102 /** 103 * A use position represents a live interval use at a given position. 104 */ 105 class UsePosition : public ArenaObject<kArenaAllocSsaLiveness> { 106 public: UsePosition(HInstruction * user,size_t input_index,size_t position,UsePosition * next)107 UsePosition(HInstruction* user, size_t input_index, size_t position, UsePosition* next) 108 : user_(user), 109 input_index_(input_index), 110 position_(position), 111 next_(next) { 112 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition()); 113 } 114 UsePosition(size_t position)115 explicit UsePosition(size_t position) 116 : user_(nullptr), 117 input_index_(kNoInput), 118 position_(dchecked_integral_cast<uint32_t>(position)), 119 next_(nullptr) { 120 } 121 GetPosition()122 size_t GetPosition() const { return position_; } 123 GetNext()124 UsePosition* GetNext() const { return next_; } SetNext(UsePosition * next)125 void SetNext(UsePosition* next) { next_ = next; } 126 GetUser()127 HInstruction* GetUser() const { return user_; } 128 IsSynthesized()129 bool IsSynthesized() const { return user_ == nullptr; } 130 GetInputIndex()131 size_t GetInputIndex() const { return input_index_; } 132 Dump(std::ostream & stream)133 void Dump(std::ostream& stream) const { 134 stream << position_; 135 } 136 GetLoopInformation()137 HLoopInformation* GetLoopInformation() const { 138 return user_->GetBlock()->GetLoopInformation(); 139 } 140 Dup(ArenaAllocator * allocator)141 UsePosition* Dup(ArenaAllocator* allocator) const { 142 return new (allocator) UsePosition( 143 user_, input_index_, position_, 144 next_ == nullptr ? nullptr : next_->Dup(allocator)); 145 } 146 RequiresRegister()147 bool RequiresRegister() const { 148 if (IsSynthesized()) return false; 149 Location location = GetUser()->GetLocations()->InAt(GetInputIndex()); 150 return location.IsUnallocated() && location.RequiresRegisterKind(); 151 } 152 153 private: 154 static constexpr uint32_t kNoInput = static_cast<uint32_t>(-1); 155 156 HInstruction* const user_; 157 const size_t input_index_; 158 const size_t position_; 159 UsePosition* next_; 160 161 DISALLOW_COPY_AND_ASSIGN(UsePosition); 162 }; 163 164 /** 165 * An environment use position represents a live interval for environment use at a given position. 166 */ 167 class EnvUsePosition : public ArenaObject<kArenaAllocSsaLiveness> { 168 public: EnvUsePosition(HEnvironment * environment,size_t input_index,size_t position,EnvUsePosition * next)169 EnvUsePosition(HEnvironment* environment, 170 size_t input_index, 171 size_t position, 172 EnvUsePosition* next) 173 : environment_(environment), 174 input_index_(input_index), 175 position_(position), 176 next_(next) { 177 DCHECK(environment != nullptr); 178 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition()); 179 } 180 GetPosition()181 size_t GetPosition() const { return position_; } 182 GetNext()183 EnvUsePosition* GetNext() const { return next_; } SetNext(EnvUsePosition * next)184 void SetNext(EnvUsePosition* next) { next_ = next; } 185 GetEnvironment()186 HEnvironment* GetEnvironment() const { return environment_; } GetInputIndex()187 size_t GetInputIndex() const { return input_index_; } 188 Dump(std::ostream & stream)189 void Dump(std::ostream& stream) const { 190 stream << position_; 191 } 192 Dup(ArenaAllocator * allocator)193 EnvUsePosition* Dup(ArenaAllocator* allocator) const { 194 return new (allocator) EnvUsePosition( 195 environment_, input_index_, position_, 196 next_ == nullptr ? nullptr : next_->Dup(allocator)); 197 } 198 199 private: 200 HEnvironment* const environment_; 201 const size_t input_index_; 202 const size_t position_; 203 EnvUsePosition* next_; 204 205 DISALLOW_COPY_AND_ASSIGN(EnvUsePosition); 206 }; 207 208 class SafepointPosition : public ArenaObject<kArenaAllocSsaLiveness> { 209 public: SafepointPosition(HInstruction * instruction)210 explicit SafepointPosition(HInstruction* instruction) 211 : instruction_(instruction), 212 next_(nullptr) {} 213 SetNext(SafepointPosition * next)214 void SetNext(SafepointPosition* next) { 215 next_ = next; 216 } 217 GetPosition()218 size_t GetPosition() const { 219 return instruction_->GetLifetimePosition(); 220 } 221 GetNext()222 SafepointPosition* GetNext() const { 223 return next_; 224 } 225 GetLocations()226 LocationSummary* GetLocations() const { 227 return instruction_->GetLocations(); 228 } 229 GetInstruction()230 HInstruction* GetInstruction() const { 231 return instruction_; 232 } 233 234 private: 235 HInstruction* const instruction_; 236 SafepointPosition* next_; 237 238 DISALLOW_COPY_AND_ASSIGN(SafepointPosition); 239 }; 240 241 /** 242 * An interval is a list of disjoint live ranges where an instruction is live. 243 * Each instruction that has uses gets an interval. 244 */ 245 class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> { 246 public: 247 static LiveInterval* MakeInterval(ArenaAllocator* allocator, 248 Primitive::Type type, 249 HInstruction* instruction = nullptr) { 250 return new (allocator) LiveInterval(allocator, type, instruction); 251 } 252 MakeFixedInterval(ArenaAllocator * allocator,int reg,Primitive::Type type)253 static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) { 254 return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false); 255 } 256 MakeTempInterval(ArenaAllocator * allocator,Primitive::Type type)257 static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) { 258 return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true); 259 } 260 IsFixed()261 bool IsFixed() const { return is_fixed_; } IsTemp()262 bool IsTemp() const { return is_temp_; } 263 // This interval is the result of a split. IsSplit()264 bool IsSplit() const { return parent_ != this; } 265 AddTempUse(HInstruction * instruction,size_t temp_index)266 void AddTempUse(HInstruction* instruction, size_t temp_index) { 267 DCHECK(IsTemp()); 268 DCHECK(first_use_ == nullptr) << "A temporary can only have one user"; 269 DCHECK(first_env_use_ == nullptr) << "A temporary cannot have environment user"; 270 size_t position = instruction->GetLifetimePosition(); 271 first_use_ = new (allocator_) UsePosition( 272 instruction, temp_index, position, first_use_); 273 AddRange(position, position + 1); 274 } 275 276 // Record use of an input. The use will be recorded as an environment use if 277 // `environment` is not null and as register use otherwise. If `actual_user` 278 // is specified, the use will be recorded at `actual_user`'s lifetime position. 279 void AddUse(HInstruction* instruction, 280 HEnvironment* environment, 281 size_t input_index, 282 HInstruction* actual_user = nullptr, 283 bool keep_alive = false) { 284 bool is_environment = (environment != nullptr); 285 LocationSummary* locations = instruction->GetLocations(); 286 if (actual_user == nullptr) { 287 actual_user = instruction; 288 } 289 290 // Set the use within the instruction. 291 size_t position = actual_user->GetLifetimePosition() + 1; 292 if (!is_environment) { 293 if (locations->IsFixedInput(input_index) || locations->OutputUsesSameAs(input_index)) { 294 // For fixed inputs and output same as input, the register allocator 295 // requires to have inputs die at the instruction, so that input moves use the 296 // location of the input just before that instruction (and not potential moves due 297 // to splitting). 298 DCHECK_EQ(instruction, actual_user); 299 position = actual_user->GetLifetimePosition(); 300 } else if (!locations->InAt(input_index).IsValid()) { 301 return; 302 } 303 } 304 305 if (!is_environment && instruction->IsInLoop()) { 306 AddBackEdgeUses(*instruction->GetBlock()); 307 } 308 309 if ((first_use_ != nullptr) 310 && (first_use_->GetUser() == actual_user) 311 && (first_use_->GetPosition() < position)) { 312 // The user uses the instruction multiple times, and one use dies before the other. 313 // We update the use list so that the latter is first. 314 DCHECK(!is_environment); 315 UsePosition* cursor = first_use_; 316 while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) { 317 cursor = cursor->GetNext(); 318 } 319 DCHECK(first_use_->GetPosition() + 1 == position); 320 UsePosition* new_use = new (allocator_) UsePosition( 321 instruction, input_index, position, cursor->GetNext()); 322 cursor->SetNext(new_use); 323 if (first_range_->GetEnd() == first_use_->GetPosition()) { 324 first_range_->end_ = position; 325 } 326 return; 327 } 328 329 if (is_environment) { 330 first_env_use_ = new (allocator_) EnvUsePosition( 331 environment, input_index, position, first_env_use_); 332 } else { 333 first_use_ = new (allocator_) UsePosition( 334 instruction, input_index, position, first_use_); 335 } 336 337 if (is_environment && !keep_alive) { 338 // If this environment use does not keep the instruction live, it does not 339 // affect the live range of that instruction. 340 return; 341 } 342 343 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart(); 344 if (first_range_ == nullptr) { 345 // First time we see a use of that interval. 346 first_range_ = last_range_ = range_search_start_ = 347 new (allocator_) LiveRange(start_block_position, position, nullptr); 348 } else if (first_range_->GetStart() == start_block_position) { 349 // There is a use later in the same block or in a following block. 350 // Note that in such a case, `AddRange` for the whole blocks has been called 351 // before arriving in this method, and this is the reason the start of 352 // `first_range_` is before the given `position`. 353 DCHECK_LE(position, first_range_->GetEnd()); 354 } else { 355 DCHECK(first_range_->GetStart() > position); 356 // There is a hole in the interval. Create a new range. 357 // Note that the start of `first_range_` can be equal to `end`: two blocks 358 // having adjacent lifetime positions are not necessarily 359 // predecessor/successor. When two blocks are predecessor/successor, the 360 // liveness algorithm has called `AddRange` before arriving in this method, 361 // and the check line 205 would succeed. 362 first_range_ = range_search_start_ = 363 new (allocator_) LiveRange(start_block_position, position, first_range_); 364 } 365 } 366 AddPhiUse(HInstruction * instruction,size_t input_index,HBasicBlock * block)367 void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) { 368 DCHECK(instruction->IsPhi()); 369 if (block->IsInLoop()) { 370 AddBackEdgeUses(*block); 371 } 372 first_use_ = new (allocator_) UsePosition( 373 instruction, input_index, block->GetLifetimeEnd(), first_use_); 374 } 375 AddRange(size_t start,size_t end)376 ALWAYS_INLINE void AddRange(size_t start, size_t end) { 377 if (first_range_ == nullptr) { 378 first_range_ = last_range_ = range_search_start_ = 379 new (allocator_) LiveRange(start, end, first_range_); 380 } else if (first_range_->GetStart() == end) { 381 // There is a use in the following block. 382 first_range_->start_ = start; 383 } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) { 384 DCHECK(is_fixed_); 385 } else { 386 DCHECK_GT(first_range_->GetStart(), end); 387 // There is a hole in the interval. Create a new range. 388 first_range_ = range_search_start_ = new (allocator_) LiveRange(start, end, first_range_); 389 } 390 } 391 AddLoopRange(size_t start,size_t end)392 void AddLoopRange(size_t start, size_t end) { 393 DCHECK(first_range_ != nullptr); 394 DCHECK_LE(start, first_range_->GetStart()); 395 // Find the range that covers the positions after the loop. 396 LiveRange* after_loop = first_range_; 397 LiveRange* last_in_loop = nullptr; 398 while (after_loop != nullptr && after_loop->GetEnd() < end) { 399 DCHECK_LE(start, after_loop->GetStart()); 400 last_in_loop = after_loop; 401 after_loop = after_loop->GetNext(); 402 } 403 if (after_loop == nullptr) { 404 // Uses are only in the loop. 405 first_range_ = last_range_ = range_search_start_ = 406 new (allocator_) LiveRange(start, end, nullptr); 407 } else if (after_loop->GetStart() <= end) { 408 first_range_ = range_search_start_ = after_loop; 409 // There are uses after the loop. 410 first_range_->start_ = start; 411 } else { 412 // The use after the loop is after a lifetime hole. 413 DCHECK(last_in_loop != nullptr); 414 first_range_ = range_search_start_ = last_in_loop; 415 first_range_->start_ = start; 416 first_range_->end_ = end; 417 } 418 } 419 HasSpillSlot()420 bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; } SetSpillSlot(int slot)421 void SetSpillSlot(int slot) { 422 DCHECK(!is_fixed_); 423 DCHECK(!is_temp_); 424 spill_slot_ = slot; 425 } GetSpillSlot()426 int GetSpillSlot() const { return spill_slot_; } 427 SetFrom(size_t from)428 void SetFrom(size_t from) { 429 if (first_range_ != nullptr) { 430 first_range_->start_ = from; 431 } else { 432 // Instruction without uses. 433 DCHECK(first_use_ == nullptr); 434 DCHECK(from == defined_by_->GetLifetimePosition()); 435 first_range_ = last_range_ = range_search_start_ = 436 new (allocator_) LiveRange(from, from + 2, nullptr); 437 } 438 } 439 GetParent()440 LiveInterval* GetParent() const { return parent_; } 441 442 // Returns whether this interval is the parent interval, that is, the interval 443 // that starts where the HInstruction is defined. IsParent()444 bool IsParent() const { return parent_ == this; } 445 GetFirstRange()446 LiveRange* GetFirstRange() const { return first_range_; } GetLastRange()447 LiveRange* GetLastRange() const { return last_range_; } 448 GetRegister()449 int GetRegister() const { return register_; } SetRegister(int reg)450 void SetRegister(int reg) { register_ = reg; } ClearRegister()451 void ClearRegister() { register_ = kNoRegister; } HasRegister()452 bool HasRegister() const { return register_ != kNoRegister; } 453 IsDeadAt(size_t position)454 bool IsDeadAt(size_t position) const { 455 return GetEnd() <= position; 456 } 457 IsDefinedAt(size_t position)458 bool IsDefinedAt(size_t position) const { 459 return GetStart() <= position && !IsDeadAt(position); 460 } 461 462 // Returns true if the interval contains a LiveRange covering `position`. 463 // The range at or immediately after the current position of linear scan 464 // is cached for better performance. If `position` can be smaller than 465 // that, CoversSlow should be used instead. Covers(size_t position)466 bool Covers(size_t position) { 467 LiveRange* candidate = FindRangeAtOrAfter(position, range_search_start_); 468 range_search_start_ = candidate; 469 return (candidate != nullptr && candidate->GetStart() <= position); 470 } 471 472 // Same as Covers but always tests all ranges. CoversSlow(size_t position)473 bool CoversSlow(size_t position) const { 474 LiveRange* candidate = FindRangeAtOrAfter(position, first_range_); 475 return candidate != nullptr && candidate->GetStart() <= position; 476 } 477 478 // Returns the first intersection of this interval with `current`, which 479 // must be the interval currently being allocated by linear scan. FirstIntersectionWith(LiveInterval * current)480 size_t FirstIntersectionWith(LiveInterval* current) const { 481 // Find the first range after the start of `current`. We use the search 482 // cache to improve performance. 483 DCHECK(GetStart() <= current->GetStart() || IsFixed()); 484 LiveRange* other_range = current->first_range_; 485 LiveRange* my_range = FindRangeAtOrAfter(other_range->GetStart(), range_search_start_); 486 if (my_range == nullptr) { 487 return kNoLifetime; 488 } 489 490 // Advance both intervals and find the first matching range start in 491 // this interval. 492 do { 493 if (my_range->IsBefore(*other_range)) { 494 my_range = my_range->GetNext(); 495 if (my_range == nullptr) { 496 return kNoLifetime; 497 } 498 } else if (other_range->IsBefore(*my_range)) { 499 other_range = other_range->GetNext(); 500 if (other_range == nullptr) { 501 return kNoLifetime; 502 } 503 } else { 504 DCHECK(my_range->IntersectsWith(*other_range)); 505 return std::max(my_range->GetStart(), other_range->GetStart()); 506 } 507 } while (true); 508 } 509 GetStart()510 size_t GetStart() const { 511 return first_range_->GetStart(); 512 } 513 GetEnd()514 size_t GetEnd() const { 515 return last_range_->GetEnd(); 516 } 517 GetLength()518 size_t GetLength() const { 519 return GetEnd() - GetStart(); 520 } 521 FirstRegisterUseAfter(size_t position)522 size_t FirstRegisterUseAfter(size_t position) const { 523 if (is_temp_) { 524 return position == GetStart() ? position : kNoLifetime; 525 } 526 527 if (IsDefiningPosition(position) && DefinitionRequiresRegister()) { 528 return position; 529 } 530 531 UsePosition* use = first_use_; 532 size_t end = GetEnd(); 533 while (use != nullptr && use->GetPosition() <= end) { 534 size_t use_position = use->GetPosition(); 535 if (use_position > position) { 536 if (use->RequiresRegister()) { 537 return use_position; 538 } 539 } 540 use = use->GetNext(); 541 } 542 return kNoLifetime; 543 } 544 545 // Returns the location of the first register use for this live interval, 546 // including a register definition if applicable. FirstRegisterUse()547 size_t FirstRegisterUse() const { 548 return FirstRegisterUseAfter(GetStart()); 549 } 550 551 // Whether the interval requires a register rather than a stack location. 552 // If needed for performance, this could be cached. RequiresRegister()553 bool RequiresRegister() const { 554 return !HasRegister() && FirstRegisterUse() != kNoLifetime; 555 } 556 FirstUseAfter(size_t position)557 size_t FirstUseAfter(size_t position) const { 558 if (is_temp_) { 559 return position == GetStart() ? position : kNoLifetime; 560 } 561 562 if (IsDefiningPosition(position)) { 563 DCHECK(defined_by_->GetLocations()->Out().IsValid()); 564 return position; 565 } 566 567 UsePosition* use = first_use_; 568 size_t end = GetEnd(); 569 while (use != nullptr && use->GetPosition() <= end) { 570 size_t use_position = use->GetPosition(); 571 if (use_position > position) { 572 return use_position; 573 } 574 use = use->GetNext(); 575 } 576 return kNoLifetime; 577 } 578 GetFirstUse()579 UsePosition* GetFirstUse() const { 580 return first_use_; 581 } 582 GetFirstEnvironmentUse()583 EnvUsePosition* GetFirstEnvironmentUse() const { 584 return first_env_use_; 585 } 586 GetType()587 Primitive::Type GetType() const { 588 return type_; 589 } 590 GetDefinedBy()591 HInstruction* GetDefinedBy() const { 592 return defined_by_; 593 } 594 HasWillCallSafepoint()595 bool HasWillCallSafepoint() const { 596 for (SafepointPosition* safepoint = first_safepoint_; 597 safepoint != nullptr; 598 safepoint = safepoint->GetNext()) { 599 if (safepoint->GetLocations()->WillCall()) return true; 600 } 601 return false; 602 } 603 FindSafepointJustBefore(size_t position)604 SafepointPosition* FindSafepointJustBefore(size_t position) const { 605 for (SafepointPosition* safepoint = first_safepoint_, *previous = nullptr; 606 safepoint != nullptr; 607 previous = safepoint, safepoint = safepoint->GetNext()) { 608 if (safepoint->GetPosition() >= position) return previous; 609 } 610 return last_safepoint_; 611 } 612 613 /** 614 * Split this interval at `position`. This interval is changed to: 615 * [start ... position). 616 * 617 * The new interval covers: 618 * [position ... end) 619 */ SplitAt(size_t position)620 LiveInterval* SplitAt(size_t position) { 621 DCHECK(!is_temp_); 622 DCHECK(!is_fixed_); 623 DCHECK_GT(position, GetStart()); 624 625 if (GetEnd() <= position) { 626 // This range dies before `position`, no need to split. 627 return nullptr; 628 } 629 630 LiveInterval* new_interval = new (allocator_) LiveInterval(allocator_, type_); 631 SafepointPosition* new_last_safepoint = FindSafepointJustBefore(position); 632 if (new_last_safepoint == nullptr) { 633 new_interval->first_safepoint_ = first_safepoint_; 634 new_interval->last_safepoint_ = last_safepoint_; 635 first_safepoint_ = last_safepoint_ = nullptr; 636 } else if (last_safepoint_ != new_last_safepoint) { 637 new_interval->last_safepoint_ = last_safepoint_; 638 new_interval->first_safepoint_ = new_last_safepoint->GetNext(); 639 DCHECK(new_interval->first_safepoint_ != nullptr); 640 last_safepoint_ = new_last_safepoint; 641 last_safepoint_->SetNext(nullptr); 642 } 643 644 new_interval->next_sibling_ = next_sibling_; 645 next_sibling_ = new_interval; 646 new_interval->parent_ = parent_; 647 648 new_interval->first_use_ = first_use_; 649 new_interval->first_env_use_ = first_env_use_; 650 LiveRange* current = first_range_; 651 LiveRange* previous = nullptr; 652 // Iterate over the ranges, and either find a range that covers this position, or 653 // two ranges in between this position (that is, the position is in a lifetime hole). 654 do { 655 if (position >= current->GetEnd()) { 656 // Move to next range. 657 previous = current; 658 current = current->next_; 659 } else if (position <= current->GetStart()) { 660 // If the previous range did not cover this position, we know position is in 661 // a lifetime hole. We can just break the first_range_ and last_range_ links 662 // and return the new interval. 663 DCHECK(previous != nullptr); 664 DCHECK(current != first_range_); 665 new_interval->last_range_ = last_range_; 666 last_range_ = previous; 667 previous->next_ = nullptr; 668 new_interval->first_range_ = current; 669 if (range_search_start_ != nullptr && range_search_start_->GetEnd() >= current->GetEnd()) { 670 // Search start point is inside `new_interval`. Change it to null 671 // (i.e. the end of the interval) in the original interval. 672 range_search_start_ = nullptr; 673 } 674 new_interval->range_search_start_ = new_interval->first_range_; 675 return new_interval; 676 } else { 677 // This range covers position. We create a new last_range_ for this interval 678 // that covers last_range_->Start() and position. We also shorten the current 679 // range and make it the first range of the new interval. 680 DCHECK(position < current->GetEnd() && position > current->GetStart()); 681 new_interval->last_range_ = last_range_; 682 last_range_ = new (allocator_) LiveRange(current->start_, position, nullptr); 683 if (previous != nullptr) { 684 previous->next_ = last_range_; 685 } else { 686 first_range_ = last_range_; 687 } 688 new_interval->first_range_ = current; 689 current->start_ = position; 690 if (range_search_start_ != nullptr && range_search_start_->GetEnd() >= current->GetEnd()) { 691 // Search start point is inside `new_interval`. Change it to `last_range` 692 // in the original interval. This is conservative but always correct. 693 range_search_start_ = last_range_; 694 } 695 new_interval->range_search_start_ = new_interval->first_range_; 696 return new_interval; 697 } 698 } while (current != nullptr); 699 700 LOG(FATAL) << "Unreachable"; 701 return nullptr; 702 } 703 StartsBeforeOrAt(LiveInterval * other)704 bool StartsBeforeOrAt(LiveInterval* other) const { 705 return GetStart() <= other->GetStart(); 706 } 707 StartsAfter(LiveInterval * other)708 bool StartsAfter(LiveInterval* other) const { 709 return GetStart() > other->GetStart(); 710 } 711 Dump(std::ostream & stream)712 void Dump(std::ostream& stream) const { 713 stream << "ranges: { "; 714 LiveRange* current = first_range_; 715 while (current != nullptr) { 716 current->Dump(stream); 717 stream << " "; 718 current = current->GetNext(); 719 } 720 stream << "}, uses: { "; 721 const UsePosition* use = first_use_; 722 if (use != nullptr) { 723 do { 724 use->Dump(stream); 725 stream << " "; 726 } while ((use = use->GetNext()) != nullptr); 727 } 728 stream << "}, { "; 729 const EnvUsePosition* env_use = first_env_use_; 730 if (env_use != nullptr) { 731 do { 732 env_use->Dump(stream); 733 stream << " "; 734 } while ((env_use = env_use->GetNext()) != nullptr); 735 } 736 stream << "}"; 737 stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit(); 738 stream << " is_low: " << IsLowInterval(); 739 stream << " is_high: " << IsHighInterval(); 740 } 741 742 // Same as Dump, but adds context such as the instruction defining this interval, and 743 // the register currently assigned to this interval. 744 void DumpWithContext(std::ostream& stream, const CodeGenerator& codegen) const; 745 GetNextSibling()746 LiveInterval* GetNextSibling() const { return next_sibling_; } GetLastSibling()747 LiveInterval* GetLastSibling() { 748 LiveInterval* result = this; 749 while (result->next_sibling_ != nullptr) { 750 result = result->next_sibling_; 751 } 752 return result; 753 } 754 755 // Returns the first register hint that is at least free before 756 // the value contained in `free_until`. If none is found, returns 757 // `kNoRegister`. 758 int FindFirstRegisterHint(size_t* free_until, const SsaLivenessAnalysis& liveness) const; 759 760 // If there is enough at the definition site to find a register (for example 761 // it uses the same input as the first input), returns the register as a hint. 762 // Returns kNoRegister otherwise. 763 int FindHintAtDefinition() const; 764 765 // Returns the number of required spilling slots (measured as a multiple of the 766 // Dex virtual register size `kVRegSize`). 767 size_t NumberOfSpillSlotsNeeded() const; 768 IsFloatingPoint()769 bool IsFloatingPoint() const { 770 return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble; 771 } 772 773 // Converts the location of the interval to a `Location` object. 774 Location ToLocation() const; 775 776 // Returns the location of the interval following its siblings at `position`. 777 Location GetLocationAt(size_t position); 778 779 // Finds the sibling that is defined at `position`. 780 LiveInterval* GetSiblingAt(size_t position); 781 782 // Returns whether `other` and `this` share the same kind of register. 783 bool SameRegisterKind(Location other) const; SameRegisterKind(const LiveInterval & other)784 bool SameRegisterKind(const LiveInterval& other) const { 785 return IsFloatingPoint() == other.IsFloatingPoint(); 786 } 787 HasHighInterval()788 bool HasHighInterval() const { 789 return IsLowInterval(); 790 } 791 HasLowInterval()792 bool HasLowInterval() const { 793 return IsHighInterval(); 794 } 795 GetLowInterval()796 LiveInterval* GetLowInterval() const { 797 DCHECK(HasLowInterval()); 798 return high_or_low_interval_; 799 } 800 GetHighInterval()801 LiveInterval* GetHighInterval() const { 802 DCHECK(HasHighInterval()); 803 return high_or_low_interval_; 804 } 805 IsHighInterval()806 bool IsHighInterval() const { 807 return GetParent()->is_high_interval_; 808 } 809 IsLowInterval()810 bool IsLowInterval() const { 811 return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr); 812 } 813 SetLowInterval(LiveInterval * low)814 void SetLowInterval(LiveInterval* low) { 815 DCHECK(IsHighInterval()); 816 high_or_low_interval_ = low; 817 } 818 SetHighInterval(LiveInterval * high)819 void SetHighInterval(LiveInterval* high) { 820 DCHECK(IsLowInterval()); 821 high_or_low_interval_ = high; 822 } 823 824 void AddHighInterval(bool is_temp = false) { 825 DCHECK(IsParent()); 826 DCHECK(!HasHighInterval()); 827 DCHECK(!HasLowInterval()); 828 high_or_low_interval_ = new (allocator_) LiveInterval( 829 allocator_, type_, defined_by_, false, kNoRegister, is_temp, true); 830 high_or_low_interval_->high_or_low_interval_ = this; 831 if (first_range_ != nullptr) { 832 high_or_low_interval_->first_range_ = first_range_->Dup(allocator_); 833 high_or_low_interval_->last_range_ = high_or_low_interval_->first_range_->GetLastRange(); 834 high_or_low_interval_->range_search_start_ = high_or_low_interval_->first_range_; 835 } 836 if (first_use_ != nullptr) { 837 high_or_low_interval_->first_use_ = first_use_->Dup(allocator_); 838 } 839 840 if (first_env_use_ != nullptr) { 841 high_or_low_interval_->first_env_use_ = first_env_use_->Dup(allocator_); 842 } 843 } 844 845 // Returns whether an interval, when it is non-split, is using 846 // the same register of one of its input. IsUsingInputRegister()847 bool IsUsingInputRegister() const { 848 CHECK(kIsDebugBuild) << "Function should be used only for DCHECKs"; 849 if (defined_by_ != nullptr && !IsSplit()) { 850 for (const HInstruction* input : defined_by_->GetInputs()) { 851 LiveInterval* interval = input->GetLiveInterval(); 852 853 // Find the interval that covers `defined_by`_. Calls to this function 854 // are made outside the linear scan, hence we need to use CoversSlow. 855 while (interval != nullptr && !interval->CoversSlow(defined_by_->GetLifetimePosition())) { 856 interval = interval->GetNextSibling(); 857 } 858 859 // Check if both intervals have the same register of the same kind. 860 if (interval != nullptr 861 && interval->SameRegisterKind(*this) 862 && interval->GetRegister() == GetRegister()) { 863 return true; 864 } 865 } 866 } 867 return false; 868 } 869 870 // Returns whether an interval, when it is non-split, can safely use 871 // the same register of one of its input. Note that this method requires 872 // IsUsingInputRegister() to be true. CanUseInputRegister()873 bool CanUseInputRegister() const { 874 CHECK(kIsDebugBuild) << "Function should be used only for DCHECKs"; 875 DCHECK(IsUsingInputRegister()); 876 if (defined_by_ != nullptr && !IsSplit()) { 877 LocationSummary* locations = defined_by_->GetLocations(); 878 if (locations->OutputCanOverlapWithInputs()) { 879 return false; 880 } 881 for (const HInstruction* input : defined_by_->GetInputs()) { 882 LiveInterval* interval = input->GetLiveInterval(); 883 884 // Find the interval that covers `defined_by`_. Calls to this function 885 // are made outside the linear scan, hence we need to use CoversSlow. 886 while (interval != nullptr && !interval->CoversSlow(defined_by_->GetLifetimePosition())) { 887 interval = interval->GetNextSibling(); 888 } 889 890 if (interval != nullptr 891 && interval->SameRegisterKind(*this) 892 && interval->GetRegister() == GetRegister()) { 893 // We found the input that has the same register. Check if it is live after 894 // `defined_by`_. 895 return !interval->CoversSlow(defined_by_->GetLifetimePosition() + 1); 896 } 897 } 898 } 899 LOG(FATAL) << "Unreachable"; 900 UNREACHABLE(); 901 } 902 AddSafepoint(HInstruction * instruction)903 void AddSafepoint(HInstruction* instruction) { 904 SafepointPosition* safepoint = new (allocator_) SafepointPosition(instruction); 905 if (first_safepoint_ == nullptr) { 906 first_safepoint_ = last_safepoint_ = safepoint; 907 } else { 908 DCHECK_LT(last_safepoint_->GetPosition(), safepoint->GetPosition()); 909 last_safepoint_->SetNext(safepoint); 910 last_safepoint_ = safepoint; 911 } 912 } 913 GetFirstSafepoint()914 SafepointPosition* GetFirstSafepoint() const { 915 return first_safepoint_; 916 } 917 918 // Resets the starting point for range-searching queries to the first range. 919 // Intervals must be reset prior to starting a new linear scan over them. ResetSearchCache()920 void ResetSearchCache() { 921 range_search_start_ = first_range_; 922 } 923 DefinitionRequiresRegister()924 bool DefinitionRequiresRegister() const { 925 DCHECK(IsParent()); 926 LocationSummary* locations = defined_by_->GetLocations(); 927 Location location = locations->Out(); 928 // This interval is the first interval of the instruction. If the output 929 // of the instruction requires a register, we return the position of that instruction 930 // as the first register use. 931 if (location.IsUnallocated()) { 932 if ((location.GetPolicy() == Location::kRequiresRegister) 933 || (location.GetPolicy() == Location::kSameAsFirstInput 934 && (locations->InAt(0).IsRegister() 935 || locations->InAt(0).IsRegisterPair() 936 || locations->InAt(0).GetPolicy() == Location::kRequiresRegister))) { 937 return true; 938 } else if ((location.GetPolicy() == Location::kRequiresFpuRegister) 939 || (location.GetPolicy() == Location::kSameAsFirstInput 940 && (locations->InAt(0).IsFpuRegister() 941 || locations->InAt(0).IsFpuRegisterPair() 942 || locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister))) { 943 return true; 944 } 945 } else if (location.IsRegister() || location.IsRegisterPair()) { 946 return true; 947 } 948 return false; 949 } 950 951 private: 952 LiveInterval(ArenaAllocator* allocator, 953 Primitive::Type type, 954 HInstruction* defined_by = nullptr, 955 bool is_fixed = false, 956 int reg = kNoRegister, 957 bool is_temp = false, 958 bool is_high_interval = false) allocator_(allocator)959 : allocator_(allocator), 960 first_range_(nullptr), 961 last_range_(nullptr), 962 range_search_start_(nullptr), 963 first_safepoint_(nullptr), 964 last_safepoint_(nullptr), 965 first_use_(nullptr), 966 first_env_use_(nullptr), 967 type_(type), 968 next_sibling_(nullptr), 969 parent_(this), 970 register_(reg), 971 spill_slot_(kNoSpillSlot), 972 is_fixed_(is_fixed), 973 is_temp_(is_temp), 974 is_high_interval_(is_high_interval), 975 high_or_low_interval_(nullptr), 976 defined_by_(defined_by) {} 977 978 // Searches for a LiveRange that either covers the given position or is the 979 // first next LiveRange. Returns null if no such LiveRange exists. Ranges 980 // known to end before `position` can be skipped with `search_start`. FindRangeAtOrAfter(size_t position,LiveRange * search_start)981 LiveRange* FindRangeAtOrAfter(size_t position, LiveRange* search_start) const { 982 if (kIsDebugBuild) { 983 if (search_start != first_range_) { 984 // If we are not searching the entire list of ranges, make sure we do 985 // not skip the range we are searching for. 986 if (search_start == nullptr) { 987 DCHECK(IsDeadAt(position)); 988 } else if (search_start->GetStart() > position) { 989 DCHECK_EQ(search_start, FindRangeAtOrAfter(position, first_range_)); 990 } 991 } 992 } 993 994 LiveRange* range; 995 for (range = search_start; 996 range != nullptr && range->GetEnd() <= position; 997 range = range->GetNext()) { 998 continue; 999 } 1000 return range; 1001 } 1002 IsDefiningPosition(size_t position)1003 bool IsDefiningPosition(size_t position) const { 1004 return IsParent() && (position == GetStart()); 1005 } 1006 HasSynthesizeUseAt(size_t position)1007 bool HasSynthesizeUseAt(size_t position) const { 1008 UsePosition* use = first_use_; 1009 while (use != nullptr) { 1010 size_t use_position = use->GetPosition(); 1011 if ((use_position == position) && use->IsSynthesized()) { 1012 return true; 1013 } 1014 if (use_position > position) break; 1015 use = use->GetNext(); 1016 } 1017 return false; 1018 } 1019 AddBackEdgeUses(const HBasicBlock & block_at_use)1020 void AddBackEdgeUses(const HBasicBlock& block_at_use) { 1021 DCHECK(block_at_use.IsInLoop()); 1022 if (block_at_use.GetGraph()->HasIrreducibleLoops()) { 1023 // Linear order may not be well formed when irreducible loops are present, 1024 // i.e. loop blocks may not be adjacent and a back edge may not be last, 1025 // which violates assumptions made in this method. 1026 return; 1027 } 1028 1029 // Add synthesized uses at the back edge of loops to help the register allocator. 1030 // Note that this method is called in decreasing liveness order, to faciliate adding 1031 // uses at the head of the `first_use_` linked list. Because below 1032 // we iterate from inner-most to outer-most, which is in increasing liveness order, 1033 // we need to take extra care of how the `first_use_` linked list is being updated. 1034 UsePosition* first_in_new_list = nullptr; 1035 UsePosition* last_in_new_list = nullptr; 1036 for (HLoopInformationOutwardIterator it(block_at_use); 1037 !it.Done(); 1038 it.Advance()) { 1039 HLoopInformation* current = it.Current(); 1040 if (GetDefinedBy()->GetLifetimePosition() >= current->GetHeader()->GetLifetimeStart()) { 1041 // This interval is defined in the loop. We can stop going outward. 1042 break; 1043 } 1044 1045 // We're only adding a synthesized use at the last back edge. Adding syntehsized uses on 1046 // all back edges is not necessary: anything used in the loop will have its use at the 1047 // last back edge. If we want branches in a loop to have better register allocation than 1048 // another branch, then it is the linear order we should change. 1049 size_t back_edge_use_position = current->GetLifetimeEnd(); 1050 if ((first_use_ != nullptr) && (first_use_->GetPosition() <= back_edge_use_position)) { 1051 // There was a use already seen in this loop. Therefore the previous call to `AddUse` 1052 // already inserted the backedge use. We can stop going outward. 1053 DCHECK(HasSynthesizeUseAt(back_edge_use_position)); 1054 break; 1055 } 1056 1057 DCHECK(last_in_new_list == nullptr || 1058 back_edge_use_position > last_in_new_list->GetPosition()); 1059 1060 UsePosition* new_use = new (allocator_) UsePosition(back_edge_use_position); 1061 1062 if (last_in_new_list != nullptr) { 1063 // Going outward. The latest created use needs to point to the new use. 1064 last_in_new_list->SetNext(new_use); 1065 } else { 1066 // This is the inner-most loop. 1067 DCHECK_EQ(current, block_at_use.GetLoopInformation()); 1068 first_in_new_list = new_use; 1069 } 1070 last_in_new_list = new_use; 1071 } 1072 // Link the newly created linked list with `first_use_`. 1073 if (last_in_new_list != nullptr) { 1074 last_in_new_list->SetNext(first_use_); 1075 first_use_ = first_in_new_list; 1076 } 1077 } 1078 1079 ArenaAllocator* const allocator_; 1080 1081 // Ranges of this interval. We need a quick access to the last range to test 1082 // for liveness (see `IsDeadAt`). 1083 LiveRange* first_range_; 1084 LiveRange* last_range_; 1085 1086 // The first range at or after the current position of a linear scan. It is 1087 // used to optimize range-searching queries. 1088 LiveRange* range_search_start_; 1089 1090 // Safepoints where this interval is live. 1091 SafepointPosition* first_safepoint_; 1092 SafepointPosition* last_safepoint_; 1093 1094 // Uses of this interval. Note that this linked list is shared amongst siblings. 1095 UsePosition* first_use_; 1096 EnvUsePosition* first_env_use_; 1097 1098 // The instruction type this interval corresponds to. 1099 const Primitive::Type type_; 1100 1101 // Live interval that is the result of a split. 1102 LiveInterval* next_sibling_; 1103 1104 // The first interval from which split intervals come from. 1105 LiveInterval* parent_; 1106 1107 // The register allocated to this interval. 1108 int register_; 1109 1110 // The spill slot allocated to this interval. 1111 int spill_slot_; 1112 1113 // Whether the interval is for a fixed register. 1114 const bool is_fixed_; 1115 1116 // Whether the interval is for a temporary. 1117 const bool is_temp_; 1118 1119 // Whether this interval is a synthesized interval for register pair. 1120 const bool is_high_interval_; 1121 1122 // If this interval needs a register pair, the high or low equivalent. 1123 // `is_high_interval_` tells whether this holds the low or the high. 1124 LiveInterval* high_or_low_interval_; 1125 1126 // The instruction represented by this interval. 1127 HInstruction* const defined_by_; 1128 1129 static constexpr int kNoRegister = -1; 1130 static constexpr int kNoSpillSlot = -1; 1131 1132 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive); 1133 1134 DISALLOW_COPY_AND_ASSIGN(LiveInterval); 1135 }; 1136 1137 /** 1138 * Analysis that computes the liveness of instructions: 1139 * 1140 * (a) Non-environment uses of an instruction always make 1141 * the instruction live. 1142 * (b) Environment uses of an instruction whose type is 1143 * object (that is, non-primitive), make the instruction live. 1144 * This is due to having to keep alive objects that have 1145 * finalizers deleting native objects. 1146 * (c) When the graph has the debuggable property, environment uses 1147 * of an instruction that has a primitive type make the instruction live. 1148 * If the graph does not have the debuggable property, the environment 1149 * use has no effect, and may get a 'none' value after register allocation. 1150 * 1151 * (b) and (c) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment. 1152 */ 1153 class SsaLivenessAnalysis : public ValueObject { 1154 public: SsaLivenessAnalysis(HGraph * graph,CodeGenerator * codegen)1155 SsaLivenessAnalysis(HGraph* graph, CodeGenerator* codegen) 1156 : graph_(graph), 1157 codegen_(codegen), 1158 block_infos_(graph->GetBlocks().size(), 1159 nullptr, 1160 graph->GetArena()->Adapter(kArenaAllocSsaLiveness)), 1161 instructions_from_ssa_index_(graph->GetArena()->Adapter(kArenaAllocSsaLiveness)), 1162 instructions_from_lifetime_position_(graph->GetArena()->Adapter(kArenaAllocSsaLiveness)), 1163 number_of_ssa_values_(0) { 1164 } 1165 1166 void Analyze(); 1167 GetLiveInSet(const HBasicBlock & block)1168 BitVector* GetLiveInSet(const HBasicBlock& block) const { 1169 return &block_infos_[block.GetBlockId()]->live_in_; 1170 } 1171 GetLiveOutSet(const HBasicBlock & block)1172 BitVector* GetLiveOutSet(const HBasicBlock& block) const { 1173 return &block_infos_[block.GetBlockId()]->live_out_; 1174 } 1175 GetKillSet(const HBasicBlock & block)1176 BitVector* GetKillSet(const HBasicBlock& block) const { 1177 return &block_infos_[block.GetBlockId()]->kill_; 1178 } 1179 GetInstructionFromSsaIndex(size_t index)1180 HInstruction* GetInstructionFromSsaIndex(size_t index) const { 1181 return instructions_from_ssa_index_[index]; 1182 } 1183 GetInstructionFromPosition(size_t index)1184 HInstruction* GetInstructionFromPosition(size_t index) const { 1185 return instructions_from_lifetime_position_[index]; 1186 } 1187 GetBlockFromPosition(size_t index)1188 HBasicBlock* GetBlockFromPosition(size_t index) const { 1189 HInstruction* instruction = GetInstructionFromPosition(index); 1190 if (instruction == nullptr) { 1191 // If we are at a block boundary, get the block following. 1192 instruction = GetInstructionFromPosition(index + 1); 1193 } 1194 return instruction->GetBlock(); 1195 } 1196 IsAtBlockBoundary(size_t index)1197 bool IsAtBlockBoundary(size_t index) const { 1198 return GetInstructionFromPosition(index) == nullptr; 1199 } 1200 GetTempUser(LiveInterval * temp)1201 HInstruction* GetTempUser(LiveInterval* temp) const { 1202 // A temporary shares the same lifetime start as the instruction that requires it. 1203 DCHECK(temp->IsTemp()); 1204 HInstruction* user = GetInstructionFromPosition(temp->GetStart() / 2); 1205 DCHECK_EQ(user, temp->GetFirstUse()->GetUser()); 1206 return user; 1207 } 1208 GetTempIndex(LiveInterval * temp)1209 size_t GetTempIndex(LiveInterval* temp) const { 1210 // We use the input index to store the index of the temporary in the user's temporary list. 1211 DCHECK(temp->IsTemp()); 1212 return temp->GetFirstUse()->GetInputIndex(); 1213 } 1214 GetMaxLifetimePosition()1215 size_t GetMaxLifetimePosition() const { 1216 return instructions_from_lifetime_position_.size() * 2 - 1; 1217 } 1218 GetNumberOfSsaValues()1219 size_t GetNumberOfSsaValues() const { 1220 return number_of_ssa_values_; 1221 } 1222 1223 static constexpr const char* kLivenessPassName = "liveness"; 1224 1225 private: 1226 // Give an SSA number to each instruction that defines a value used by another instruction, 1227 // and setup the lifetime information of each instruction and block. 1228 void NumberInstructions(); 1229 1230 // Compute live ranges of instructions, as well as live_in, live_out and kill sets. 1231 void ComputeLiveness(); 1232 1233 // Compute the live ranges of instructions, as well as the initial live_in, live_out and 1234 // kill sets, that do not take into account backward branches. 1235 void ComputeLiveRanges(); 1236 1237 // After computing the initial sets, this method does a fixed point 1238 // calculation over the live_in and live_out set to take into account 1239 // backwards branches. 1240 void ComputeLiveInAndLiveOutSets(); 1241 1242 // Update the live_in set of the block and returns whether it has changed. 1243 bool UpdateLiveIn(const HBasicBlock& block); 1244 1245 // Update the live_out set of the block and returns whether it has changed. 1246 bool UpdateLiveOut(const HBasicBlock& block); 1247 1248 // Returns whether `instruction` in an HEnvironment held by `env_holder` 1249 // should be kept live by the HEnvironment. ShouldBeLiveForEnvironment(HInstruction * env_holder,HInstruction * instruction)1250 static bool ShouldBeLiveForEnvironment(HInstruction* env_holder, HInstruction* instruction) { 1251 if (instruction == nullptr) return false; 1252 // A value that's not live in compiled code may still be needed in interpreter, 1253 // due to code motion, etc. 1254 if (env_holder->IsDeoptimize()) return true; 1255 // A value live at a throwing instruction in a try block may be copied by 1256 // the exception handler to its location at the top of the catch block. 1257 if (env_holder->CanThrowIntoCatchBlock()) return true; 1258 if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true; 1259 return instruction->GetType() == Primitive::kPrimNot; 1260 } 1261 CheckNoLiveInIrreducibleLoop(const HBasicBlock & block)1262 void CheckNoLiveInIrreducibleLoop(const HBasicBlock& block) const { 1263 if (!block.IsLoopHeader() || !block.GetLoopInformation()->IsIrreducible()) { 1264 return; 1265 } 1266 BitVector* live_in = GetLiveInSet(block); 1267 // To satisfy our liveness algorithm, we need to ensure loop headers of 1268 // irreducible loops do not have any live-in instructions, except constants 1269 // and the current method, which can be trivially re-materialized. 1270 for (uint32_t idx : live_in->Indexes()) { 1271 HInstruction* instruction = GetInstructionFromSsaIndex(idx); 1272 DCHECK(instruction->GetBlock()->IsEntryBlock()) << instruction->DebugName(); 1273 DCHECK(!instruction->IsParameterValue()); 1274 DCHECK(instruction->IsCurrentMethod() || instruction->IsConstant()) 1275 << instruction->DebugName(); 1276 } 1277 } 1278 1279 HGraph* const graph_; 1280 CodeGenerator* const codegen_; 1281 ArenaVector<BlockInfo*> block_infos_; 1282 1283 // Temporary array used when computing live_in, live_out, and kill sets. 1284 ArenaVector<HInstruction*> instructions_from_ssa_index_; 1285 1286 // Temporary array used when inserting moves in the graph. 1287 ArenaVector<HInstruction*> instructions_from_lifetime_position_; 1288 size_t number_of_ssa_values_; 1289 1290 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive); 1291 ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil); 1292 1293 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis); 1294 }; 1295 1296 } // namespace art 1297 1298 #endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_ 1299