blob: 2d914363fccab9e46e41d0056bb773ed09f6d3ba [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
24class BlockInfo : public ArenaObject {
25 public:
26 BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values)
27 : block_(block),
28 live_in_(allocator, number_of_ssa_values, false),
29 live_out_(allocator, number_of_ssa_values, false),
30 kill_(allocator, number_of_ssa_values, false) {
31 live_in_.ClearAllBits();
32 live_out_.ClearAllBits();
33 kill_.ClearAllBits();
34 }
35
36 private:
37 const HBasicBlock& block_;
38 ArenaBitVector live_in_;
39 ArenaBitVector live_out_;
40 ArenaBitVector kill_;
41
42 friend class SsaLivenessAnalysis;
43
44 DISALLOW_COPY_AND_ASSIGN(BlockInfo);
45};
46
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010047/**
48 * A live range contains the start and end of a range where an instruction
49 * is live.
50 */
51class LiveRange : public ValueObject {
52 public:
53 LiveRange(size_t start, size_t end) : start_(start), end_(end) {
54 DCHECK_LT(start, end);
55 }
56
57 size_t GetStart() const { return start_; }
58 size_t GetEnd() const { return end_; }
59
60 private:
61 size_t start_;
62 size_t end_;
63};
64
65static constexpr int kDefaultNumberOfRanges = 3;
66
67/**
68 * An interval is a list of disjoint live ranges where an instruction is live.
69 * Each instruction that has uses gets an interval.
70 */
71class LiveInterval : public ArenaObject {
72 public:
73 explicit LiveInterval(ArenaAllocator* allocator) : ranges_(allocator, kDefaultNumberOfRanges) {}
74
75 void AddUse(HInstruction* instruction) {
76 size_t position = instruction->GetLifetimePosition();
77 size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
78 size_t end_block_position = instruction->GetBlock()->GetLifetimeEnd();
79 if (ranges_.IsEmpty()) {
80 // First time we see a use of that interval.
81 ranges_.Add(LiveRange(start_block_position, position));
82 } else if (ranges_.Peek().GetStart() == start_block_position) {
83 // There is a use later in the same block.
84 DCHECK_LE(position, ranges_.Peek().GetEnd());
85 } else if (ranges_.Peek().GetStart() == end_block_position + 1) {
86 // Last use is in a following block.
87 LiveRange existing = ranges_.Pop();
88 ranges_.Add(LiveRange(start_block_position, existing.GetEnd()));
89 } else {
90 // There is a hole in the interval. Create a new range.
91 ranges_.Add(LiveRange(start_block_position, position));
92 }
93 }
94
95 void AddRange(size_t start, size_t end) {
96 if (ranges_.IsEmpty()) {
97 ranges_.Add(LiveRange(start, end));
98 } else if (ranges_.Peek().GetStart() == end + 1) {
99 // There is a use in the following block.
100 LiveRange existing = ranges_.Pop();
101 ranges_.Add(LiveRange(start, existing.GetEnd()));
102 } else {
103 // There is a hole in the interval. Create a new range.
104 ranges_.Add(LiveRange(start, end));
105 }
106 }
107
108 void AddLoopRange(size_t start, size_t end) {
109 DCHECK(!ranges_.IsEmpty());
110 while (!ranges_.IsEmpty() && ranges_.Peek().GetEnd() < end) {
111 DCHECK_LE(start, ranges_.Peek().GetStart());
112 ranges_.Pop();
113 }
114 if (ranges_.IsEmpty()) {
115 // Uses are only in the loop.
116 ranges_.Add(LiveRange(start, end));
117 } else {
118 // There are uses after the loop.
119 LiveRange range = ranges_.Pop();
120 ranges_.Add(LiveRange(start, range.GetEnd()));
121 }
122 }
123
124 void SetFrom(size_t from) {
125 DCHECK(!ranges_.IsEmpty());
126 LiveRange existing = ranges_.Pop();
127 ranges_.Add(LiveRange(from, existing.GetEnd()));
128 }
129
130 const GrowableArray<LiveRange>& GetRanges() const { return ranges_; }
131
132 private:
133 GrowableArray<LiveRange> ranges_;
134
135 DISALLOW_COPY_AND_ASSIGN(LiveInterval);
136};
137
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100138class SsaLivenessAnalysis : public ValueObject {
139 public:
140 explicit SsaLivenessAnalysis(const HGraph& graph)
141 : graph_(graph),
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100142 linear_post_order_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100143 block_infos_(graph.GetArena(), graph.GetBlocks().Size()),
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100144 instructions_from_ssa_index_(graph.GetArena(), 0),
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100145 number_of_ssa_values_(0) {
146 block_infos_.SetSize(graph.GetBlocks().Size());
147 }
148
149 void Analyze();
150
151 BitVector* GetLiveInSet(const HBasicBlock& block) const {
152 return &block_infos_.Get(block.GetBlockId())->live_in_;
153 }
154
155 BitVector* GetLiveOutSet(const HBasicBlock& block) const {
156 return &block_infos_.Get(block.GetBlockId())->live_out_;
157 }
158
159 BitVector* GetKillSet(const HBasicBlock& block) const {
160 return &block_infos_.Get(block.GetBlockId())->kill_;
161 }
162
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100163 const GrowableArray<HBasicBlock*>& GetLinearPostOrder() const {
164 return linear_post_order_;
165 }
166
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100167 HInstruction* GetInstructionFromSsaIndex(size_t index) {
168 return instructions_from_ssa_index_.Get(index);
169 }
170
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100171 private:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100172 // Linearize the graph so that:
173 // (1): a block is always after its dominator,
174 // (2): blocks of loops are contiguous.
175 // This creates a natural and efficient ordering when visualizing live ranges.
176 void LinearizeGraph();
177
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100178 // Give an SSA number to each instruction that defines a value used by another instruction,
179 // and setup the lifetime information of each instruction and block.
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100180 void NumberInstructions();
181
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100182 // Compute live ranges of instructions, as well as live_in, live_out and kill sets.
183 void ComputeLiveness();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100184
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100185 // Compute the live ranges of instructions, as well as the initial live_in, live_out and
186 // kill sets, that do not take into account backward branches.
187 void ComputeLiveRanges();
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100188
189 // After computing the initial sets, this method does a fixed point
190 // calculation over the live_in and live_out set to take into account
191 // backwards branches.
192 void ComputeLiveInAndLiveOutSets();
193
194 // Update the live_in set of the block and returns whether it has changed.
195 bool UpdateLiveIn(const HBasicBlock& block);
196
197 // Update the live_out set of the block and returns whether it has changed.
198 bool UpdateLiveOut(const HBasicBlock& block);
199
200 const HGraph& graph_;
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100201 GrowableArray<HBasicBlock*> linear_post_order_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100202 GrowableArray<BlockInfo*> block_infos_;
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100203 GrowableArray<HInstruction*> instructions_from_ssa_index_;
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100204 size_t number_of_ssa_values_;
205
206 DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
207};
208
209} // namespace art
210
211#endif // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_