blob: be726294529c339908063b027a69d2821807243e [file] [log] [blame]
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001/*
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"
Nicolas Geoffray829280c2015-01-28 10:20:37 +000021#include <iostream>
Nicolas Geoffray804d0932014-05-02 08:46:00 +010022
23namespace art {
24
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010025class CodeGenerator;
26
Nicolas Geoffray01ef3452014-10-01 11:32:17 +010027static constexpr int kNoRegister = -1;
28
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070029class BlockInfo : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffray804d0932014-05-02 08:46:00 +010030 public:
31 BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values)
32 : block_(block),
33 live_in_(allocator, number_of_ssa_values, false),
34 live_out_(allocator, number_of_ssa_values, false),
35 kill_(allocator, number_of_ssa_values, false) {
Ian Rogerscf7f1912014-10-22 22:06:39 -070036 UNUSED(block_);
Nicolas Geoffray804d0932014-05-02 08:46:00 +010037 live_in_.ClearAllBits();
38 live_out_.ClearAllBits();
39 kill_.ClearAllBits();
40 }
41
42 private:
43 const HBasicBlock& block_;
44 ArenaBitVector live_in_;
45 ArenaBitVector live_out_;
46 ArenaBitVector kill_;
47
48 friend class SsaLivenessAnalysis;
49
50 DISALLOW_COPY_AND_ASSIGN(BlockInfo);
51};
52
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010053/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010054 * A live range contains the start and end of a range where an instruction or a temporary
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010055 * is live.
56 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070057class LiveRange FINAL : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010058 public:
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010059 LiveRange(size_t start, size_t end, LiveRange* next) : start_(start), end_(end), next_(next) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010060 DCHECK_LT(start, end);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010061 DCHECK(next_ == nullptr || next_->GetStart() > GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010062 }
63
64 size_t GetStart() const { return start_; }
65 size_t GetEnd() const { return end_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010066 LiveRange* GetNext() const { return next_; }
67
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070068 bool IntersectsWith(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069 return (start_ >= other.start_ && start_ < other.end_)
70 || (other.start_ >= start_ && other.start_ < end_);
71 }
72
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070073 bool IsBefore(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010074 return end_ <= other.start_;
75 }
76
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070077 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010078 stream << "[" << start_ << ", " << end_ << ")";
79 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010080
Nicolas Geoffray840e5462015-01-07 16:01:24 +000081 LiveRange* Dup(ArenaAllocator* allocator) const {
82 return new (allocator) LiveRange(
83 start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator));
84 }
85
86 LiveRange* GetLastRange() {
87 return next_ == nullptr ? this : next_->GetLastRange();
88 }
89
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010090 private:
91 size_t start_;
Nicolas Geoffray76905622014-09-25 14:39:26 +010092 size_t end_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093 LiveRange* next_;
94
95 friend class LiveInterval;
96
97 DISALLOW_COPY_AND_ASSIGN(LiveRange);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010098};
99
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100100/**
101 * A use position represents a live interval use at a given position.
102 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700103class UsePosition : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100104 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100105 UsePosition(HInstruction* user,
106 size_t input_index,
107 bool is_environment,
108 size_t position,
109 UsePosition* next)
110 : user_(user),
111 input_index_(input_index),
112 is_environment_(is_environment),
113 position_(position),
114 next_(next) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100115 DCHECK(user->IsPhi()
116 || (GetPosition() == user->GetLifetimePosition() + 1)
117 || (GetPosition() == user->GetLifetimePosition()));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition());
119 }
120
121 size_t GetPosition() const { return position_; }
122
123 UsePosition* GetNext() const { return next_; }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100124 void SetNext(UsePosition* next) { next_ = next; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100125
126 HInstruction* GetUser() const { return user_; }
127
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100128 bool GetIsEnvironment() const { return is_environment_; }
129
130 size_t GetInputIndex() const { return input_index_; }
131
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100132 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100133 stream << position_;
134 }
135
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000136 UsePosition* Dup(ArenaAllocator* allocator) const {
137 return new (allocator) UsePosition(
138 user_, input_index_, is_environment_, position_,
139 next_ == nullptr ? nullptr : next_->Dup(allocator));
140 }
141
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 private:
143 HInstruction* const user_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100144 const size_t input_index_;
145 const bool is_environment_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100146 const size_t position_;
Nicolas Geoffray76905622014-09-25 14:39:26 +0100147 UsePosition* next_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100148
149 DISALLOW_COPY_AND_ASSIGN(UsePosition);
150};
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100151
152/**
153 * An interval is a list of disjoint live ranges where an instruction is live.
154 * Each instruction that has uses gets an interval.
155 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700156class LiveInterval : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100157 public:
Mingyao Yang296bd602014-10-06 16:47:28 -0700158 static LiveInterval* MakeInterval(ArenaAllocator* allocator,
159 Primitive::Type type,
160 HInstruction* instruction = nullptr) {
161 return new (allocator) LiveInterval(allocator, type, instruction);
162 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100163
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100164 static LiveInterval* MakeSlowPathInterval(ArenaAllocator* allocator, HInstruction* instruction) {
165 return new (allocator) LiveInterval(
166 allocator, Primitive::kPrimVoid, instruction, false, kNoRegister, false, true);
167 }
168
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100169 static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100170 return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
171 }
172
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100173 static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) {
174 return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100175 }
176
177 bool IsFixed() const { return is_fixed_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700178 bool IsTemp() const { return is_temp_; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100179 bool IsSlowPathSafepoint() const { return is_slow_path_safepoint_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700180 // This interval is the result of a split.
181 bool IsSplit() const { return parent_ != this; }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100182
183 void AddUse(HInstruction* instruction, size_t input_index, bool is_environment) {
184 // Set the use within the instruction.
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000185 size_t position = instruction->GetLifetimePosition() + 1;
186 LocationSummary* locations = instruction->GetLocations();
187 if (!is_environment) {
188 if (locations->IsFixedInput(input_index) || locations->OutputUsesSameAs(input_index)) {
189 // For fixed inputs and output same as input, the register allocator
190 // requires to have inputs die at the instruction, so that input moves use the
191 // location of the input just before that instruction (and not potential moves due
192 // to splitting).
193 position = instruction->GetLifetimePosition();
194 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100195 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000196
197 DCHECK(position == instruction->GetLifetimePosition()
198 || position == instruction->GetLifetimePosition() + 1);
199
Nicolas Geoffray76905622014-09-25 14:39:26 +0100200 if ((first_use_ != nullptr)
201 && (first_use_->GetUser() == instruction)
202 && (first_use_->GetPosition() < position)) {
203 // The user uses the instruction multiple times, and one use dies before the other.
204 // We update the use list so that the latter is first.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100205 UsePosition* cursor = first_use_;
206 while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) {
207 cursor = cursor->GetNext();
208 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100209 DCHECK(first_use_->GetPosition() + 1 == position);
210 UsePosition* new_use = new (allocator_) UsePosition(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100211 instruction, input_index, is_environment, position, cursor->GetNext());
212 cursor->SetNext(new_use);
Nicolas Geoffray76905622014-09-25 14:39:26 +0100213 if (first_range_->GetEnd() == first_use_->GetPosition()) {
214 first_range_->end_ = position;
215 }
216 return;
217 }
218
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100219 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100220 if (first_range_ == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100221 // First time we see a use of that interval.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100222 first_range_ = last_range_ = new (allocator_) LiveRange(
223 start_block_position, position, nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100224 } else if (first_range_->GetStart() == start_block_position) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100225 // There is a use later in the same block or in a following block.
226 // Note that in such a case, `AddRange` for the whole blocks has been called
227 // before arriving in this method, and this is the reason the start of
228 // `first_range_` is before the given `position`.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100229 DCHECK_LE(position, first_range_->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100230 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100231 DCHECK(first_range_->GetStart() > position);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100232 // There is a hole in the interval. Create a new range.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100233 // Note that the start of `first_range_` can be equal to `end`: two blocks
234 // having adjacent lifetime positions are not necessarily
235 // predecessor/successor. When two blocks are predecessor/successor, the
236 // liveness algorithm has called `AddRange` before arriving in this method,
237 // and the check line 205 would succeed.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100238 first_range_ = new (allocator_) LiveRange(start_block_position, position, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100239 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100240 first_use_ = new (allocator_) UsePosition(
241 instruction, input_index, is_environment, position, first_use_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242 }
243
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100244 void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100245 DCHECK(instruction->IsPhi());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100246 first_use_ = new (allocator_) UsePosition(
247 instruction, input_index, false, block->GetLifetimeEnd(), first_use_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100248 }
249
250 void AddRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100251 if (first_range_ == nullptr) {
252 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, first_range_);
253 } else if (first_range_->GetStart() == end) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100254 // There is a use in the following block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 first_range_->start_ = start;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100256 } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) {
257 DCHECK(is_fixed_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100258 } else {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100259 DCHECK_GT(first_range_->GetStart(), end);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100260 // There is a hole in the interval. Create a new range.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100261 first_range_ = new (allocator_) LiveRange(start, end, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100262 }
263 }
264
265 void AddLoopRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100266 DCHECK(first_range_ != nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000267 DCHECK_LE(start, first_range_->GetStart());
268 // Find the range that covers the positions after the loop.
269 LiveRange* after_loop = first_range_;
270 LiveRange* last_in_loop = nullptr;
271 while (after_loop != nullptr && after_loop->GetEnd() < end) {
272 DCHECK_LE(start, after_loop->GetStart());
273 last_in_loop = after_loop;
274 after_loop = after_loop->GetNext();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100275 }
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000276 if (after_loop == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100277 // Uses are only in the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100278 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000279 } else if (after_loop->GetStart() <= end) {
280 first_range_ = after_loop;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100281 // There are uses after the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100282 first_range_->start_ = start;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000283 } else {
284 // The use after the loop is after a lifetime hole.
285 DCHECK(last_in_loop != nullptr);
286 first_range_ = last_in_loop;
287 first_range_->start_ = start;
288 first_range_->end_ = end;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100289 }
290 }
291
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100292 bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100293 void SetSpillSlot(int slot) {
294 DCHECK(!is_fixed_);
295 DCHECK(!is_temp_);
296 spill_slot_ = slot;
297 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100298 int GetSpillSlot() const { return spill_slot_; }
299
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100300 void SetFrom(size_t from) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100301 if (first_range_ != nullptr) {
302 first_range_->start_ = from;
303 } else {
304 // Instruction without uses.
305 DCHECK(!defined_by_->HasUses());
306 DCHECK(from == defined_by_->GetLifetimePosition());
307 first_range_ = last_range_ = new (allocator_) LiveRange(from, from + 2, nullptr);
308 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100309 }
310
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100311 LiveInterval* GetParent() const { return parent_; }
312
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100313 LiveRange* GetFirstRange() const { return first_range_; }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000314 LiveRange* GetLastRange() const { return last_range_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100315
316 int GetRegister() const { return register_; }
317 void SetRegister(int reg) { register_ = reg; }
318 void ClearRegister() { register_ = kNoRegister; }
319 bool HasRegister() const { return register_ != kNoRegister; }
320
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100321 bool IsDeadAt(size_t position) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100322 return last_range_->GetEnd() <= position;
323 }
324
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100325 bool Covers(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100326 if (IsDeadAt(position)) {
327 return false;
328 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100329 LiveRange* current = first_range_;
330 while (current != nullptr) {
331 if (position >= current->GetStart() && position < current->GetEnd()) {
332 return true;
333 }
334 current = current->GetNext();
335 }
336 return false;
337 }
338
339 /**
340 * Returns the first intersection of this interval with `other`.
341 */
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100342 size_t FirstIntersectionWith(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100343 // Advance both intervals and find the first matching range start in
344 // this interval.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100345 LiveRange* my_range = first_range_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100346 LiveRange* other_range = other->first_range_;
347 do {
348 if (my_range->IntersectsWith(*other_range)) {
349 return std::max(my_range->GetStart(), other_range->GetStart());
350 } else if (my_range->IsBefore(*other_range)) {
351 my_range = my_range->GetNext();
352 if (my_range == nullptr) {
353 return kNoLifetime;
354 }
355 } else {
356 DCHECK(other_range->IsBefore(*my_range));
357 other_range = other_range->GetNext();
358 if (other_range == nullptr) {
359 return kNoLifetime;
360 }
361 }
362 } while (true);
363 }
364
365 size_t GetStart() const {
366 return first_range_->GetStart();
367 }
368
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100369 size_t GetEnd() const {
370 return last_range_->GetEnd();
371 }
372
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100373 size_t FirstRegisterUseAfter(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100374 if (is_temp_) {
375 return position == GetStart() ? position : kNoLifetime;
376 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100377 if (position == GetStart() && defined_by_ != nullptr) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100378 LocationSummary* locations = defined_by_->GetLocations();
379 Location location = locations->Out();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100380 // This interval is the first interval of the instruction. If the output
381 // of the instruction requires a register, we return the position of that instruction
382 // as the first register use.
383 if (location.IsUnallocated()) {
384 if ((location.GetPolicy() == Location::kRequiresRegister)
385 || (location.GetPolicy() == Location::kSameAsFirstInput
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100386 && locations->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100387 return position;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100388 } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
389 || (location.GetPolicy() == Location::kSameAsFirstInput
390 && locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister)) {
391 return position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100392 }
393 }
394 }
395
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100396 UsePosition* use = first_use_;
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100397 size_t end = GetEnd();
398 while (use != nullptr && use->GetPosition() <= end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100399 size_t use_position = use->GetPosition();
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100400 if (use_position > position && !use->GetIsEnvironment()) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100401 Location location = use->GetUser()->GetLocations()->InAt(use->GetInputIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100402 if (location.IsUnallocated()
403 && (location.GetPolicy() == Location::kRequiresRegister
404 || location.GetPolicy() == Location::kRequiresFpuRegister)) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100405 return use_position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100406 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100407 }
408 use = use->GetNext();
409 }
410 return kNoLifetime;
411 }
412
413 size_t FirstRegisterUse() const {
414 return FirstRegisterUseAfter(GetStart());
415 }
416
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000417 size_t FirstUseAfter(size_t position) const {
418 if (is_temp_) {
419 return position == GetStart() ? position : kNoLifetime;
420 }
421
422 UsePosition* use = first_use_;
423 size_t end = GetEnd();
424 while (use != nullptr && use->GetPosition() <= end) {
425 size_t use_position = use->GetPosition();
426 if (use_position > position) {
427 return use_position;
428 }
429 use = use->GetNext();
430 }
431 return kNoLifetime;
432 }
433
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100434 UsePosition* GetFirstUse() const {
435 return first_use_;
436 }
437
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100438 Primitive::Type GetType() const {
439 return type_;
440 }
441
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100442 HInstruction* GetDefinedBy() const {
443 return defined_by_;
444 }
445
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100446 /**
447 * Split this interval at `position`. This interval is changed to:
448 * [start ... position).
449 *
450 * The new interval covers:
451 * [position ... end)
452 */
453 LiveInterval* SplitAt(size_t position) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100454 DCHECK(!is_temp_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100455 DCHECK(!is_fixed_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100456 DCHECK_GT(position, GetStart());
457
458 if (last_range_->GetEnd() <= position) {
459 // This range dies before `position`, no need to split.
460 return nullptr;
461 }
462
463 LiveInterval* new_interval = new (allocator_) LiveInterval(allocator_, type_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100464 new_interval->next_sibling_ = next_sibling_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100465 next_sibling_ = new_interval;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100466 new_interval->parent_ = parent_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100467
468 new_interval->first_use_ = first_use_;
469 LiveRange* current = first_range_;
470 LiveRange* previous = nullptr;
471 // Iterate over the ranges, and either find a range that covers this position, or
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000472 // two ranges in between this position (that is, the position is in a lifetime hole).
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100473 do {
474 if (position >= current->GetEnd()) {
475 // Move to next range.
476 previous = current;
477 current = current->next_;
478 } else if (position <= current->GetStart()) {
479 // If the previous range did not cover this position, we know position is in
480 // a lifetime hole. We can just break the first_range_ and last_range_ links
481 // and return the new interval.
482 DCHECK(previous != nullptr);
483 DCHECK(current != first_range_);
484 new_interval->last_range_ = last_range_;
485 last_range_ = previous;
486 previous->next_ = nullptr;
487 new_interval->first_range_ = current;
488 return new_interval;
489 } else {
490 // This range covers position. We create a new last_range_ for this interval
491 // that covers last_range_->Start() and position. We also shorten the current
492 // range and make it the first range of the new interval.
493 DCHECK(position < current->GetEnd() && position > current->GetStart());
494 new_interval->last_range_ = last_range_;
495 last_range_ = new (allocator_) LiveRange(current->start_, position, nullptr);
496 if (previous != nullptr) {
497 previous->next_ = last_range_;
498 } else {
499 first_range_ = last_range_;
500 }
501 new_interval->first_range_ = current;
502 current->start_ = position;
503 return new_interval;
504 }
505 } while (current != nullptr);
506
507 LOG(FATAL) << "Unreachable";
508 return nullptr;
509 }
510
Nicolas Geoffray76905622014-09-25 14:39:26 +0100511 bool StartsBeforeOrAt(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100512 return GetStart() <= other->GetStart();
513 }
514
515 bool StartsAfter(LiveInterval* other) const {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100516 return GetStart() > other->GetStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100517 }
518
519 void Dump(std::ostream& stream) const {
520 stream << "ranges: { ";
521 LiveRange* current = first_range_;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000522 while (current != nullptr) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100523 current->Dump(stream);
524 stream << " ";
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000525 current = current->GetNext();
526 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100527 stream << "}, uses: { ";
528 UsePosition* use = first_use_;
529 if (use != nullptr) {
530 do {
531 use->Dump(stream);
532 stream << " ";
533 } while ((use = use->GetNext()) != nullptr);
534 }
535 stream << "}";
Mingyao Yang296bd602014-10-06 16:47:28 -0700536 stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000537 stream << " is_high: " << IsHighInterval();
538 stream << " is_low: " << IsLowInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100539 }
540
541 LiveInterval* GetNextSibling() const { return next_sibling_; }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000542 LiveInterval* GetLastSibling() {
543 LiveInterval* result = this;
544 while (result->next_sibling_ != nullptr) {
545 result = result->next_sibling_;
546 }
547 return result;
548 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100549
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100550 // Returns the first register hint that is at least free before
551 // the value contained in `free_until`. If none is found, returns
552 // `kNoRegister`.
553 int FindFirstRegisterHint(size_t* free_until) const;
554
555 // If there is enough at the definition site to find a register (for example
556 // it uses the same input as the first input), returns the register as a hint.
557 // Returns kNoRegister otherwise.
558 int FindHintAtDefinition() const;
559
560 // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
561 // slots for spilling.
562 bool NeedsTwoSpillSlots() const;
563
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100564 bool IsFloatingPoint() const {
565 return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
566 }
567
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100568 // Converts the location of the interval to a `Location` object.
569 Location ToLocation() const;
570
571 // Returns the location of the interval following its siblings at `position`.
572 Location GetLocationAt(size_t position) const;
573
574 // Finds the interval that covers `position`.
575 const LiveInterval& GetIntervalAt(size_t position) const;
576
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100577 // Returns whether `other` and `this` share the same kind of register.
578 bool SameRegisterKind(Location other) const;
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000579 bool SameRegisterKind(const LiveInterval& other) const {
580 return IsFloatingPoint() == other.IsFloatingPoint();
581 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100582
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000583 bool HasHighInterval() const {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000584 return IsLowInterval();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000585 }
586
587 bool HasLowInterval() const {
588 return IsHighInterval();
589 }
590
591 LiveInterval* GetLowInterval() const {
592 DCHECK(HasLowInterval());
593 return high_or_low_interval_;
594 }
595
596 LiveInterval* GetHighInterval() const {
597 DCHECK(HasHighInterval());
598 return high_or_low_interval_;
599 }
600
601 bool IsHighInterval() const {
602 return GetParent()->is_high_interval_;
603 }
604
605 bool IsLowInterval() const {
606 return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr);
607 }
608
609 void SetLowInterval(LiveInterval* low) {
610 DCHECK(IsHighInterval());
611 high_or_low_interval_ = low;
612 }
613
614 void SetHighInterval(LiveInterval* high) {
615 DCHECK(IsLowInterval());
616 high_or_low_interval_ = high;
617 }
618
619 void AddHighInterval(bool is_temp = false) {
620 DCHECK_EQ(GetParent(), this);
621 DCHECK(!HasHighInterval());
622 DCHECK(!HasLowInterval());
623 high_or_low_interval_ = new (allocator_) LiveInterval(
624 allocator_, type_, defined_by_, false, kNoRegister, is_temp, false, true);
625 high_or_low_interval_->high_or_low_interval_ = this;
626 if (first_range_ != nullptr) {
627 high_or_low_interval_->first_range_ = first_range_->Dup(allocator_);
628 high_or_low_interval_->last_range_ = first_range_->GetLastRange();
629 }
630 if (first_use_ != nullptr) {
631 high_or_low_interval_->first_use_ = first_use_->Dup(allocator_);
632 }
633 }
634
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000635 // Returns whether an interval, when it is non-split, is using
636 // the same register of one of its input.
637 bool IsUsingInputRegister() const {
638 if (defined_by_ != nullptr && !IsSplit()) {
639 for (HInputIterator it(defined_by_); !it.Done(); it.Advance()) {
640 LiveInterval* interval = it.Current()->GetLiveInterval();
641
642 // Find the interval that covers `defined_by`_.
643 while (interval != nullptr && !interval->Covers(defined_by_->GetLifetimePosition())) {
644 interval = interval->GetNextSibling();
645 }
646
647 // Check if both intervals have the same register of the same kind.
648 if (interval != nullptr
649 && interval->SameRegisterKind(*this)
650 && interval->GetRegister() == GetRegister()) {
651 return true;
652 }
653 }
654 }
655 return false;
656 }
657
658 // Returns whether an interval, when it is non-split, can safely use
659 // the same register of one of its input. Note that this method requires
660 // IsUsingInputRegister() to be true.
661 bool CanUseInputRegister() const {
662 DCHECK(IsUsingInputRegister());
663 if (defined_by_ != nullptr && !IsSplit()) {
664 LocationSummary* locations = defined_by_->GetLocations();
665 if (locations->OutputCanOverlapWithInputs()) {
666 return false;
667 }
668 for (HInputIterator it(defined_by_); !it.Done(); it.Advance()) {
669 LiveInterval* interval = it.Current()->GetLiveInterval();
670
671 // Find the interval that covers `defined_by`_.
672 while (interval != nullptr && !interval->Covers(defined_by_->GetLifetimePosition())) {
673 interval = interval->GetNextSibling();
674 }
675
676 if (interval != nullptr
677 && interval->SameRegisterKind(*this)
678 && interval->GetRegister() == GetRegister()) {
679 // We found the input that has the same register. Check if it is live after
680 // `defined_by`_.
681 return !interval->Covers(defined_by_->GetLifetimePosition() + 1);
682 }
683 }
684 }
685 LOG(FATAL) << "Unreachable";
686 UNREACHABLE();
687 }
688
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100689 private:
Mingyao Yang296bd602014-10-06 16:47:28 -0700690 LiveInterval(ArenaAllocator* allocator,
691 Primitive::Type type,
692 HInstruction* defined_by = nullptr,
693 bool is_fixed = false,
694 int reg = kNoRegister,
695 bool is_temp = false,
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000696 bool is_slow_path_safepoint = false,
697 bool is_high_interval = false)
Mingyao Yang296bd602014-10-06 16:47:28 -0700698 : allocator_(allocator),
699 first_range_(nullptr),
700 last_range_(nullptr),
701 first_use_(nullptr),
702 type_(type),
703 next_sibling_(nullptr),
704 parent_(this),
705 register_(reg),
706 spill_slot_(kNoSpillSlot),
707 is_fixed_(is_fixed),
708 is_temp_(is_temp),
709 is_slow_path_safepoint_(is_slow_path_safepoint),
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000710 is_high_interval_(is_high_interval),
711 high_or_low_interval_(nullptr),
Mingyao Yang296bd602014-10-06 16:47:28 -0700712 defined_by_(defined_by) {}
713
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100714 ArenaAllocator* const allocator_;
715
716 // Ranges of this interval. We need a quick access to the last range to test
717 // for liveness (see `IsDeadAt`).
718 LiveRange* first_range_;
719 LiveRange* last_range_;
720
721 // Uses of this interval. Note that this linked list is shared amongst siblings.
722 UsePosition* first_use_;
723
724 // The instruction type this interval corresponds to.
725 const Primitive::Type type_;
726
727 // Live interval that is the result of a split.
728 LiveInterval* next_sibling_;
729
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100730 // The first interval from which split intervals come from.
731 LiveInterval* parent_;
732
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100733 // The register allocated to this interval.
734 int register_;
735
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100736 // The spill slot allocated to this interval.
737 int spill_slot_;
738
739 // Whether the interval is for a fixed register.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100740 const bool is_fixed_;
741
742 // Whether the interval is for a temporary.
743 const bool is_temp_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100744
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100745 // Whether the interval is for a safepoint that calls on slow path.
746 const bool is_slow_path_safepoint_;
747
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000748 // Whether this interval is a synthesized interval for register pair.
749 const bool is_high_interval_;
750
751 // If this interval needs a register pair, the high or low equivalent.
752 // `is_high_interval_` tells whether this holds the low or the high.
753 LiveInterval* high_or_low_interval_;
754
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100755 // The instruction represented by this interval.
756 HInstruction* const defined_by_;
757
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100758 static constexpr int kNoRegister = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100759 static constexpr int kNoSpillSlot = -1;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100760
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000761 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
762
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100763 DISALLOW_COPY_AND_ASSIGN(LiveInterval);
764};
765
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100766class SsaLivenessAnalysis : public ValueObject {
767 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100768 SsaLivenessAnalysis(const HGraph& graph, CodeGenerator* codegen)
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100769 : graph_(graph),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100770 codegen_(codegen),
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000771 linear_order_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100772 block_infos_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100773 instructions_from_ssa_index_(graph.GetArena(), 0),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100774 instructions_from_lifetime_position_(graph.GetArena(), 0),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100775 number_of_ssa_values_(0) {
776 block_infos_.SetSize(graph.GetBlocks().Size());
777 }
778
779 void Analyze();
780
781 BitVector* GetLiveInSet(const HBasicBlock& block) const {
782 return &block_infos_.Get(block.GetBlockId())->live_in_;
783 }
784
785 BitVector* GetLiveOutSet(const HBasicBlock& block) const {
786 return &block_infos_.Get(block.GetBlockId())->live_out_;
787 }
788
789 BitVector* GetKillSet(const HBasicBlock& block) const {
790 return &block_infos_.Get(block.GetBlockId())->kill_;
791 }
792
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000793 const GrowableArray<HBasicBlock*>& GetLinearOrder() const {
794 return linear_order_;
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100795 }
796
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100797 HInstruction* GetInstructionFromSsaIndex(size_t index) const {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100798 return instructions_from_ssa_index_.Get(index);
799 }
800
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100801 HInstruction* GetInstructionFromPosition(size_t index) const {
802 return instructions_from_lifetime_position_.Get(index);
803 }
804
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100805 HInstruction* GetTempUser(LiveInterval* temp) const {
806 // A temporary shares the same lifetime start as the instruction that requires it.
807 DCHECK(temp->IsTemp());
808 return GetInstructionFromPosition(temp->GetStart() / 2);
809 }
810
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100811 size_t GetMaxLifetimePosition() const {
812 return instructions_from_lifetime_position_.Size() * 2 - 1;
813 }
814
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100815 size_t GetNumberOfSsaValues() const {
816 return number_of_ssa_values_;
817 }
818
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800819 static constexpr const char* kLivenessPassName = "liveness";
820
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100821 private:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100822 // Linearize the graph so that:
823 // (1): a block is always after its dominator,
824 // (2): blocks of loops are contiguous.
825 // This creates a natural and efficient ordering when visualizing live ranges.
826 void LinearizeGraph();
827
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100828 // Give an SSA number to each instruction that defines a value used by another instruction,
829 // and setup the lifetime information of each instruction and block.
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100830 void NumberInstructions();
831
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100832 // Compute live ranges of instructions, as well as live_in, live_out and kill sets.
833 void ComputeLiveness();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100834
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100835 // Compute the live ranges of instructions, as well as the initial live_in, live_out and
836 // kill sets, that do not take into account backward branches.
837 void ComputeLiveRanges();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100838
839 // After computing the initial sets, this method does a fixed point
840 // calculation over the live_in and live_out set to take into account
841 // backwards branches.
842 void ComputeLiveInAndLiveOutSets();
843
844 // Update the live_in set of the block and returns whether it has changed.
845 bool UpdateLiveIn(const HBasicBlock& block);
846
847 // Update the live_out set of the block and returns whether it has changed.
848 bool UpdateLiveOut(const HBasicBlock& block);
849
850 const HGraph& graph_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100851 CodeGenerator* const codegen_;
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000852 GrowableArray<HBasicBlock*> linear_order_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100853 GrowableArray<BlockInfo*> block_infos_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100854
855 // Temporary array used when computing live_in, live_out, and kill sets.
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100856 GrowableArray<HInstruction*> instructions_from_ssa_index_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100857
858 // Temporary array used when inserting moves in the graph.
859 GrowableArray<HInstruction*> instructions_from_lifetime_position_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100860 size_t number_of_ssa_values_;
861
862 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
863};
864
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000865class HLinearPostOrderIterator : public ValueObject {
866 public:
867 explicit HLinearPostOrderIterator(const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000868 : order_(liveness.GetLinearOrder()), index_(liveness.GetLinearOrder().Size()) {}
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000869
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000870 bool Done() const { return index_ == 0; }
871
872 HBasicBlock* Current() const { return order_.Get(index_ -1); }
873
874 void Advance() {
875 --index_;
876 DCHECK_GE(index_, 0U);
877 }
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000878
879 private:
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000880 const GrowableArray<HBasicBlock*>& order_;
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000881 size_t index_;
882
883 DISALLOW_COPY_AND_ASSIGN(HLinearPostOrderIterator);
884};
885
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000886class HLinearOrderIterator : public ValueObject {
887 public:
888 explicit HLinearOrderIterator(const SsaLivenessAnalysis& liveness)
889 : order_(liveness.GetLinearOrder()), index_(0) {}
890
891 bool Done() const { return index_ == order_.Size(); }
892 HBasicBlock* Current() const { return order_.Get(index_); }
893 void Advance() { ++index_; }
894
895 private:
896 const GrowableArray<HBasicBlock*>& order_;
897 size_t index_;
898
899 DISALLOW_COPY_AND_ASSIGN(HLinearOrderIterator);
900};
901
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100902} // namespace art
903
904#endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_