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