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