blob: 414cc7d951a3c2af0bedccc399b83b140e31c413 [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;
Nicolas Geoffrayfbda5f32015-04-29 14:16:00 +010026class SsaLivenessAnalysis;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010027
Nicolas Geoffray01ef3452014-10-01 11:32:17 +010028static constexpr int kNoRegister = -1;
29
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070030class BlockInfo : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffray804d0932014-05-02 08:46:00 +010031 public:
32 BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values)
33 : block_(block),
34 live_in_(allocator, number_of_ssa_values, false),
35 live_out_(allocator, number_of_ssa_values, false),
36 kill_(allocator, number_of_ssa_values, false) {
Ian Rogerscf7f1912014-10-22 22:06:39 -070037 UNUSED(block_);
Nicolas Geoffray804d0932014-05-02 08:46:00 +010038 live_in_.ClearAllBits();
39 live_out_.ClearAllBits();
40 kill_.ClearAllBits();
41 }
42
43 private:
44 const HBasicBlock& block_;
45 ArenaBitVector live_in_;
46 ArenaBitVector live_out_;
47 ArenaBitVector kill_;
48
49 friend class SsaLivenessAnalysis;
50
51 DISALLOW_COPY_AND_ASSIGN(BlockInfo);
52};
53
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010054/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010055 * A live range contains the start and end of a range where an instruction or a temporary
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010056 * is live.
57 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070058class LiveRange FINAL : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010059 public:
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060 LiveRange(size_t start, size_t end, LiveRange* next) : start_(start), end_(end), next_(next) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010061 DCHECK_LT(start, end);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010062 DCHECK(next_ == nullptr || next_->GetStart() > GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010063 }
64
65 size_t GetStart() const { return start_; }
66 size_t GetEnd() const { return end_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010067 LiveRange* GetNext() const { return next_; }
68
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070069 bool IntersectsWith(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010070 return (start_ >= other.start_ && start_ < other.end_)
71 || (other.start_ >= start_ && other.start_ < end_);
72 }
73
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070074 bool IsBefore(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010075 return end_ <= other.start_;
76 }
77
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070078 void Dump(std::ostream& stream) const {
David Brazdilc7a24852015-05-15 16:44:05 +010079 stream << "[" << start_ << "," << end_ << ")";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010080 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010081
Nicolas Geoffray840e5462015-01-07 16:01:24 +000082 LiveRange* Dup(ArenaAllocator* allocator) const {
83 return new (allocator) LiveRange(
84 start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator));
85 }
86
87 LiveRange* GetLastRange() {
88 return next_ == nullptr ? this : next_->GetLastRange();
89 }
90
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010091 private:
92 size_t start_;
Nicolas Geoffray76905622014-09-25 14:39:26 +010093 size_t end_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010094 LiveRange* next_;
95
96 friend class LiveInterval;
97
98 DISALLOW_COPY_AND_ASSIGN(LiveRange);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010099};
100
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100101/**
102 * A use position represents a live interval use at a given position.
103 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700104class UsePosition : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100105 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100106 UsePosition(HInstruction* user,
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100107 HEnvironment* environment,
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100108 size_t input_index,
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100109 size_t position,
110 UsePosition* next)
111 : user_(user),
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100112 environment_(environment),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100113 input_index_(input_index),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100114 position_(position),
115 next_(next) {
Nicolas Geoffray57902602015-04-21 14:28:41 +0100116 DCHECK((user == nullptr)
117 || user->IsPhi()
Nicolas Geoffray76905622014-09-25 14:39:26 +0100118 || (GetPosition() == user->GetLifetimePosition() + 1)
119 || (GetPosition() == user->GetLifetimePosition()));
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100120 DCHECK(environment == nullptr || user == nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100121 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition());
122 }
123
Nicolas Geoffray57902602015-04-21 14:28:41 +0100124 static constexpr size_t kNoInput = -1;
125
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100126 size_t GetPosition() const { return position_; }
127
128 UsePosition* GetNext() const { return next_; }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100129 void SetNext(UsePosition* next) { next_ = next; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100130
131 HInstruction* GetUser() const { return user_; }
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100132 HEnvironment* GetEnvironment() const { return environment_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100133
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100134 bool GetIsEnvironment() const { return environment_ != nullptr; }
Nicolas Geoffray57902602015-04-21 14:28:41 +0100135 bool IsSynthesized() const { return user_ == nullptr; }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100136
137 size_t GetInputIndex() const { return input_index_; }
138
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100139 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100140 stream << position_;
Nicolas Geoffray57902602015-04-21 14:28:41 +0100141 }
142
143 HLoopInformation* GetLoopInformation() const {
144 return user_->GetBlock()->GetLoopInformation();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 }
146
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000147 UsePosition* Dup(ArenaAllocator* allocator) const {
148 return new (allocator) UsePosition(
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100149 user_, environment_, input_index_, position_,
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000150 next_ == nullptr ? nullptr : next_->Dup(allocator));
151 }
152
Nicolas Geoffray57902602015-04-21 14:28:41 +0100153 bool RequiresRegister() const {
154 if (GetIsEnvironment()) return false;
155 if (IsSynthesized()) return false;
156 Location location = GetUser()->GetLocations()->InAt(GetInputIndex());
157 return location.IsUnallocated()
158 && (location.GetPolicy() == Location::kRequiresRegister
159 || location.GetPolicy() == Location::kRequiresFpuRegister);
160 }
161
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100162 private:
163 HInstruction* const user_;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100164 HEnvironment* const environment_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100165 const size_t input_index_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100166 const size_t position_;
Nicolas Geoffray76905622014-09-25 14:39:26 +0100167 UsePosition* next_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100168
169 DISALLOW_COPY_AND_ASSIGN(UsePosition);
170};
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100171
Nicolas Geoffray5588e582015-04-14 14:10:59 +0100172class SafepointPosition : public ArenaObject<kArenaAllocMisc> {
173 public:
174 explicit SafepointPosition(HInstruction* instruction)
175 : instruction_(instruction),
176 next_(nullptr) {}
177
178 void SetNext(SafepointPosition* next) {
179 next_ = next;
180 }
181
182 size_t GetPosition() const {
183 return instruction_->GetLifetimePosition();
184 }
185
186 SafepointPosition* GetNext() const {
187 return next_;
188 }
189
190 LocationSummary* GetLocations() const {
191 return instruction_->GetLocations();
192 }
193
194 HInstruction* GetInstruction() const {
195 return instruction_;
196 }
197
198 private:
199 HInstruction* const instruction_;
200 SafepointPosition* next_;
201
202 DISALLOW_COPY_AND_ASSIGN(SafepointPosition);
203};
204
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100205/**
206 * An interval is a list of disjoint live ranges where an instruction is live.
207 * Each instruction that has uses gets an interval.
208 */
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100209class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100210 public:
Mingyao Yang296bd602014-10-06 16:47:28 -0700211 static LiveInterval* MakeInterval(ArenaAllocator* allocator,
212 Primitive::Type type,
213 HInstruction* instruction = nullptr) {
214 return new (allocator) LiveInterval(allocator, type, instruction);
215 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100216
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100217 static LiveInterval* MakeSlowPathInterval(ArenaAllocator* allocator, HInstruction* instruction) {
218 return new (allocator) LiveInterval(
219 allocator, Primitive::kPrimVoid, instruction, false, kNoRegister, false, true);
220 }
221
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100222 static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100223 return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
224 }
225
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100226 static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) {
227 return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100228 }
229
230 bool IsFixed() const { return is_fixed_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700231 bool IsTemp() const { return is_temp_; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100232 bool IsSlowPathSafepoint() const { return is_slow_path_safepoint_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700233 // This interval is the result of a split.
234 bool IsSplit() const { return parent_ != this; }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100235
Nicolas Geoffrayf01d3442015-03-27 17:15:49 +0000236 void AddTempUse(HInstruction* instruction, size_t temp_index) {
237 DCHECK(IsTemp());
238 DCHECK(first_use_ == nullptr) << "A temporary can only have one user";
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100239 DCHECK(first_env_use_ == nullptr) << "A temporary cannot have environment user";
Nicolas Geoffrayf01d3442015-03-27 17:15:49 +0000240 size_t position = instruction->GetLifetimePosition();
241 first_use_ = new (allocator_) UsePosition(
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100242 instruction, /* environment */ nullptr, temp_index, position, first_use_);
Nicolas Geoffrayf01d3442015-03-27 17:15:49 +0000243 AddRange(position, position + 1);
244 }
245
Nicolas Geoffrayd8126be2015-03-27 10:22:41 +0000246 void AddUse(HInstruction* instruction,
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100247 HEnvironment* environment,
Nicolas Geoffrayd8126be2015-03-27 10:22:41 +0000248 size_t input_index,
Nicolas Geoffrayd8126be2015-03-27 10:22:41 +0000249 bool keep_alive = false) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100250 // Set the use within the instruction.
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100251 bool is_environment = (environment != nullptr);
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000252 size_t position = instruction->GetLifetimePosition() + 1;
253 LocationSummary* locations = instruction->GetLocations();
254 if (!is_environment) {
255 if (locations->IsFixedInput(input_index) || locations->OutputUsesSameAs(input_index)) {
256 // For fixed inputs and output same as input, the register allocator
257 // requires to have inputs die at the instruction, so that input moves use the
258 // location of the input just before that instruction (and not potential moves due
259 // to splitting).
260 position = instruction->GetLifetimePosition();
Nicolas Geoffray57902602015-04-21 14:28:41 +0100261 } else if (!locations->InAt(input_index).IsValid()) {
262 return;
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000263 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100264 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000265
Nicolas Geoffray57902602015-04-21 14:28:41 +0100266 if (!is_environment && instruction->IsInLoop()) {
267 AddBackEdgeUses(*instruction->GetBlock());
268 }
269
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000270 DCHECK(position == instruction->GetLifetimePosition()
271 || position == instruction->GetLifetimePosition() + 1);
272
Nicolas Geoffray76905622014-09-25 14:39:26 +0100273 if ((first_use_ != nullptr)
274 && (first_use_->GetUser() == instruction)
275 && (first_use_->GetPosition() < position)) {
276 // The user uses the instruction multiple times, and one use dies before the other.
277 // We update the use list so that the latter is first.
Nicolas Geoffrayd8126be2015-03-27 10:22:41 +0000278 DCHECK(!is_environment);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100279 UsePosition* cursor = first_use_;
280 while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) {
281 cursor = cursor->GetNext();
282 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100283 DCHECK(first_use_->GetPosition() + 1 == position);
284 UsePosition* new_use = new (allocator_) UsePosition(
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100285 instruction, nullptr /* environment */, input_index, position, cursor->GetNext());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100286 cursor->SetNext(new_use);
Nicolas Geoffray76905622014-09-25 14:39:26 +0100287 if (first_range_->GetEnd() == first_use_->GetPosition()) {
288 first_range_->end_ = position;
289 }
290 return;
291 }
292
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100293 if (is_environment) {
294 first_env_use_ = new (allocator_) UsePosition(
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100295 nullptr /* instruction */, environment, input_index, position, first_env_use_);
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100296 } else {
297 first_use_ = new (allocator_) UsePosition(
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100298 instruction, nullptr /* environment */, input_index, position, first_use_);
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100299 }
Nicolas Geoffrayd8126be2015-03-27 10:22:41 +0000300
301 if (is_environment && !keep_alive) {
302 // If this environment use does not keep the instruction live, it does not
303 // affect the live range of that instruction.
304 return;
305 }
306
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100307 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100308 if (first_range_ == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100309 // First time we see a use of that interval.
David Brazdil3fc992f2015-04-16 18:31:55 +0100310 first_range_ = last_range_ = range_search_start_ =
311 new (allocator_) LiveRange(start_block_position, position, nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100312 } else if (first_range_->GetStart() == start_block_position) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100313 // There is a use later in the same block or in a following block.
314 // Note that in such a case, `AddRange` for the whole blocks has been called
315 // before arriving in this method, and this is the reason the start of
316 // `first_range_` is before the given `position`.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100317 DCHECK_LE(position, first_range_->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100318 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100319 DCHECK(first_range_->GetStart() > position);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100320 // There is a hole in the interval. Create a new range.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100321 // Note that the start of `first_range_` can be equal to `end`: two blocks
322 // having adjacent lifetime positions are not necessarily
323 // predecessor/successor. When two blocks are predecessor/successor, the
324 // liveness algorithm has called `AddRange` before arriving in this method,
325 // and the check line 205 would succeed.
David Brazdil3fc992f2015-04-16 18:31:55 +0100326 first_range_ = range_search_start_ =
327 new (allocator_) LiveRange(start_block_position, position, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100328 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100329 }
330
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100331 void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100332 DCHECK(instruction->IsPhi());
Nicolas Geoffray57902602015-04-21 14:28:41 +0100333 if (block->IsInLoop()) {
334 AddBackEdgeUses(*block);
335 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100336 first_use_ = new (allocator_) UsePosition(
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100337 instruction, /* environment */ nullptr, input_index, block->GetLifetimeEnd(), first_use_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100338 }
339
340 void AddRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100341 if (first_range_ == nullptr) {
David Brazdil3fc992f2015-04-16 18:31:55 +0100342 first_range_ = last_range_ = range_search_start_ =
343 new (allocator_) LiveRange(start, end, first_range_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100344 } else if (first_range_->GetStart() == end) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100345 // There is a use in the following block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100346 first_range_->start_ = start;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100347 } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) {
348 DCHECK(is_fixed_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100349 } else {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100350 DCHECK_GT(first_range_->GetStart(), end);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100351 // There is a hole in the interval. Create a new range.
David Brazdil3fc992f2015-04-16 18:31:55 +0100352 first_range_ = range_search_start_ = new (allocator_) LiveRange(start, end, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100353 }
354 }
355
356 void AddLoopRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100357 DCHECK(first_range_ != nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000358 DCHECK_LE(start, first_range_->GetStart());
359 // Find the range that covers the positions after the loop.
360 LiveRange* after_loop = first_range_;
361 LiveRange* last_in_loop = nullptr;
362 while (after_loop != nullptr && after_loop->GetEnd() < end) {
363 DCHECK_LE(start, after_loop->GetStart());
364 last_in_loop = after_loop;
365 after_loop = after_loop->GetNext();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100366 }
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000367 if (after_loop == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100368 // Uses are only in the loop.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700369 first_range_ = last_range_ = range_search_start_ =
370 new (allocator_) LiveRange(start, end, nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000371 } else if (after_loop->GetStart() <= end) {
David Brazdil3fc992f2015-04-16 18:31:55 +0100372 first_range_ = range_search_start_ = after_loop;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100373 // There are uses after the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100374 first_range_->start_ = start;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000375 } else {
376 // The use after the loop is after a lifetime hole.
377 DCHECK(last_in_loop != nullptr);
David Brazdil3fc992f2015-04-16 18:31:55 +0100378 first_range_ = range_search_start_ = last_in_loop;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000379 first_range_->start_ = start;
380 first_range_->end_ = end;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100381 }
382 }
383
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100384 bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100385 void SetSpillSlot(int slot) {
386 DCHECK(!is_fixed_);
387 DCHECK(!is_temp_);
388 spill_slot_ = slot;
389 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100390 int GetSpillSlot() const { return spill_slot_; }
391
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100392 void SetFrom(size_t from) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100393 if (first_range_ != nullptr) {
394 first_range_->start_ = from;
395 } else {
396 // Instruction without uses.
Nicolas Geoffray94015b92015-06-04 18:21:04 +0100397 DCHECK(first_use_ == nullptr);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100398 DCHECK(from == defined_by_->GetLifetimePosition());
David Brazdil3fc992f2015-04-16 18:31:55 +0100399 first_range_ = last_range_ = range_search_start_ =
400 new (allocator_) LiveRange(from, from + 2, nullptr);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100401 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100402 }
403
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100404 LiveInterval* GetParent() const { return parent_; }
405
Nicolas Geoffray1ba19812015-04-21 09:12:40 +0100406 // Returns whether this interval is the parent interval, that is, the interval
407 // that starts where the HInstruction is defined.
408 bool IsParent() const { return parent_ == this; }
409
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100410 LiveRange* GetFirstRange() const { return first_range_; }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000411 LiveRange* GetLastRange() const { return last_range_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100412
413 int GetRegister() const { return register_; }
414 void SetRegister(int reg) { register_ = reg; }
415 void ClearRegister() { register_ = kNoRegister; }
416 bool HasRegister() const { return register_ != kNoRegister; }
417
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100418 bool IsDeadAt(size_t position) const {
David Brazdil241a4862015-04-16 17:59:03 +0100419 return GetEnd() <= position;
420 }
421
422 bool IsDefinedAt(size_t position) const {
423 return GetStart() <= position && !IsDeadAt(position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100424 }
425
David Brazdil3fc992f2015-04-16 18:31:55 +0100426 // Returns true if the interval contains a LiveRange covering `position`.
427 // The range at or immediately after the current position of linear scan
428 // is cached for better performance. If `position` can be smaller than
429 // that, CoversSlow should be used instead.
David Brazdil5b8e6a52015-02-25 16:17:05 +0000430 bool Covers(size_t position) {
David Brazdil3fc992f2015-04-16 18:31:55 +0100431 LiveRange* candidate = FindRangeAtOrAfter(position, range_search_start_);
432 range_search_start_ = candidate;
433 return (candidate != nullptr && candidate->GetStart() <= position);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100434 }
435
David Brazdil3fc992f2015-04-16 18:31:55 +0100436 // Same as Covers but always tests all ranges.
437 bool CoversSlow(size_t position) const {
438 LiveRange* candidate = FindRangeAtOrAfter(position, first_range_);
439 return candidate != nullptr && candidate->GetStart() <= position;
440 }
441
442 // Returns the first intersection of this interval with `current`, which
443 // must be the interval currently being allocated by linear scan.
444 size_t FirstIntersectionWith(LiveInterval* current) const {
445 // Find the first range after the start of `current`. We use the search
446 // cache to improve performance.
447 DCHECK(GetStart() <= current->GetStart() || IsFixed());
448 LiveRange* other_range = current->first_range_;
449 LiveRange* my_range = FindRangeAtOrAfter(other_range->GetStart(), range_search_start_);
450 if (my_range == nullptr) {
451 return kNoLifetime;
452 }
453
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100454 // Advance both intervals and find the first matching range start in
455 // this interval.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100456 do {
David Brazdil714e14f2015-02-25 11:57:05 +0000457 if (my_range->IsBefore(*other_range)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100458 my_range = my_range->GetNext();
459 if (my_range == nullptr) {
460 return kNoLifetime;
461 }
David Brazdil714e14f2015-02-25 11:57:05 +0000462 } else if (other_range->IsBefore(*my_range)) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100463 other_range = other_range->GetNext();
464 if (other_range == nullptr) {
465 return kNoLifetime;
466 }
David Brazdil714e14f2015-02-25 11:57:05 +0000467 } else {
468 DCHECK(my_range->IntersectsWith(*other_range));
469 return std::max(my_range->GetStart(), other_range->GetStart());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100470 }
471 } while (true);
472 }
473
474 size_t GetStart() const {
475 return first_range_->GetStart();
476 }
477
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100478 size_t GetEnd() const {
479 return last_range_->GetEnd();
480 }
481
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100482 size_t FirstRegisterUseAfter(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100483 if (is_temp_) {
484 return position == GetStart() ? position : kNoLifetime;
485 }
Nicolas Geoffray57902602015-04-21 14:28:41 +0100486
487 if (IsDefiningPosition(position) && DefinitionRequiresRegister()) {
488 return position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100489 }
490
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100491 UsePosition* use = first_use_;
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100492 size_t end = GetEnd();
493 while (use != nullptr && use->GetPosition() <= end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100494 size_t use_position = use->GetPosition();
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100495 if (use_position > position) {
Nicolas Geoffray57902602015-04-21 14:28:41 +0100496 if (use->RequiresRegister()) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100497 return use_position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100498 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100499 }
500 use = use->GetNext();
501 }
502 return kNoLifetime;
503 }
504
505 size_t FirstRegisterUse() const {
506 return FirstRegisterUseAfter(GetStart());
507 }
508
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000509 size_t FirstUseAfter(size_t position) const {
510 if (is_temp_) {
511 return position == GetStart() ? position : kNoLifetime;
512 }
513
Nicolas Geoffray57902602015-04-21 14:28:41 +0100514 if (IsDefiningPosition(position)) {
515 DCHECK(defined_by_->GetLocations()->Out().IsValid());
516 return position;
Nicolas Geoffray1ba19812015-04-21 09:12:40 +0100517 }
518
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000519 UsePosition* use = first_use_;
520 size_t end = GetEnd();
521 while (use != nullptr && use->GetPosition() <= end) {
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100522 size_t use_position = use->GetPosition();
Nicolas Geoffray57902602015-04-21 14:28:41 +0100523 if (use_position > position) {
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100524 return use_position;
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000525 }
526 use = use->GetNext();
527 }
528 return kNoLifetime;
529 }
530
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100531 UsePosition* GetFirstUse() const {
532 return first_use_;
533 }
534
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100535 UsePosition* GetFirstEnvironmentUse() const {
536 return first_env_use_;
537 }
538
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100539 Primitive::Type GetType() const {
540 return type_;
541 }
542
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100543 HInstruction* GetDefinedBy() const {
544 return defined_by_;
545 }
546
Nicolas Geoffray8826f672015-04-17 09:15:11 +0100547 bool HasWillCallSafepoint() const {
548 for (SafepointPosition* safepoint = first_safepoint_;
549 safepoint != nullptr;
550 safepoint = safepoint->GetNext()) {
551 if (safepoint->GetLocations()->WillCall()) return true;
552 }
553 return false;
554 }
555
Nicolas Geoffray43af7282015-04-16 13:01:01 +0100556 SafepointPosition* FindSafepointJustBefore(size_t position) const {
557 for (SafepointPosition* safepoint = first_safepoint_, *previous = nullptr;
558 safepoint != nullptr;
559 previous = safepoint, safepoint = safepoint->GetNext()) {
560 if (safepoint->GetPosition() >= position) return previous;
561 }
562 return last_safepoint_;
563 }
564
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100565 /**
566 * Split this interval at `position`. This interval is changed to:
567 * [start ... position).
568 *
569 * The new interval covers:
570 * [position ... end)
571 */
572 LiveInterval* SplitAt(size_t position) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100573 DCHECK(!is_temp_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100574 DCHECK(!is_fixed_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100575 DCHECK_GT(position, GetStart());
576
David Brazdil241a4862015-04-16 17:59:03 +0100577 if (GetEnd() <= position) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100578 // This range dies before `position`, no need to split.
579 return nullptr;
580 }
581
582 LiveInterval* new_interval = new (allocator_) LiveInterval(allocator_, type_);
Nicolas Geoffray43af7282015-04-16 13:01:01 +0100583 SafepointPosition* new_last_safepoint = FindSafepointJustBefore(position);
584 if (new_last_safepoint == nullptr) {
585 new_interval->first_safepoint_ = first_safepoint_;
586 new_interval->last_safepoint_ = last_safepoint_;
587 first_safepoint_ = last_safepoint_ = nullptr;
588 } else if (last_safepoint_ != new_last_safepoint) {
589 new_interval->last_safepoint_ = last_safepoint_;
590 new_interval->first_safepoint_ = new_last_safepoint->GetNext();
591 DCHECK(new_interval->first_safepoint_ != nullptr);
592 last_safepoint_ = new_last_safepoint;
593 last_safepoint_->SetNext(nullptr);
594 }
595
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100596 new_interval->next_sibling_ = next_sibling_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100597 next_sibling_ = new_interval;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100598 new_interval->parent_ = parent_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100599
600 new_interval->first_use_ = first_use_;
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100601 new_interval->first_env_use_ = first_env_use_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100602 LiveRange* current = first_range_;
603 LiveRange* previous = nullptr;
604 // Iterate over the ranges, and either find a range that covers this position, or
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000605 // two ranges in between this position (that is, the position is in a lifetime hole).
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100606 do {
607 if (position >= current->GetEnd()) {
608 // Move to next range.
609 previous = current;
610 current = current->next_;
611 } else if (position <= current->GetStart()) {
612 // If the previous range did not cover this position, we know position is in
613 // a lifetime hole. We can just break the first_range_ and last_range_ links
614 // and return the new interval.
615 DCHECK(previous != nullptr);
616 DCHECK(current != first_range_);
617 new_interval->last_range_ = last_range_;
618 last_range_ = previous;
619 previous->next_ = nullptr;
620 new_interval->first_range_ = current;
David Brazdil3fc992f2015-04-16 18:31:55 +0100621 if (range_search_start_ != nullptr && range_search_start_->GetEnd() >= current->GetEnd()) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700622 // Search start point is inside `new_interval`. Change it to null
David Brazdil3fc992f2015-04-16 18:31:55 +0100623 // (i.e. the end of the interval) in the original interval.
624 range_search_start_ = nullptr;
625 }
626 new_interval->range_search_start_ = new_interval->first_range_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100627 return new_interval;
628 } else {
629 // This range covers position. We create a new last_range_ for this interval
630 // that covers last_range_->Start() and position. We also shorten the current
631 // range and make it the first range of the new interval.
632 DCHECK(position < current->GetEnd() && position > current->GetStart());
633 new_interval->last_range_ = last_range_;
634 last_range_ = new (allocator_) LiveRange(current->start_, position, nullptr);
635 if (previous != nullptr) {
636 previous->next_ = last_range_;
637 } else {
638 first_range_ = last_range_;
639 }
640 new_interval->first_range_ = current;
641 current->start_ = position;
David Brazdil3fc992f2015-04-16 18:31:55 +0100642 if (range_search_start_ != nullptr && range_search_start_->GetEnd() >= current->GetEnd()) {
643 // Search start point is inside `new_interval`. Change it to `last_range`
644 // in the original interval. This is conservative but always correct.
645 range_search_start_ = last_range_;
646 }
647 new_interval->range_search_start_ = new_interval->first_range_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100648 return new_interval;
649 }
650 } while (current != nullptr);
651
652 LOG(FATAL) << "Unreachable";
653 return nullptr;
654 }
655
Nicolas Geoffray76905622014-09-25 14:39:26 +0100656 bool StartsBeforeOrAt(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100657 return GetStart() <= other->GetStart();
658 }
659
660 bool StartsAfter(LiveInterval* other) const {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100661 return GetStart() > other->GetStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100662 }
663
664 void Dump(std::ostream& stream) const {
665 stream << "ranges: { ";
666 LiveRange* current = first_range_;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000667 while (current != nullptr) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100668 current->Dump(stream);
669 stream << " ";
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000670 current = current->GetNext();
671 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100672 stream << "}, uses: { ";
673 UsePosition* use = first_use_;
674 if (use != nullptr) {
675 do {
676 use->Dump(stream);
677 stream << " ";
678 } while ((use = use->GetNext()) != nullptr);
679 }
Nicolas Geoffray57902602015-04-21 14:28:41 +0100680 stream << "}, { ";
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100681 use = first_env_use_;
682 if (use != nullptr) {
683 do {
684 use->Dump(stream);
685 stream << " ";
686 } while ((use = use->GetNext()) != nullptr);
687 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100688 stream << "}";
Mingyao Yang296bd602014-10-06 16:47:28 -0700689 stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000690 stream << " is_low: " << IsLowInterval();
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100691 stream << " is_high: " << IsHighInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100692 }
693
694 LiveInterval* GetNextSibling() const { return next_sibling_; }
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000695 LiveInterval* GetLastSibling() {
696 LiveInterval* result = this;
697 while (result->next_sibling_ != nullptr) {
698 result = result->next_sibling_;
699 }
700 return result;
701 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100702
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100703 // Returns the first register hint that is at least free before
704 // the value contained in `free_until`. If none is found, returns
705 // `kNoRegister`.
Nicolas Geoffrayfbda5f32015-04-29 14:16:00 +0100706 int FindFirstRegisterHint(size_t* free_until, const SsaLivenessAnalysis& liveness) const;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100707
708 // If there is enough at the definition site to find a register (for example
709 // it uses the same input as the first input), returns the register as a hint.
710 // Returns kNoRegister otherwise.
711 int FindHintAtDefinition() const;
712
713 // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
714 // slots for spilling.
715 bool NeedsTwoSpillSlots() const;
716
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100717 bool IsFloatingPoint() const {
718 return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
719 }
720
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100721 // Converts the location of the interval to a `Location` object.
722 Location ToLocation() const;
723
724 // Returns the location of the interval following its siblings at `position`.
David Brazdil5b8e6a52015-02-25 16:17:05 +0000725 Location GetLocationAt(size_t position);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100726
David Brazdil241a4862015-04-16 17:59:03 +0100727 // Finds the sibling that is defined at `position`.
728 LiveInterval* GetSiblingAt(size_t position);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100729
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100730 // Returns whether `other` and `this` share the same kind of register.
731 bool SameRegisterKind(Location other) const;
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000732 bool SameRegisterKind(const LiveInterval& other) const {
733 return IsFloatingPoint() == other.IsFloatingPoint();
734 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100735
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000736 bool HasHighInterval() const {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000737 return IsLowInterval();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000738 }
739
740 bool HasLowInterval() const {
741 return IsHighInterval();
742 }
743
744 LiveInterval* GetLowInterval() const {
745 DCHECK(HasLowInterval());
746 return high_or_low_interval_;
747 }
748
749 LiveInterval* GetHighInterval() const {
750 DCHECK(HasHighInterval());
751 return high_or_low_interval_;
752 }
753
754 bool IsHighInterval() const {
755 return GetParent()->is_high_interval_;
756 }
757
758 bool IsLowInterval() const {
759 return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr);
760 }
761
762 void SetLowInterval(LiveInterval* low) {
763 DCHECK(IsHighInterval());
764 high_or_low_interval_ = low;
765 }
766
767 void SetHighInterval(LiveInterval* high) {
768 DCHECK(IsLowInterval());
769 high_or_low_interval_ = high;
770 }
771
772 void AddHighInterval(bool is_temp = false) {
Nicolas Geoffray1ba19812015-04-21 09:12:40 +0100773 DCHECK(IsParent());
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000774 DCHECK(!HasHighInterval());
775 DCHECK(!HasLowInterval());
776 high_or_low_interval_ = new (allocator_) LiveInterval(
777 allocator_, type_, defined_by_, false, kNoRegister, is_temp, false, true);
778 high_or_low_interval_->high_or_low_interval_ = this;
779 if (first_range_ != nullptr) {
780 high_or_low_interval_->first_range_ = first_range_->Dup(allocator_);
David Brazdilc08675c2015-04-17 15:49:51 +0100781 high_or_low_interval_->last_range_ = high_or_low_interval_->first_range_->GetLastRange();
David Brazdil3fc992f2015-04-16 18:31:55 +0100782 high_or_low_interval_->range_search_start_ = high_or_low_interval_->first_range_;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000783 }
784 if (first_use_ != nullptr) {
785 high_or_low_interval_->first_use_ = first_use_->Dup(allocator_);
786 }
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100787
788 if (first_env_use_ != nullptr) {
789 high_or_low_interval_->first_env_use_ = first_env_use_->Dup(allocator_);
790 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000791 }
792
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000793 // Returns whether an interval, when it is non-split, is using
794 // the same register of one of its input.
795 bool IsUsingInputRegister() const {
David Brazdil3fc992f2015-04-16 18:31:55 +0100796 CHECK(kIsDebugBuild) << "Function should be used only for DCHECKs";
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000797 if (defined_by_ != nullptr && !IsSplit()) {
798 for (HInputIterator it(defined_by_); !it.Done(); it.Advance()) {
799 LiveInterval* interval = it.Current()->GetLiveInterval();
800
David Brazdil3fc992f2015-04-16 18:31:55 +0100801 // Find the interval that covers `defined_by`_. Calls to this function
802 // are made outside the linear scan, hence we need to use CoversSlow.
803 while (interval != nullptr && !interval->CoversSlow(defined_by_->GetLifetimePosition())) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000804 interval = interval->GetNextSibling();
805 }
806
807 // Check if both intervals have the same register of the same kind.
808 if (interval != nullptr
809 && interval->SameRegisterKind(*this)
810 && interval->GetRegister() == GetRegister()) {
811 return true;
812 }
813 }
814 }
815 return false;
816 }
817
818 // Returns whether an interval, when it is non-split, can safely use
819 // the same register of one of its input. Note that this method requires
820 // IsUsingInputRegister() to be true.
821 bool CanUseInputRegister() const {
David Brazdil3fc992f2015-04-16 18:31:55 +0100822 CHECK(kIsDebugBuild) << "Function should be used only for DCHECKs";
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000823 DCHECK(IsUsingInputRegister());
824 if (defined_by_ != nullptr && !IsSplit()) {
825 LocationSummary* locations = defined_by_->GetLocations();
826 if (locations->OutputCanOverlapWithInputs()) {
827 return false;
828 }
829 for (HInputIterator it(defined_by_); !it.Done(); it.Advance()) {
830 LiveInterval* interval = it.Current()->GetLiveInterval();
831
David Brazdil3fc992f2015-04-16 18:31:55 +0100832 // Find the interval that covers `defined_by`_. Calls to this function
833 // are made outside the linear scan, hence we need to use CoversSlow.
834 while (interval != nullptr && !interval->CoversSlow(defined_by_->GetLifetimePosition())) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000835 interval = interval->GetNextSibling();
836 }
837
838 if (interval != nullptr
839 && interval->SameRegisterKind(*this)
840 && interval->GetRegister() == GetRegister()) {
841 // We found the input that has the same register. Check if it is live after
842 // `defined_by`_.
David Brazdil3fc992f2015-04-16 18:31:55 +0100843 return !interval->CoversSlow(defined_by_->GetLifetimePosition() + 1);
Nicolas Geoffray829280c2015-01-28 10:20:37 +0000844 }
845 }
846 }
847 LOG(FATAL) << "Unreachable";
848 UNREACHABLE();
849 }
850
Nicolas Geoffray5588e582015-04-14 14:10:59 +0100851 void AddSafepoint(HInstruction* instruction) {
852 SafepointPosition* safepoint = new (allocator_) SafepointPosition(instruction);
853 if (first_safepoint_ == nullptr) {
854 first_safepoint_ = last_safepoint_ = safepoint;
855 } else {
856 DCHECK_LT(last_safepoint_->GetPosition(), safepoint->GetPosition());
857 last_safepoint_->SetNext(safepoint);
858 last_safepoint_ = safepoint;
859 }
860 }
861
862 SafepointPosition* GetFirstSafepoint() const {
Nicolas Geoffray5588e582015-04-14 14:10:59 +0100863 return first_safepoint_;
864 }
865
David Brazdil3fc992f2015-04-16 18:31:55 +0100866 // Resets the starting point for range-searching queries to the first range.
867 // Intervals must be reset prior to starting a new linear scan over them.
868 void ResetSearchCache() {
869 range_search_start_ = first_range_;
870 }
871
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100872 private:
Mingyao Yang296bd602014-10-06 16:47:28 -0700873 LiveInterval(ArenaAllocator* allocator,
874 Primitive::Type type,
875 HInstruction* defined_by = nullptr,
876 bool is_fixed = false,
877 int reg = kNoRegister,
878 bool is_temp = false,
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000879 bool is_slow_path_safepoint = false,
880 bool is_high_interval = false)
Mingyao Yang296bd602014-10-06 16:47:28 -0700881 : allocator_(allocator),
882 first_range_(nullptr),
883 last_range_(nullptr),
David Brazdil3fc992f2015-04-16 18:31:55 +0100884 range_search_start_(nullptr),
Nicolas Geoffray5588e582015-04-14 14:10:59 +0100885 first_safepoint_(nullptr),
886 last_safepoint_(nullptr),
Mingyao Yang296bd602014-10-06 16:47:28 -0700887 first_use_(nullptr),
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +0100888 first_env_use_(nullptr),
Mingyao Yang296bd602014-10-06 16:47:28 -0700889 type_(type),
890 next_sibling_(nullptr),
891 parent_(this),
892 register_(reg),
893 spill_slot_(kNoSpillSlot),
894 is_fixed_(is_fixed),
895 is_temp_(is_temp),
896 is_slow_path_safepoint_(is_slow_path_safepoint),
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000897 is_high_interval_(is_high_interval),
898 high_or_low_interval_(nullptr),
Mingyao Yang296bd602014-10-06 16:47:28 -0700899 defined_by_(defined_by) {}
900
David Brazdil3fc992f2015-04-16 18:31:55 +0100901 // Searches for a LiveRange that either covers the given position or is the
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700902 // first next LiveRange. Returns null if no such LiveRange exists. Ranges
David Brazdil3fc992f2015-04-16 18:31:55 +0100903 // known to end before `position` can be skipped with `search_start`.
904 LiveRange* FindRangeAtOrAfter(size_t position, LiveRange* search_start) const {
David Brazdil5b8e6a52015-02-25 16:17:05 +0000905 if (kIsDebugBuild) {
David Brazdil3fc992f2015-04-16 18:31:55 +0100906 if (search_start != first_range_) {
907 // If we are not searching the entire list of ranges, make sure we do
908 // not skip the range we are searching for.
909 if (search_start == nullptr) {
910 DCHECK(IsDeadAt(position));
911 } else if (search_start->GetStart() > position) {
912 DCHECK_EQ(search_start, FindRangeAtOrAfter(position, first_range_));
913 }
David Brazdil5b8e6a52015-02-25 16:17:05 +0000914 }
915 }
916
David Brazdil3fc992f2015-04-16 18:31:55 +0100917 LiveRange* range;
918 for (range = search_start;
919 range != nullptr && range->GetEnd() <= position;
920 range = range->GetNext()) {
921 continue;
David Brazdil5b8e6a52015-02-25 16:17:05 +0000922 }
David Brazdil3fc992f2015-04-16 18:31:55 +0100923 return range;
David Brazdil5b8e6a52015-02-25 16:17:05 +0000924 }
925
Nicolas Geoffray57902602015-04-21 14:28:41 +0100926 bool DefinitionRequiresRegister() const {
927 DCHECK(IsParent());
928 LocationSummary* locations = defined_by_->GetLocations();
929 Location location = locations->Out();
930 // This interval is the first interval of the instruction. If the output
931 // of the instruction requires a register, we return the position of that instruction
932 // as the first register use.
933 if (location.IsUnallocated()) {
934 if ((location.GetPolicy() == Location::kRequiresRegister)
935 || (location.GetPolicy() == Location::kSameAsFirstInput
936 && (locations->InAt(0).IsRegister()
937 || locations->InAt(0).IsRegisterPair()
938 || locations->InAt(0).GetPolicy() == Location::kRequiresRegister))) {
939 return true;
940 } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
941 || (location.GetPolicy() == Location::kSameAsFirstInput
942 && (locations->InAt(0).IsFpuRegister()
943 || locations->InAt(0).IsFpuRegisterPair()
944 || locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister))) {
945 return true;
946 }
947 } else if (location.IsRegister() || location.IsRegisterPair()) {
948 return true;
949 }
950 return false;
951 }
952
953 bool IsDefiningPosition(size_t position) const {
954 return IsParent() && (position == GetStart());
955 }
956
957 bool HasSynthesizeUseAt(size_t position) const {
958 UsePosition* use = first_use_;
959 while (use != nullptr) {
960 size_t use_position = use->GetPosition();
961 if ((use_position == position) && use->IsSynthesized()) {
962 return true;
963 }
964 if (use_position > position) break;
965 use = use->GetNext();
966 }
967 return false;
968 }
969
970 void AddBackEdgeUses(const HBasicBlock& block_at_use) {
971 DCHECK(block_at_use.IsInLoop());
972 // Add synthesized uses at the back edge of loops to help the register allocator.
973 // Note that this method is called in decreasing liveness order, to faciliate adding
974 // uses at the head of the `first_use_` linked list. Because below
975 // we iterate from inner-most to outer-most, which is in increasing liveness order,
976 // we need to take extra care of how the `first_use_` linked list is being updated.
977 UsePosition* first_in_new_list = nullptr;
978 UsePosition* last_in_new_list = nullptr;
979 for (HLoopInformationOutwardIterator it(block_at_use);
980 !it.Done();
981 it.Advance()) {
982 HLoopInformation* current = it.Current();
983 if (GetDefinedBy()->GetLifetimePosition() >= current->GetHeader()->GetLifetimeStart()) {
984 // This interval is defined in the loop. We can stop going outward.
985 break;
986 }
987
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100988 // We're only adding a synthesized use at the last back edge. Adding syntehsized uses on
989 // all back edges is not necessary: anything used in the loop will have its use at the
990 // last back edge. If we want branches in a loop to have better register allocation than
991 // another branch, then it is the linear order we should change.
992 size_t back_edge_use_position = current->GetLifetimeEnd();
Nicolas Geoffray57902602015-04-21 14:28:41 +0100993 if ((first_use_ != nullptr) && (first_use_->GetPosition() <= back_edge_use_position)) {
994 // There was a use already seen in this loop. Therefore the previous call to `AddUse`
995 // already inserted the backedge use. We can stop going outward.
996 DCHECK(HasSynthesizeUseAt(back_edge_use_position));
997 break;
998 }
999
1000 DCHECK(last_in_new_list == nullptr
1001 || back_edge_use_position > last_in_new_list->GetPosition());
1002
1003 UsePosition* new_use = new (allocator_) UsePosition(
Nicolas Geoffray0a23d742015-05-07 11:57:35 +01001004 /* user */ nullptr,
1005 /* environment */ nullptr,
1006 UsePosition::kNoInput,
1007 back_edge_use_position,
1008 /* next */ nullptr);
Nicolas Geoffray57902602015-04-21 14:28:41 +01001009
1010 if (last_in_new_list != nullptr) {
1011 // Going outward. The latest created use needs to point to the new use.
1012 last_in_new_list->SetNext(new_use);
1013 } else {
1014 // This is the inner-most loop.
1015 DCHECK_EQ(current, block_at_use.GetLoopInformation());
1016 first_in_new_list = new_use;
1017 }
1018 last_in_new_list = new_use;
1019 }
1020 // Link the newly created linked list with `first_use_`.
1021 if (last_in_new_list != nullptr) {
1022 last_in_new_list->SetNext(first_use_);
1023 first_use_ = first_in_new_list;
1024 }
1025 }
1026
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001027 ArenaAllocator* const allocator_;
1028
1029 // Ranges of this interval. We need a quick access to the last range to test
1030 // for liveness (see `IsDeadAt`).
1031 LiveRange* first_range_;
1032 LiveRange* last_range_;
1033
David Brazdil3fc992f2015-04-16 18:31:55 +01001034 // The first range at or after the current position of a linear scan. It is
1035 // used to optimize range-searching queries.
1036 LiveRange* range_search_start_;
1037
Nicolas Geoffray43af7282015-04-16 13:01:01 +01001038 // Safepoints where this interval is live.
Nicolas Geoffray5588e582015-04-14 14:10:59 +01001039 SafepointPosition* first_safepoint_;
1040 SafepointPosition* last_safepoint_;
1041
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001042 // Uses of this interval. Note that this linked list is shared amongst siblings.
1043 UsePosition* first_use_;
Nicolas Geoffray4ed947a2015-04-27 16:58:06 +01001044 UsePosition* first_env_use_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001045
1046 // The instruction type this interval corresponds to.
1047 const Primitive::Type type_;
1048
1049 // Live interval that is the result of a split.
1050 LiveInterval* next_sibling_;
1051
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001052 // The first interval from which split intervals come from.
1053 LiveInterval* parent_;
1054
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001055 // The register allocated to this interval.
1056 int register_;
1057
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001058 // The spill slot allocated to this interval.
1059 int spill_slot_;
1060
1061 // Whether the interval is for a fixed register.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001062 const bool is_fixed_;
1063
1064 // Whether the interval is for a temporary.
1065 const bool is_temp_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001066
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001067 // Whether the interval is for a safepoint that calls on slow path.
1068 const bool is_slow_path_safepoint_;
1069
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001070 // Whether this interval is a synthesized interval for register pair.
1071 const bool is_high_interval_;
1072
1073 // If this interval needs a register pair, the high or low equivalent.
1074 // `is_high_interval_` tells whether this holds the low or the high.
1075 LiveInterval* high_or_low_interval_;
1076
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001077 // The instruction represented by this interval.
1078 HInstruction* const defined_by_;
1079
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001080 static constexpr int kNoRegister = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001081 static constexpr int kNoSpillSlot = -1;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001082
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +00001083 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
1084
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001085 DISALLOW_COPY_AND_ASSIGN(LiveInterval);
1086};
1087
Nicolas Geoffray915b9d02015-03-11 15:11:19 +00001088/**
1089 * Analysis that computes the liveness of instructions:
1090 *
1091 * (a) Non-environment uses of an instruction always make
1092 * the instruction live.
1093 * (b) Environment uses of an instruction whose type is
1094 * object (that is, non-primitive), make the instruction live.
1095 * This is due to having to keep alive objects that have
1096 * finalizers deleting native objects.
1097 * (c) When the graph has the debuggable property, environment uses
1098 * of an instruction that has a primitive type make the instruction live.
1099 * If the graph does not have the debuggable property, the environment
1100 * use has no effect, and may get a 'none' value after register allocation.
1101 *
1102 * (b) and (c) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
1103 */
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001104class SsaLivenessAnalysis : public ValueObject {
1105 public:
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +01001106 SsaLivenessAnalysis(HGraph* graph, CodeGenerator* codegen)
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001107 : graph_(graph),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001108 codegen_(codegen),
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001109 block_infos_(graph->GetBlocks().size(),
1110 nullptr,
1111 graph->GetArena()->Adapter(kArenaAllocSsaLiveness)),
1112 instructions_from_ssa_index_(graph->GetArena()->Adapter(kArenaAllocSsaLiveness)),
1113 instructions_from_lifetime_position_(graph->GetArena()->Adapter(kArenaAllocSsaLiveness)),
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001114 number_of_ssa_values_(0) {
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001115 }
1116
1117 void Analyze();
1118
1119 BitVector* GetLiveInSet(const HBasicBlock& block) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001120 DCHECK_LT(block.GetBlockId(), block_infos_.size());
1121 return &block_infos_[block.GetBlockId()]->live_in_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001122 }
1123
1124 BitVector* GetLiveOutSet(const HBasicBlock& block) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001125 DCHECK_LT(block.GetBlockId(), block_infos_.size());
1126 return &block_infos_[block.GetBlockId()]->live_out_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001127 }
1128
1129 BitVector* GetKillSet(const HBasicBlock& block) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001130 DCHECK_LT(block.GetBlockId(), block_infos_.size());
1131 return &block_infos_[block.GetBlockId()]->kill_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001132 }
1133
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001134 HInstruction* GetInstructionFromSsaIndex(size_t index) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001135 DCHECK_LT(index, instructions_from_ssa_index_.size());
1136 return instructions_from_ssa_index_[index];
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001137 }
1138
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001139 HInstruction* GetInstructionFromPosition(size_t index) const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001140 DCHECK_LT(index, instructions_from_lifetime_position_.size());
1141 return instructions_from_lifetime_position_[index];
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001142 }
1143
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +01001144 HBasicBlock* GetBlockFromPosition(size_t index) const {
Nicolas Geoffrayfbda5f32015-04-29 14:16:00 +01001145 HInstruction* instruction = GetInstructionFromPosition(index);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +01001146 if (instruction == nullptr) {
1147 // If we are at a block boundary, get the block following.
Nicolas Geoffrayfbda5f32015-04-29 14:16:00 +01001148 instruction = GetInstructionFromPosition(index + 1);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +01001149 }
1150 return instruction->GetBlock();
1151 }
1152
Nicolas Geoffrayfbda5f32015-04-29 14:16:00 +01001153 bool IsAtBlockBoundary(size_t index) const {
1154 return GetInstructionFromPosition(index) == nullptr;
1155 }
1156
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001157 HInstruction* GetTempUser(LiveInterval* temp) const {
1158 // A temporary shares the same lifetime start as the instruction that requires it.
1159 DCHECK(temp->IsTemp());
Nicolas Geoffrayf01d3442015-03-27 17:15:49 +00001160 HInstruction* user = GetInstructionFromPosition(temp->GetStart() / 2);
1161 DCHECK_EQ(user, temp->GetFirstUse()->GetUser());
1162 return user;
1163 }
1164
1165 size_t GetTempIndex(LiveInterval* temp) const {
1166 // We use the input index to store the index of the temporary in the user's temporary list.
1167 DCHECK(temp->IsTemp());
1168 return temp->GetFirstUse()->GetInputIndex();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +01001169 }
1170
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001171 size_t GetMaxLifetimePosition() const {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001172 return instructions_from_lifetime_position_.size() * 2 - 1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001173 }
1174
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001175 size_t GetNumberOfSsaValues() const {
1176 return number_of_ssa_values_;
1177 }
1178
Andreas Gampe7c3952f2015-02-19 18:21:24 -08001179 static constexpr const char* kLivenessPassName = "liveness";
1180
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001181 private:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +01001182 // Linearize the graph so that:
1183 // (1): a block is always after its dominator,
1184 // (2): blocks of loops are contiguous.
1185 // This creates a natural and efficient ordering when visualizing live ranges.
1186 void LinearizeGraph();
1187
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001188 // Give an SSA number to each instruction that defines a value used by another instruction,
1189 // and setup the lifetime information of each instruction and block.
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001190 void NumberInstructions();
1191
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001192 // Compute live ranges of instructions, as well as live_in, live_out and kill sets.
1193 void ComputeLiveness();
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001194
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +01001195 // Compute the live ranges of instructions, as well as the initial live_in, live_out and
1196 // kill sets, that do not take into account backward branches.
1197 void ComputeLiveRanges();
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001198
1199 // After computing the initial sets, this method does a fixed point
1200 // calculation over the live_in and live_out set to take into account
1201 // backwards branches.
1202 void ComputeLiveInAndLiveOutSets();
1203
1204 // Update the live_in set of the block and returns whether it has changed.
1205 bool UpdateLiveIn(const HBasicBlock& block);
1206
1207 // Update the live_out set of the block and returns whether it has changed.
1208 bool UpdateLiveOut(const HBasicBlock& block);
1209
Mingyao Yang718493c2015-07-22 15:56:34 -07001210 // Returns whether `instruction` in an HEnvironment held by `env_holder`
1211 // should be kept live by the HEnvironment.
1212 static bool ShouldBeLiveForEnvironment(HInstruction* env_holder,
1213 HInstruction* instruction) {
Nicolas Geoffray915b9d02015-03-11 15:11:19 +00001214 if (instruction == nullptr) return false;
Mingyao Yang718493c2015-07-22 15:56:34 -07001215 // A value that's not live in compiled code may still be needed in interpreter,
1216 // due to code motion, etc.
1217 if (env_holder->IsDeoptimize()) return true;
David Brazdil77a48ae2015-09-15 12:34:04 +00001218 // A value live at a throwing instruction in a try block may be copied by
1219 // the exception handler to its location at the top of the catch block.
1220 if (env_holder->CanThrowIntoCatchBlock()) return true;
Nicolas Geoffray915b9d02015-03-11 15:11:19 +00001221 if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true;
1222 return instruction->GetType() == Primitive::kPrimNot;
1223 }
1224
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +01001225 HGraph* const graph_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001226 CodeGenerator* const codegen_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001227 ArenaVector<BlockInfo*> block_infos_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001228
1229 // Temporary array used when computing live_in, live_out, and kill sets.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001230 ArenaVector<HInstruction*> instructions_from_ssa_index_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001231
1232 // Temporary array used when inserting moves in the graph.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +01001233 ArenaVector<HInstruction*> instructions_from_lifetime_position_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001234 size_t number_of_ssa_values_;
1235
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +01001236 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
Nicolas Geoffray23a81882015-06-01 18:12:38 +01001237 ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +01001238
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001239 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
1240};
1241
Nicolas Geoffray804d0932014-05-02 08:46:00 +01001242} // namespace art
1243
1244#endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_