blob: b0d38531e903e5367e404ae45c92f70c808e5dde [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"
21
22namespace art {
23
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010024class CodeGenerator;
25
Nicolas Geoffray01ef3452014-10-01 11:32:17 +010026static constexpr int kNoRegister = -1;
27
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070028class BlockInfo : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffray804d0932014-05-02 08:46:00 +010029 public:
30 BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values)
31 : block_(block),
32 live_in_(allocator, number_of_ssa_values, false),
33 live_out_(allocator, number_of_ssa_values, false),
34 kill_(allocator, number_of_ssa_values, false) {
Ian Rogerscf7f1912014-10-22 22:06:39 -070035 UNUSED(block_);
Nicolas Geoffray804d0932014-05-02 08:46:00 +010036 live_in_.ClearAllBits();
37 live_out_.ClearAllBits();
38 kill_.ClearAllBits();
39 }
40
41 private:
42 const HBasicBlock& block_;
43 ArenaBitVector live_in_;
44 ArenaBitVector live_out_;
45 ArenaBitVector kill_;
46
47 friend class SsaLivenessAnalysis;
48
49 DISALLOW_COPY_AND_ASSIGN(BlockInfo);
50};
51
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010052/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010053 * A live range contains the start and end of a range where an instruction or a temporary
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010054 * is live.
55 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070056class LiveRange FINAL : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010057 public:
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010058 LiveRange(size_t start, size_t end, LiveRange* next) : start_(start), end_(end), next_(next) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010059 DCHECK_LT(start, end);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060 DCHECK(next_ == nullptr || next_->GetStart() > GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010061 }
62
63 size_t GetStart() const { return start_; }
64 size_t GetEnd() const { return end_; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010065 LiveRange* GetNext() const { return next_; }
66
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070067 bool IntersectsWith(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010068 return (start_ >= other.start_ && start_ < other.end_)
69 || (other.start_ >= start_ && other.start_ < end_);
70 }
71
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070072 bool IsBefore(const LiveRange& other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010073 return end_ <= other.start_;
74 }
75
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070076 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010077 stream << "[" << start_ << ", " << end_ << ")";
78 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010079
Nicolas Geoffray840e5462015-01-07 16:01:24 +000080 LiveRange* Dup(ArenaAllocator* allocator) const {
81 return new (allocator) LiveRange(
82 start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator));
83 }
84
85 LiveRange* GetLastRange() {
86 return next_ == nullptr ? this : next_->GetLastRange();
87 }
88
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010089 private:
90 size_t start_;
Nicolas Geoffray76905622014-09-25 14:39:26 +010091 size_t end_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010092 LiveRange* next_;
93
94 friend class LiveInterval;
95
96 DISALLOW_COPY_AND_ASSIGN(LiveRange);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010097};
98
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010099/**
100 * A use position represents a live interval use at a given position.
101 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700102class UsePosition : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100103 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100104 UsePosition(HInstruction* user,
105 size_t input_index,
106 bool is_environment,
107 size_t position,
108 UsePosition* next)
109 : user_(user),
110 input_index_(input_index),
111 is_environment_(is_environment),
112 position_(position),
113 next_(next) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100114 DCHECK(user->IsPhi()
115 || (GetPosition() == user->GetLifetimePosition() + 1)
116 || (GetPosition() == user->GetLifetimePosition()));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100117 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition());
118 }
119
120 size_t GetPosition() const { return position_; }
121
122 UsePosition* GetNext() const { return next_; }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100123 void SetNext(UsePosition* next) { next_ = next; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100124
125 HInstruction* GetUser() const { return user_; }
126
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100127 bool GetIsEnvironment() const { return is_environment_; }
128
129 size_t GetInputIndex() const { return input_index_; }
130
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100131 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100132 stream << position_;
133 }
134
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000135 UsePosition* Dup(ArenaAllocator* allocator) const {
136 return new (allocator) UsePosition(
137 user_, input_index_, is_environment_, position_,
138 next_ == nullptr ? nullptr : next_->Dup(allocator));
139 }
140
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100141 private:
142 HInstruction* const user_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100143 const size_t input_index_;
144 const bool is_environment_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 const size_t position_;
Nicolas Geoffray76905622014-09-25 14:39:26 +0100146 UsePosition* next_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100147
148 DISALLOW_COPY_AND_ASSIGN(UsePosition);
149};
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100150
151/**
152 * An interval is a list of disjoint live ranges where an instruction is live.
153 * Each instruction that has uses gets an interval.
154 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700155class LiveInterval : public ArenaObject<kArenaAllocMisc> {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100156 public:
Mingyao Yang296bd602014-10-06 16:47:28 -0700157 static LiveInterval* MakeInterval(ArenaAllocator* allocator,
158 Primitive::Type type,
159 HInstruction* instruction = nullptr) {
160 return new (allocator) LiveInterval(allocator, type, instruction);
161 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100162
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100163 static LiveInterval* MakeSlowPathInterval(ArenaAllocator* allocator, HInstruction* instruction) {
164 return new (allocator) LiveInterval(
165 allocator, Primitive::kPrimVoid, instruction, false, kNoRegister, false, true);
166 }
167
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100168 static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100169 return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
170 }
171
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100172 static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) {
173 return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100174 }
175
176 bool IsFixed() const { return is_fixed_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700177 bool IsTemp() const { return is_temp_; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100178 bool IsSlowPathSafepoint() const { return is_slow_path_safepoint_; }
Mingyao Yang296bd602014-10-06 16:47:28 -0700179 // This interval is the result of a split.
180 bool IsSplit() const { return parent_ != this; }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100181
182 void AddUse(HInstruction* instruction, size_t input_index, bool is_environment) {
183 // Set the use within the instruction.
Nicolas Geoffray76905622014-09-25 14:39:26 +0100184 size_t position = instruction->GetLifetimePosition();
185 if (instruction->GetLocations()->InputOverlapsWithOutputOrTemp(input_index, is_environment)) {
186 // If it overlaps, we need to make sure the user will not try to allocate a temp
187 // or its output to the same register.
188 ++position;
189 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100190 if ((first_use_ != nullptr)
191 && (first_use_->GetUser() == instruction)
192 && (first_use_->GetPosition() < position)) {
193 // The user uses the instruction multiple times, and one use dies before the other.
194 // We update the use list so that the latter is first.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100195 UsePosition* cursor = first_use_;
196 while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) {
197 cursor = cursor->GetNext();
198 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100199 DCHECK(first_use_->GetPosition() + 1 == position);
200 UsePosition* new_use = new (allocator_) UsePosition(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100201 instruction, input_index, is_environment, position, cursor->GetNext());
202 cursor->SetNext(new_use);
Nicolas Geoffray76905622014-09-25 14:39:26 +0100203 if (first_range_->GetEnd() == first_use_->GetPosition()) {
204 first_range_->end_ = position;
205 }
206 return;
207 }
208
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100209 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100210 if (first_range_ == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100211 // First time we see a use of that interval.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100212 first_range_ = last_range_ = new (allocator_) LiveRange(
213 start_block_position, position, nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100214 } else if (first_range_->GetStart() == start_block_position) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100215 // There is a use later in the same block or in a following block.
216 // Note that in such a case, `AddRange` for the whole blocks has been called
217 // before arriving in this method, and this is the reason the start of
218 // `first_range_` is before the given `position`.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100219 DCHECK_LE(position, first_range_->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100220 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100221 DCHECK(first_range_->GetStart() > position);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100222 // There is a hole in the interval. Create a new range.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100223 // Note that the start of `first_range_` can be equal to `end`: two blocks
224 // having adjacent lifetime positions are not necessarily
225 // predecessor/successor. When two blocks are predecessor/successor, the
226 // liveness algorithm has called `AddRange` before arriving in this method,
227 // and the check line 205 would succeed.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100228 first_range_ = new (allocator_) LiveRange(start_block_position, position, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100229 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100230 first_use_ = new (allocator_) UsePosition(
231 instruction, input_index, is_environment, position, first_use_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100232 }
233
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100234 void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100235 DCHECK(instruction->IsPhi());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100236 first_use_ = new (allocator_) UsePosition(
237 instruction, input_index, false, block->GetLifetimeEnd(), first_use_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100238 }
239
240 void AddRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100241 if (first_range_ == nullptr) {
242 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, first_range_);
243 } else if (first_range_->GetStart() == end) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100244 // There is a use in the following block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100245 first_range_->start_ = start;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100246 } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) {
247 DCHECK(is_fixed_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100248 } else {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100249 DCHECK_GT(first_range_->GetStart(), end);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100250 // There is a hole in the interval. Create a new range.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100251 first_range_ = new (allocator_) LiveRange(start, end, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100252 }
253 }
254
255 void AddLoopRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100256 DCHECK(first_range_ != nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000257 DCHECK_LE(start, first_range_->GetStart());
258 // Find the range that covers the positions after the loop.
259 LiveRange* after_loop = first_range_;
260 LiveRange* last_in_loop = nullptr;
261 while (after_loop != nullptr && after_loop->GetEnd() < end) {
262 DCHECK_LE(start, after_loop->GetStart());
263 last_in_loop = after_loop;
264 after_loop = after_loop->GetNext();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100265 }
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000266 if (after_loop == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100267 // Uses are only in the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100268 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, nullptr);
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000269 } else if (after_loop->GetStart() <= end) {
270 first_range_ = after_loop;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100271 // There are uses after the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100272 first_range_->start_ = start;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000273 } else {
274 // The use after the loop is after a lifetime hole.
275 DCHECK(last_in_loop != nullptr);
276 first_range_ = last_in_loop;
277 first_range_->start_ = start;
278 first_range_->end_ = end;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100279 }
280 }
281
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100282 bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100283 void SetSpillSlot(int slot) {
284 DCHECK(!is_fixed_);
285 DCHECK(!is_temp_);
286 spill_slot_ = slot;
287 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100288 int GetSpillSlot() const { return spill_slot_; }
289
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100290 void SetFrom(size_t from) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100291 if (first_range_ != nullptr) {
292 first_range_->start_ = from;
293 } else {
294 // Instruction without uses.
295 DCHECK(!defined_by_->HasUses());
296 DCHECK(from == defined_by_->GetLifetimePosition());
297 first_range_ = last_range_ = new (allocator_) LiveRange(from, from + 2, nullptr);
298 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100299 }
300
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100301 LiveInterval* GetParent() const { return parent_; }
302
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100303 LiveRange* GetFirstRange() const { return first_range_; }
304
305 int GetRegister() const { return register_; }
306 void SetRegister(int reg) { register_ = reg; }
307 void ClearRegister() { register_ = kNoRegister; }
308 bool HasRegister() const { return register_ != kNoRegister; }
309
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100310 bool IsDeadAt(size_t position) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100311 return last_range_->GetEnd() <= position;
312 }
313
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100314 bool Covers(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100315 if (IsDeadAt(position)) {
316 return false;
317 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100318 LiveRange* current = first_range_;
319 while (current != nullptr) {
320 if (position >= current->GetStart() && position < current->GetEnd()) {
321 return true;
322 }
323 current = current->GetNext();
324 }
325 return false;
326 }
327
328 /**
329 * Returns the first intersection of this interval with `other`.
330 */
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100331 size_t FirstIntersectionWith(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100332 // Advance both intervals and find the first matching range start in
333 // this interval.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100334 LiveRange* my_range = first_range_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100335 LiveRange* other_range = other->first_range_;
336 do {
337 if (my_range->IntersectsWith(*other_range)) {
338 return std::max(my_range->GetStart(), other_range->GetStart());
339 } else if (my_range->IsBefore(*other_range)) {
340 my_range = my_range->GetNext();
341 if (my_range == nullptr) {
342 return kNoLifetime;
343 }
344 } else {
345 DCHECK(other_range->IsBefore(*my_range));
346 other_range = other_range->GetNext();
347 if (other_range == nullptr) {
348 return kNoLifetime;
349 }
350 }
351 } while (true);
352 }
353
354 size_t GetStart() const {
355 return first_range_->GetStart();
356 }
357
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100358 size_t GetEnd() const {
359 return last_range_->GetEnd();
360 }
361
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100362 size_t FirstRegisterUseAfter(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100363 if (is_temp_) {
364 return position == GetStart() ? position : kNoLifetime;
365 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100366 if (position == GetStart() && defined_by_ != nullptr) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100367 LocationSummary* locations = defined_by_->GetLocations();
368 Location location = locations->Out();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100369 // This interval is the first interval of the instruction. If the output
370 // of the instruction requires a register, we return the position of that instruction
371 // as the first register use.
372 if (location.IsUnallocated()) {
373 if ((location.GetPolicy() == Location::kRequiresRegister)
374 || (location.GetPolicy() == Location::kSameAsFirstInput
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100375 && locations->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100376 return position;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100377 } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
378 || (location.GetPolicy() == Location::kSameAsFirstInput
379 && locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister)) {
380 return position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100381 }
382 }
383 }
384
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100385 UsePosition* use = first_use_;
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100386 size_t end = GetEnd();
387 while (use != nullptr && use->GetPosition() <= end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100388 size_t use_position = use->GetPosition();
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100389 if (use_position > position && !use->GetIsEnvironment()) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100390 Location location = use->GetUser()->GetLocations()->InAt(use->GetInputIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100391 if (location.IsUnallocated()
392 && (location.GetPolicy() == Location::kRequiresRegister
393 || location.GetPolicy() == Location::kRequiresFpuRegister)) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100394 return use_position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100395 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100396 }
397 use = use->GetNext();
398 }
399 return kNoLifetime;
400 }
401
402 size_t FirstRegisterUse() const {
403 return FirstRegisterUseAfter(GetStart());
404 }
405
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100406 UsePosition* GetFirstUse() const {
407 return first_use_;
408 }
409
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100410 Primitive::Type GetType() const {
411 return type_;
412 }
413
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100414 HInstruction* GetDefinedBy() const {
415 return defined_by_;
416 }
417
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100418 /**
419 * Split this interval at `position`. This interval is changed to:
420 * [start ... position).
421 *
422 * The new interval covers:
423 * [position ... end)
424 */
425 LiveInterval* SplitAt(size_t position) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100426 DCHECK(!is_temp_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100427 DCHECK(!is_fixed_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100428 DCHECK_GT(position, GetStart());
429
430 if (last_range_->GetEnd() <= position) {
431 // This range dies before `position`, no need to split.
432 return nullptr;
433 }
434
435 LiveInterval* new_interval = new (allocator_) LiveInterval(allocator_, type_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100436 new_interval->next_sibling_ = next_sibling_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100437 next_sibling_ = new_interval;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100438 new_interval->parent_ = parent_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100439
440 new_interval->first_use_ = first_use_;
441 LiveRange* current = first_range_;
442 LiveRange* previous = nullptr;
443 // Iterate over the ranges, and either find a range that covers this position, or
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000444 // two ranges in between this position (that is, the position is in a lifetime hole).
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100445 do {
446 if (position >= current->GetEnd()) {
447 // Move to next range.
448 previous = current;
449 current = current->next_;
450 } else if (position <= current->GetStart()) {
451 // If the previous range did not cover this position, we know position is in
452 // a lifetime hole. We can just break the first_range_ and last_range_ links
453 // and return the new interval.
454 DCHECK(previous != nullptr);
455 DCHECK(current != first_range_);
456 new_interval->last_range_ = last_range_;
457 last_range_ = previous;
458 previous->next_ = nullptr;
459 new_interval->first_range_ = current;
460 return new_interval;
461 } else {
462 // This range covers position. We create a new last_range_ for this interval
463 // that covers last_range_->Start() and position. We also shorten the current
464 // range and make it the first range of the new interval.
465 DCHECK(position < current->GetEnd() && position > current->GetStart());
466 new_interval->last_range_ = last_range_;
467 last_range_ = new (allocator_) LiveRange(current->start_, position, nullptr);
468 if (previous != nullptr) {
469 previous->next_ = last_range_;
470 } else {
471 first_range_ = last_range_;
472 }
473 new_interval->first_range_ = current;
474 current->start_ = position;
475 return new_interval;
476 }
477 } while (current != nullptr);
478
479 LOG(FATAL) << "Unreachable";
480 return nullptr;
481 }
482
Nicolas Geoffray76905622014-09-25 14:39:26 +0100483 bool StartsBeforeOrAt(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100484 return GetStart() <= other->GetStart();
485 }
486
487 bool StartsAfter(LiveInterval* other) const {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100488 return GetStart() > other->GetStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100489 }
490
491 void Dump(std::ostream& stream) const {
492 stream << "ranges: { ";
493 LiveRange* current = first_range_;
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000494 while (current != nullptr) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100495 current->Dump(stream);
496 stream << " ";
Nicolas Geoffrayaedc3282015-01-23 18:01:51 +0000497 current = current->GetNext();
498 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100499 stream << "}, uses: { ";
500 UsePosition* use = first_use_;
501 if (use != nullptr) {
502 do {
503 use->Dump(stream);
504 stream << " ";
505 } while ((use = use->GetNext()) != nullptr);
506 }
507 stream << "}";
Mingyao Yang296bd602014-10-06 16:47:28 -0700508 stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000509 stream << " is_high: " << IsHighInterval();
510 stream << " is_low: " << IsLowInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100511 }
512
513 LiveInterval* GetNextSibling() const { return next_sibling_; }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100514
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100515 // Returns the first register hint that is at least free before
516 // the value contained in `free_until`. If none is found, returns
517 // `kNoRegister`.
518 int FindFirstRegisterHint(size_t* free_until) const;
519
520 // If there is enough at the definition site to find a register (for example
521 // it uses the same input as the first input), returns the register as a hint.
522 // Returns kNoRegister otherwise.
523 int FindHintAtDefinition() const;
524
525 // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
526 // slots for spilling.
527 bool NeedsTwoSpillSlots() const;
528
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100529 bool IsFloatingPoint() const {
530 return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
531 }
532
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100533 // Converts the location of the interval to a `Location` object.
534 Location ToLocation() const;
535
536 // Returns the location of the interval following its siblings at `position`.
537 Location GetLocationAt(size_t position) const;
538
539 // Finds the interval that covers `position`.
540 const LiveInterval& GetIntervalAt(size_t position) const;
541
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100542 // Returns whether `other` and `this` share the same kind of register.
543 bool SameRegisterKind(Location other) const;
544
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000545 bool HasHighInterval() const {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000546 return IsLowInterval();
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000547 }
548
549 bool HasLowInterval() const {
550 return IsHighInterval();
551 }
552
553 LiveInterval* GetLowInterval() const {
554 DCHECK(HasLowInterval());
555 return high_or_low_interval_;
556 }
557
558 LiveInterval* GetHighInterval() const {
559 DCHECK(HasHighInterval());
560 return high_or_low_interval_;
561 }
562
563 bool IsHighInterval() const {
564 return GetParent()->is_high_interval_;
565 }
566
567 bool IsLowInterval() const {
568 return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr);
569 }
570
571 void SetLowInterval(LiveInterval* low) {
572 DCHECK(IsHighInterval());
573 high_or_low_interval_ = low;
574 }
575
576 void SetHighInterval(LiveInterval* high) {
577 DCHECK(IsLowInterval());
578 high_or_low_interval_ = high;
579 }
580
581 void AddHighInterval(bool is_temp = false) {
582 DCHECK_EQ(GetParent(), this);
583 DCHECK(!HasHighInterval());
584 DCHECK(!HasLowInterval());
585 high_or_low_interval_ = new (allocator_) LiveInterval(
586 allocator_, type_, defined_by_, false, kNoRegister, is_temp, false, true);
587 high_or_low_interval_->high_or_low_interval_ = this;
588 if (first_range_ != nullptr) {
589 high_or_low_interval_->first_range_ = first_range_->Dup(allocator_);
590 high_or_low_interval_->last_range_ = first_range_->GetLastRange();
591 }
592 if (first_use_ != nullptr) {
593 high_or_low_interval_->first_use_ = first_use_->Dup(allocator_);
594 }
595 }
596
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100597 private:
Mingyao Yang296bd602014-10-06 16:47:28 -0700598 LiveInterval(ArenaAllocator* allocator,
599 Primitive::Type type,
600 HInstruction* defined_by = nullptr,
601 bool is_fixed = false,
602 int reg = kNoRegister,
603 bool is_temp = false,
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000604 bool is_slow_path_safepoint = false,
605 bool is_high_interval = false)
Mingyao Yang296bd602014-10-06 16:47:28 -0700606 : allocator_(allocator),
607 first_range_(nullptr),
608 last_range_(nullptr),
609 first_use_(nullptr),
610 type_(type),
611 next_sibling_(nullptr),
612 parent_(this),
613 register_(reg),
614 spill_slot_(kNoSpillSlot),
615 is_fixed_(is_fixed),
616 is_temp_(is_temp),
617 is_slow_path_safepoint_(is_slow_path_safepoint),
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000618 is_high_interval_(is_high_interval),
619 high_or_low_interval_(nullptr),
Mingyao Yang296bd602014-10-06 16:47:28 -0700620 defined_by_(defined_by) {}
621
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100622 ArenaAllocator* const allocator_;
623
624 // Ranges of this interval. We need a quick access to the last range to test
625 // for liveness (see `IsDeadAt`).
626 LiveRange* first_range_;
627 LiveRange* last_range_;
628
629 // Uses of this interval. Note that this linked list is shared amongst siblings.
630 UsePosition* first_use_;
631
632 // The instruction type this interval corresponds to.
633 const Primitive::Type type_;
634
635 // Live interval that is the result of a split.
636 LiveInterval* next_sibling_;
637
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100638 // The first interval from which split intervals come from.
639 LiveInterval* parent_;
640
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100641 // The register allocated to this interval.
642 int register_;
643
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100644 // The spill slot allocated to this interval.
645 int spill_slot_;
646
647 // Whether the interval is for a fixed register.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100648 const bool is_fixed_;
649
650 // Whether the interval is for a temporary.
651 const bool is_temp_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100652
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100653 // Whether the interval is for a safepoint that calls on slow path.
654 const bool is_slow_path_safepoint_;
655
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000656 // Whether this interval is a synthesized interval for register pair.
657 const bool is_high_interval_;
658
659 // If this interval needs a register pair, the high or low equivalent.
660 // `is_high_interval_` tells whether this holds the low or the high.
661 LiveInterval* high_or_low_interval_;
662
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100663 // The instruction represented by this interval.
664 HInstruction* const defined_by_;
665
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100666 static constexpr int kNoRegister = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100667 static constexpr int kNoSpillSlot = -1;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100668
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000669 ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
670
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100671 DISALLOW_COPY_AND_ASSIGN(LiveInterval);
672};
673
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100674class SsaLivenessAnalysis : public ValueObject {
675 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100676 SsaLivenessAnalysis(const HGraph& graph, CodeGenerator* codegen)
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100677 : graph_(graph),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100678 codegen_(codegen),
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000679 linear_order_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100680 block_infos_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100681 instructions_from_ssa_index_(graph.GetArena(), 0),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100682 instructions_from_lifetime_position_(graph.GetArena(), 0),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100683 number_of_ssa_values_(0) {
684 block_infos_.SetSize(graph.GetBlocks().Size());
685 }
686
687 void Analyze();
688
689 BitVector* GetLiveInSet(const HBasicBlock& block) const {
690 return &block_infos_.Get(block.GetBlockId())->live_in_;
691 }
692
693 BitVector* GetLiveOutSet(const HBasicBlock& block) const {
694 return &block_infos_.Get(block.GetBlockId())->live_out_;
695 }
696
697 BitVector* GetKillSet(const HBasicBlock& block) const {
698 return &block_infos_.Get(block.GetBlockId())->kill_;
699 }
700
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000701 const GrowableArray<HBasicBlock*>& GetLinearOrder() const {
702 return linear_order_;
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100703 }
704
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100705 HInstruction* GetInstructionFromSsaIndex(size_t index) const {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100706 return instructions_from_ssa_index_.Get(index);
707 }
708
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100709 HInstruction* GetInstructionFromPosition(size_t index) const {
710 return instructions_from_lifetime_position_.Get(index);
711 }
712
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100713 HInstruction* GetTempUser(LiveInterval* temp) const {
714 // A temporary shares the same lifetime start as the instruction that requires it.
715 DCHECK(temp->IsTemp());
716 return GetInstructionFromPosition(temp->GetStart() / 2);
717 }
718
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100719 size_t GetMaxLifetimePosition() const {
720 return instructions_from_lifetime_position_.Size() * 2 - 1;
721 }
722
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100723 size_t GetNumberOfSsaValues() const {
724 return number_of_ssa_values_;
725 }
726
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100727 private:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100728 // Linearize the graph so that:
729 // (1): a block is always after its dominator,
730 // (2): blocks of loops are contiguous.
731 // This creates a natural and efficient ordering when visualizing live ranges.
732 void LinearizeGraph();
733
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100734 // Give an SSA number to each instruction that defines a value used by another instruction,
735 // and setup the lifetime information of each instruction and block.
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100736 void NumberInstructions();
737
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100738 // Compute live ranges of instructions, as well as live_in, live_out and kill sets.
739 void ComputeLiveness();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100740
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100741 // Compute the live ranges of instructions, as well as the initial live_in, live_out and
742 // kill sets, that do not take into account backward branches.
743 void ComputeLiveRanges();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100744
745 // After computing the initial sets, this method does a fixed point
746 // calculation over the live_in and live_out set to take into account
747 // backwards branches.
748 void ComputeLiveInAndLiveOutSets();
749
750 // Update the live_in set of the block and returns whether it has changed.
751 bool UpdateLiveIn(const HBasicBlock& block);
752
753 // Update the live_out set of the block and returns whether it has changed.
754 bool UpdateLiveOut(const HBasicBlock& block);
755
756 const HGraph& graph_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100757 CodeGenerator* const codegen_;
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000758 GrowableArray<HBasicBlock*> linear_order_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100759 GrowableArray<BlockInfo*> block_infos_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100760
761 // Temporary array used when computing live_in, live_out, and kill sets.
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100762 GrowableArray<HInstruction*> instructions_from_ssa_index_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100763
764 // Temporary array used when inserting moves in the graph.
765 GrowableArray<HInstruction*> instructions_from_lifetime_position_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100766 size_t number_of_ssa_values_;
767
768 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
769};
770
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000771class HLinearPostOrderIterator : public ValueObject {
772 public:
773 explicit HLinearPostOrderIterator(const SsaLivenessAnalysis& liveness)
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000774 : order_(liveness.GetLinearOrder()), index_(liveness.GetLinearOrder().Size()) {}
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000775
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000776 bool Done() const { return index_ == 0; }
777
778 HBasicBlock* Current() const { return order_.Get(index_ -1); }
779
780 void Advance() {
781 --index_;
782 DCHECK_GE(index_, 0U);
783 }
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000784
785 private:
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000786 const GrowableArray<HBasicBlock*>& order_;
Nicolas Geoffraye50fa582014-11-24 17:44:15 +0000787 size_t index_;
788
789 DISALLOW_COPY_AND_ASSIGN(HLinearPostOrderIterator);
790};
791
Nicolas Geoffraya8eed3a2014-11-24 17:47:10 +0000792class HLinearOrderIterator : public ValueObject {
793 public:
794 explicit HLinearOrderIterator(const SsaLivenessAnalysis& liveness)
795 : order_(liveness.GetLinearOrder()), index_(0) {}
796
797 bool Done() const { return index_ == order_.Size(); }
798 HBasicBlock* Current() const { return order_.Get(index_); }
799 void Advance() { ++index_; }
800
801 private:
802 const GrowableArray<HBasicBlock*>& order_;
803 size_t index_;
804
805 DISALLOW_COPY_AND_ASSIGN(HLinearOrderIterator);
806};
807
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100808} // namespace art
809
810#endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_