blob: 7dda4f61d5b8f9daea78f24ef808397d584fbb02 [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
Nicolas Geoffray804d0932014-05-02 08:46:00 +010028class BlockInfo : public ArenaObject {
29 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 */
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010056class LiveRange : public ArenaObject {
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
67 bool IntersectsWith(const LiveRange& other) {
68 return (start_ >= other.start_ && start_ < other.end_)
69 || (other.start_ >= start_ && other.start_ < end_);
70 }
71
72 bool IsBefore(const LiveRange& other) {
73 return end_ <= other.start_;
74 }
75
76 void Dump(std::ostream& stream) {
77 stream << "[" << start_ << ", " << end_ << ")";
78 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010079
80 private:
81 size_t start_;
Nicolas Geoffray76905622014-09-25 14:39:26 +010082 size_t end_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010083 LiveRange* next_;
84
85 friend class LiveInterval;
86
87 DISALLOW_COPY_AND_ASSIGN(LiveRange);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010088};
89
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010090/**
91 * A use position represents a live interval use at a given position.
92 */
93class UsePosition : public ArenaObject {
94 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010095 UsePosition(HInstruction* user,
96 size_t input_index,
97 bool is_environment,
98 size_t position,
99 UsePosition* next)
100 : user_(user),
101 input_index_(input_index),
102 is_environment_(is_environment),
103 position_(position),
104 next_(next) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100105 DCHECK(user->IsPhi()
106 || (GetPosition() == user->GetLifetimePosition() + 1)
107 || (GetPosition() == user->GetLifetimePosition()));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100108 DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition());
109 }
110
111 size_t GetPosition() const { return position_; }
112
113 UsePosition* GetNext() const { return next_; }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100114 void SetNext(UsePosition* next) { next_ = next; }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100115
116 HInstruction* GetUser() const { return user_; }
117
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100118 bool GetIsEnvironment() const { return is_environment_; }
119
120 size_t GetInputIndex() const { return input_index_; }
121
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100122 void Dump(std::ostream& stream) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100123 stream << position_;
124 }
125
126 private:
127 HInstruction* const user_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100128 const size_t input_index_;
129 const bool is_environment_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100130 const size_t position_;
Nicolas Geoffray76905622014-09-25 14:39:26 +0100131 UsePosition* next_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100132
133 DISALLOW_COPY_AND_ASSIGN(UsePosition);
134};
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100135
136/**
137 * An interval is a list of disjoint live ranges where an instruction is live.
138 * Each instruction that has uses gets an interval.
139 */
140class LiveInterval : public ArenaObject {
141 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100142 LiveInterval(ArenaAllocator* allocator,
143 Primitive::Type type,
144 HInstruction* defined_by = nullptr,
145 bool is_fixed = false,
146 int reg = kNoRegister,
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100147 bool is_temp = false,
148 bool is_slow_path_safepoint = false)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100149 : allocator_(allocator),
150 first_range_(nullptr),
151 last_range_(nullptr),
152 first_use_(nullptr),
153 type_(type),
154 next_sibling_(nullptr),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100155 parent_(this),
Nicolas Geoffray39468442014-09-02 15:17:15 +0100156 register_(reg),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100157 spill_slot_(kNoSpillSlot),
Nicolas Geoffray39468442014-09-02 15:17:15 +0100158 is_fixed_(is_fixed),
159 is_temp_(is_temp),
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100160 is_slow_path_safepoint_(is_slow_path_safepoint),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100161 defined_by_(defined_by) {}
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_; }
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100177 bool IsSlowPathSafepoint() const { return is_slow_path_safepoint_; }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100178
179 void AddUse(HInstruction* instruction, size_t input_index, bool is_environment) {
180 // Set the use within the instruction.
Nicolas Geoffray76905622014-09-25 14:39:26 +0100181 size_t position = instruction->GetLifetimePosition();
182 if (instruction->GetLocations()->InputOverlapsWithOutputOrTemp(input_index, is_environment)) {
183 // If it overlaps, we need to make sure the user will not try to allocate a temp
184 // or its output to the same register.
185 ++position;
186 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100187 if ((first_use_ != nullptr)
188 && (first_use_->GetUser() == instruction)
189 && (first_use_->GetPosition() < position)) {
190 // The user uses the instruction multiple times, and one use dies before the other.
191 // We update the use list so that the latter is first.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100192 UsePosition* cursor = first_use_;
193 while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) {
194 cursor = cursor->GetNext();
195 }
Nicolas Geoffray76905622014-09-25 14:39:26 +0100196 DCHECK(first_use_->GetPosition() + 1 == position);
197 UsePosition* new_use = new (allocator_) UsePosition(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100198 instruction, input_index, is_environment, position, cursor->GetNext());
199 cursor->SetNext(new_use);
Nicolas Geoffray76905622014-09-25 14:39:26 +0100200 if (first_range_->GetEnd() == first_use_->GetPosition()) {
201 first_range_->end_ = position;
202 }
203 return;
204 }
205
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100206 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100207 if (first_range_ == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100208 // First time we see a use of that interval.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100209 first_range_ = last_range_ = new (allocator_) LiveRange(
210 start_block_position, position, nullptr);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100211 } else if (first_range_->GetStart() == start_block_position) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100212 // There is a use later in the same block or in a following block.
213 // Note that in such a case, `AddRange` for the whole blocks has been called
214 // before arriving in this method, and this is the reason the start of
215 // `first_range_` is before the given `position`.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100216 DCHECK_LE(position, first_range_->GetEnd());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100217 } else {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100218 DCHECK(first_range_->GetStart() > position);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100219 // There is a hole in the interval. Create a new range.
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100220 // Note that the start of `first_range_` can be equal to `end`: two blocks
221 // having adjacent lifetime positions are not necessarily
222 // predecessor/successor. When two blocks are predecessor/successor, the
223 // liveness algorithm has called `AddRange` before arriving in this method,
224 // and the check line 205 would succeed.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100225 first_range_ = new (allocator_) LiveRange(start_block_position, position, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100226 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100227 first_use_ = new (allocator_) UsePosition(
228 instruction, input_index, is_environment, position, first_use_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100229 }
230
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100231 void AddPhiUse(HInstruction* instruction, size_t input_index, HBasicBlock* block) {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100232 DCHECK(instruction->IsPhi());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100233 first_use_ = new (allocator_) UsePosition(
234 instruction, input_index, false, block->GetLifetimeEnd(), first_use_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100235 }
236
237 void AddRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100238 if (first_range_ == nullptr) {
239 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, first_range_);
240 } else if (first_range_->GetStart() == end) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100241 // There is a use in the following block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242 first_range_->start_ = start;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100243 } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) {
244 DCHECK(is_fixed_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100245 } else {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100246 DCHECK_GT(first_range_->GetStart(), end);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100247 // There is a hole in the interval. Create a new range.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100248 first_range_ = new (allocator_) LiveRange(start, end, first_range_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100249 }
250 }
251
252 void AddLoopRange(size_t start, size_t end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100253 DCHECK(first_range_ != nullptr);
254 while (first_range_ != nullptr && first_range_->GetEnd() < end) {
255 DCHECK_LE(start, first_range_->GetStart());
256 first_range_ = first_range_->GetNext();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100257 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100258 if (first_range_ == nullptr) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100259 // Uses are only in the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100260 first_range_ = last_range_ = new (allocator_) LiveRange(start, end, nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100261 } else {
262 // There are uses after the loop.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 first_range_->start_ = start;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100264 }
265 }
266
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100267 bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; }
Nicolas Geoffray39468442014-09-02 15:17:15 +0100268 void SetSpillSlot(int slot) {
269 DCHECK(!is_fixed_);
270 DCHECK(!is_temp_);
271 spill_slot_ = slot;
272 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100273 int GetSpillSlot() const { return spill_slot_; }
274
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100275 void SetFrom(size_t from) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100276 if (first_range_ != nullptr) {
277 first_range_->start_ = from;
278 } else {
279 // Instruction without uses.
280 DCHECK(!defined_by_->HasUses());
281 DCHECK(from == defined_by_->GetLifetimePosition());
282 first_range_ = last_range_ = new (allocator_) LiveRange(from, from + 2, nullptr);
283 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100284 }
285
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100286 LiveInterval* GetParent() const { return parent_; }
287
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100288 LiveRange* GetFirstRange() const { return first_range_; }
289
290 int GetRegister() const { return register_; }
291 void SetRegister(int reg) { register_ = reg; }
292 void ClearRegister() { register_ = kNoRegister; }
293 bool HasRegister() const { return register_ != kNoRegister; }
294
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100295 bool IsDeadAt(size_t position) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100296 return last_range_->GetEnd() <= position;
297 }
298
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100299 bool Covers(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100300 if (IsDeadAt(position)) {
301 return false;
302 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100303 LiveRange* current = first_range_;
304 while (current != nullptr) {
305 if (position >= current->GetStart() && position < current->GetEnd()) {
306 return true;
307 }
308 current = current->GetNext();
309 }
310 return false;
311 }
312
313 /**
314 * Returns the first intersection of this interval with `other`.
315 */
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100316 size_t FirstIntersectionWith(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100317 // Advance both intervals and find the first matching range start in
318 // this interval.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100319 LiveRange* my_range = first_range_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100320 LiveRange* other_range = other->first_range_;
321 do {
322 if (my_range->IntersectsWith(*other_range)) {
323 return std::max(my_range->GetStart(), other_range->GetStart());
324 } else if (my_range->IsBefore(*other_range)) {
325 my_range = my_range->GetNext();
326 if (my_range == nullptr) {
327 return kNoLifetime;
328 }
329 } else {
330 DCHECK(other_range->IsBefore(*my_range));
331 other_range = other_range->GetNext();
332 if (other_range == nullptr) {
333 return kNoLifetime;
334 }
335 }
336 } while (true);
337 }
338
339 size_t GetStart() const {
340 return first_range_->GetStart();
341 }
342
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100343 size_t GetEnd() const {
344 return last_range_->GetEnd();
345 }
346
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100347 size_t FirstRegisterUseAfter(size_t position) const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100348 if (is_temp_) {
349 return position == GetStart() ? position : kNoLifetime;
350 }
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100351 if (position == GetStart() && defined_by_ != nullptr) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100352 LocationSummary* locations = defined_by_->GetLocations();
353 Location location = locations->Out();
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100354 // This interval is the first interval of the instruction. If the output
355 // of the instruction requires a register, we return the position of that instruction
356 // as the first register use.
357 if (location.IsUnallocated()) {
358 if ((location.GetPolicy() == Location::kRequiresRegister)
359 || (location.GetPolicy() == Location::kSameAsFirstInput
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100360 && locations->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100361 return position;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100362 } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
363 || (location.GetPolicy() == Location::kSameAsFirstInput
364 && locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister)) {
365 return position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100366 }
367 }
368 }
369
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100370 UsePosition* use = first_use_;
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100371 size_t end = GetEnd();
372 while (use != nullptr && use->GetPosition() <= end) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100373 size_t use_position = use->GetPosition();
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100374 if (use_position > position && !use->GetIsEnvironment()) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100375 Location location = use->GetUser()->GetLocations()->InAt(use->GetInputIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100376 if (location.IsUnallocated()
377 && (location.GetPolicy() == Location::kRequiresRegister
378 || location.GetPolicy() == Location::kRequiresFpuRegister)) {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +0100379 return use_position;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100380 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100381 }
382 use = use->GetNext();
383 }
384 return kNoLifetime;
385 }
386
387 size_t FirstRegisterUse() const {
388 return FirstRegisterUseAfter(GetStart());
389 }
390
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100391 UsePosition* GetFirstUse() const {
392 return first_use_;
393 }
394
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100395 Primitive::Type GetType() const {
396 return type_;
397 }
398
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100399 HInstruction* GetDefinedBy() const {
400 return defined_by_;
401 }
402
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100403 /**
404 * Split this interval at `position`. This interval is changed to:
405 * [start ... position).
406 *
407 * The new interval covers:
408 * [position ... end)
409 */
410 LiveInterval* SplitAt(size_t position) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100411 DCHECK(!is_temp_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100412 DCHECK(!is_fixed_);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100413 DCHECK_GT(position, GetStart());
414
415 if (last_range_->GetEnd() <= position) {
416 // This range dies before `position`, no need to split.
417 return nullptr;
418 }
419
420 LiveInterval* new_interval = new (allocator_) LiveInterval(allocator_, type_);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100421 new_interval->next_sibling_ = next_sibling_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100422 next_sibling_ = new_interval;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100423 new_interval->parent_ = parent_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100424
425 new_interval->first_use_ = first_use_;
426 LiveRange* current = first_range_;
427 LiveRange* previous = nullptr;
428 // Iterate over the ranges, and either find a range that covers this position, or
429 // a two ranges in between this position (that is, the position is in a lifetime hole).
430 do {
431 if (position >= current->GetEnd()) {
432 // Move to next range.
433 previous = current;
434 current = current->next_;
435 } else if (position <= current->GetStart()) {
436 // If the previous range did not cover this position, we know position is in
437 // a lifetime hole. We can just break the first_range_ and last_range_ links
438 // and return the new interval.
439 DCHECK(previous != nullptr);
440 DCHECK(current != first_range_);
441 new_interval->last_range_ = last_range_;
442 last_range_ = previous;
443 previous->next_ = nullptr;
444 new_interval->first_range_ = current;
445 return new_interval;
446 } else {
447 // This range covers position. We create a new last_range_ for this interval
448 // that covers last_range_->Start() and position. We also shorten the current
449 // range and make it the first range of the new interval.
450 DCHECK(position < current->GetEnd() && position > current->GetStart());
451 new_interval->last_range_ = last_range_;
452 last_range_ = new (allocator_) LiveRange(current->start_, position, nullptr);
453 if (previous != nullptr) {
454 previous->next_ = last_range_;
455 } else {
456 first_range_ = last_range_;
457 }
458 new_interval->first_range_ = current;
459 current->start_ = position;
460 return new_interval;
461 }
462 } while (current != nullptr);
463
464 LOG(FATAL) << "Unreachable";
465 return nullptr;
466 }
467
Nicolas Geoffray76905622014-09-25 14:39:26 +0100468 bool StartsBeforeOrAt(LiveInterval* other) const {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100469 return GetStart() <= other->GetStart();
470 }
471
472 bool StartsAfter(LiveInterval* other) const {
Nicolas Geoffray76905622014-09-25 14:39:26 +0100473 return GetStart() > other->GetStart();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100474 }
475
476 void Dump(std::ostream& stream) const {
477 stream << "ranges: { ";
478 LiveRange* current = first_range_;
479 do {
480 current->Dump(stream);
481 stream << " ";
482 } while ((current = current->GetNext()) != nullptr);
483 stream << "}, uses: { ";
484 UsePosition* use = first_use_;
485 if (use != nullptr) {
486 do {
487 use->Dump(stream);
488 stream << " ";
489 } while ((use = use->GetNext()) != nullptr);
490 }
491 stream << "}";
492 }
493
494 LiveInterval* GetNextSibling() const { return next_sibling_; }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100495
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100496 // Returns the first register hint that is at least free before
497 // the value contained in `free_until`. If none is found, returns
498 // `kNoRegister`.
499 int FindFirstRegisterHint(size_t* free_until) const;
500
501 // If there is enough at the definition site to find a register (for example
502 // it uses the same input as the first input), returns the register as a hint.
503 // Returns kNoRegister otherwise.
504 int FindHintAtDefinition() const;
505
506 // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
507 // slots for spilling.
508 bool NeedsTwoSpillSlots() const;
509
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100510 bool IsFloatingPoint() const {
511 return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
512 }
513
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100514 // Converts the location of the interval to a `Location` object.
515 Location ToLocation() const;
516
517 // Returns the location of the interval following its siblings at `position`.
518 Location GetLocationAt(size_t position) const;
519
520 // Finds the interval that covers `position`.
521 const LiveInterval& GetIntervalAt(size_t position) const;
522
523 bool IsTemp() const { return is_temp_; }
524
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100525 // Returns whether `other` and `this` share the same kind of register.
526 bool SameRegisterKind(Location other) const;
527
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100528 private:
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100529 ArenaAllocator* const allocator_;
530
531 // Ranges of this interval. We need a quick access to the last range to test
532 // for liveness (see `IsDeadAt`).
533 LiveRange* first_range_;
534 LiveRange* last_range_;
535
536 // Uses of this interval. Note that this linked list is shared amongst siblings.
537 UsePosition* first_use_;
538
539 // The instruction type this interval corresponds to.
540 const Primitive::Type type_;
541
542 // Live interval that is the result of a split.
543 LiveInterval* next_sibling_;
544
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100545 // The first interval from which split intervals come from.
546 LiveInterval* parent_;
547
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100548 // The register allocated to this interval.
549 int register_;
550
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100551 // The spill slot allocated to this interval.
552 int spill_slot_;
553
554 // Whether the interval is for a fixed register.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100555 const bool is_fixed_;
556
557 // Whether the interval is for a temporary.
558 const bool is_temp_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100559
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100560 // Whether the interval is for a safepoint that calls on slow path.
561 const bool is_slow_path_safepoint_;
562
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100563 // The instruction represented by this interval.
564 HInstruction* const defined_by_;
565
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100566 static constexpr int kNoRegister = -1;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100567 static constexpr int kNoSpillSlot = -1;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100568
569 DISALLOW_COPY_AND_ASSIGN(LiveInterval);
570};
571
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100572class SsaLivenessAnalysis : public ValueObject {
573 public:
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100574 SsaLivenessAnalysis(const HGraph& graph, CodeGenerator* codegen)
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100575 : graph_(graph),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100576 codegen_(codegen),
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100577 linear_post_order_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100578 block_infos_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100579 instructions_from_ssa_index_(graph.GetArena(), 0),
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100580 instructions_from_lifetime_position_(graph.GetArena(), 0),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100581 number_of_ssa_values_(0) {
582 block_infos_.SetSize(graph.GetBlocks().Size());
583 }
584
585 void Analyze();
586
587 BitVector* GetLiveInSet(const HBasicBlock& block) const {
588 return &block_infos_.Get(block.GetBlockId())->live_in_;
589 }
590
591 BitVector* GetLiveOutSet(const HBasicBlock& block) const {
592 return &block_infos_.Get(block.GetBlockId())->live_out_;
593 }
594
595 BitVector* GetKillSet(const HBasicBlock& block) const {
596 return &block_infos_.Get(block.GetBlockId())->kill_;
597 }
598
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100599 const GrowableArray<HBasicBlock*>& GetLinearPostOrder() const {
600 return linear_post_order_;
601 }
602
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100603 HInstruction* GetInstructionFromSsaIndex(size_t index) const {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100604 return instructions_from_ssa_index_.Get(index);
605 }
606
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100607 HInstruction* GetInstructionFromPosition(size_t index) const {
608 return instructions_from_lifetime_position_.Get(index);
609 }
610
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100611 HInstruction* GetTempUser(LiveInterval* temp) const {
612 // A temporary shares the same lifetime start as the instruction that requires it.
613 DCHECK(temp->IsTemp());
614 return GetInstructionFromPosition(temp->GetStart() / 2);
615 }
616
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100617 size_t GetMaxLifetimePosition() const {
618 return instructions_from_lifetime_position_.Size() * 2 - 1;
619 }
620
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100621 size_t GetNumberOfSsaValues() const {
622 return number_of_ssa_values_;
623 }
624
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100625 private:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100626 // Linearize the graph so that:
627 // (1): a block is always after its dominator,
628 // (2): blocks of loops are contiguous.
629 // This creates a natural and efficient ordering when visualizing live ranges.
630 void LinearizeGraph();
631
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100632 // Give an SSA number to each instruction that defines a value used by another instruction,
633 // and setup the lifetime information of each instruction and block.
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100634 void NumberInstructions();
635
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100636 // Compute live ranges of instructions, as well as live_in, live_out and kill sets.
637 void ComputeLiveness();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100638
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100639 // Compute the live ranges of instructions, as well as the initial live_in, live_out and
640 // kill sets, that do not take into account backward branches.
641 void ComputeLiveRanges();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100642
643 // After computing the initial sets, this method does a fixed point
644 // calculation over the live_in and live_out set to take into account
645 // backwards branches.
646 void ComputeLiveInAndLiveOutSets();
647
648 // Update the live_in set of the block and returns whether it has changed.
649 bool UpdateLiveIn(const HBasicBlock& block);
650
651 // Update the live_out set of the block and returns whether it has changed.
652 bool UpdateLiveOut(const HBasicBlock& block);
653
654 const HGraph& graph_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100655 CodeGenerator* const codegen_;
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100656 GrowableArray<HBasicBlock*> linear_post_order_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100657 GrowableArray<BlockInfo*> block_infos_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100658
659 // Temporary array used when computing live_in, live_out, and kill sets.
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100660 GrowableArray<HInstruction*> instructions_from_ssa_index_;
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100661
662 // Temporary array used when inserting moves in the graph.
663 GrowableArray<HInstruction*> instructions_from_lifetime_position_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100664 size_t number_of_ssa_values_;
665
666 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
667};
668
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100669class HLinearOrderIterator : public ValueObject {
670 public:
671 explicit HLinearOrderIterator(const SsaLivenessAnalysis& liveness)
672 : post_order_(liveness.GetLinearPostOrder()), index_(liveness.GetLinearPostOrder().Size()) {}
673
674 bool Done() const { return index_ == 0; }
675 HBasicBlock* Current() const { return post_order_.Get(index_ -1); }
676 void Advance() { --index_; DCHECK_GE(index_, 0U); }
677
678 private:
679 const GrowableArray<HBasicBlock*>& post_order_;
680 size_t index_;
681
682 DISALLOW_COPY_AND_ASSIGN(HLinearOrderIterator);
683};
684
685class HLinearPostOrderIterator : public ValueObject {
686 public:
687 explicit HLinearPostOrderIterator(const SsaLivenessAnalysis& liveness)
688 : post_order_(liveness.GetLinearPostOrder()), index_(0) {}
689
690 bool Done() const { return index_ == post_order_.Size(); }
691 HBasicBlock* Current() const { return post_order_.Get(index_); }
692 void Advance() { ++index_; }
693
694 private:
695 const GrowableArray<HBasicBlock*>& post_order_;
696 size_t index_;
697
698 DISALLOW_COPY_AND_ASSIGN(HLinearPostOrderIterator);
699};
700
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100701} // namespace art
702
703#endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_