blob: 8f6a26cd115f388f4f0699199162a1247b6f6cf5 [file] [log] [blame]
Nicolas Geoffray818f2102014-02-18 16:43:35 +00001/*
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_NODES_H_
18#define ART_COMPILER_OPTIMIZING_NODES_H_
19
20#include "utils/allocation.h"
21#include "utils/growable_array.h"
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000022#include "dex/arena_bit_vector.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000023
24namespace art {
25
26class HBasicBlock;
27class HInstruction;
28class HGraphVisitor;
29
30static const int kDefaultNumberOfBlocks = 8;
31static const int kDefaultNumberOfSuccessors = 2;
32static const int kDefaultNumberOfPredecessors = 2;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000033static const int kDefaultNumberOfBackEdges = 1;
Nicolas Geoffray818f2102014-02-18 16:43:35 +000034
35// Control-flow graph of a method. Contains a list of basic blocks.
36class HGraph : public ArenaObject {
37 public:
38 explicit HGraph(ArenaAllocator* arena)
39 : arena_(arena),
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000040 blocks_(arena, kDefaultNumberOfBlocks),
41 dominator_order_(arena, kDefaultNumberOfBlocks) { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +000042
43 ArenaAllocator* arena() const { return arena_; }
44 const GrowableArray<HBasicBlock*>* blocks() const { return &blocks_; }
45
46 void AddBlock(HBasicBlock* block);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000047 void BuildDominatorTree();
Nicolas Geoffray818f2102014-02-18 16:43:35 +000048
49 private:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000050 HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
51 void VisitBlockForDominatorTree(HBasicBlock* block,
52 HBasicBlock* predecessor,
53 GrowableArray<size_t>* visits);
54 void FindBackEdges(ArenaBitVector* visited) const;
55 void VisitBlockForBackEdges(HBasicBlock* block,
56 ArenaBitVector* visited,
57 ArenaBitVector* visiting) const;
58 void RemoveDeadBlocks(const ArenaBitVector& visited) const;
59
60 HBasicBlock* GetEntryBlock() const { return blocks_.Get(0); }
61
Nicolas Geoffray818f2102014-02-18 16:43:35 +000062 ArenaAllocator* const arena_;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000063
64 // List of blocks in insertion order.
Nicolas Geoffray818f2102014-02-18 16:43:35 +000065 GrowableArray<HBasicBlock*> blocks_;
66
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000067 // List of blocks to perform a pre-order dominator tree traversal.
68 GrowableArray<HBasicBlock*> dominator_order_;
69
Nicolas Geoffray818f2102014-02-18 16:43:35 +000070 DISALLOW_COPY_AND_ASSIGN(HGraph);
71};
72
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +000073class HLoopInformation : public ArenaObject {
74 public:
75 HLoopInformation(HBasicBlock* header, HGraph* graph)
76 : header_(header),
77 back_edges_(graph->arena(), kDefaultNumberOfBackEdges) { }
78
79 void AddBackEdge(HBasicBlock* back_edge) {
80 back_edges_.Add(back_edge);
81 }
82
83 int NumberOfBackEdges() const {
84 return back_edges_.Size();
85 }
86
87 private:
88 HBasicBlock* header_;
89 GrowableArray<HBasicBlock*> back_edges_;
90
91 DISALLOW_COPY_AND_ASSIGN(HLoopInformation);
92};
93
Nicolas Geoffray818f2102014-02-18 16:43:35 +000094// A block in a method. Contains the list of instructions represented
95// as a double linked list. Each block knows its predecessors and
96// successors.
97class HBasicBlock : public ArenaObject {
98 public:
99 explicit HBasicBlock(HGraph* graph)
100 : graph_(graph),
101 predecessors_(graph->arena(), kDefaultNumberOfPredecessors),
102 successors_(graph->arena(), kDefaultNumberOfSuccessors),
103 first_instruction_(nullptr),
104 last_instruction_(nullptr),
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000105 loop_information_(nullptr),
106 dominator_(nullptr),
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000107 block_id_(-1) { }
108
109 const GrowableArray<HBasicBlock*>* predecessors() const {
110 return &predecessors_;
111 }
112
113 const GrowableArray<HBasicBlock*>* successors() const {
114 return &successors_;
115 }
116
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000117 void AddBackEdge(HBasicBlock* back_edge) {
118 if (loop_information_ == nullptr) {
119 loop_information_ = new (graph_->arena()) HLoopInformation(this, graph_);
120 }
121 loop_information_->AddBackEdge(back_edge);
122 }
123
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000124 HGraph* graph() const { return graph_; }
125
126 int block_id() const { return block_id_; }
127 void set_block_id(int id) { block_id_ = id; }
128
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000129 HBasicBlock* dominator() const { return dominator_; }
130 void set_dominator(HBasicBlock* dominator) { dominator_ = dominator; }
131
132 int NumberOfBackEdges() const {
133 return loop_information_ == nullptr
134 ? 0
135 : loop_information_->NumberOfBackEdges();
136 }
137
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000138 HInstruction* first_instruction() const { return first_instruction_; }
139 HInstruction* last_instruction() const { return last_instruction_; }
140
141 void AddSuccessor(HBasicBlock* block) {
142 successors_.Add(block);
143 block->predecessors_.Add(this);
144 }
145
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000146 void RemovePredecessor(HBasicBlock* block) {
147 predecessors_.Delete(block);
148 }
149
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000150 void AddInstruction(HInstruction* instruction);
151
152 private:
153 HGraph* const graph_;
154 GrowableArray<HBasicBlock*> predecessors_;
155 GrowableArray<HBasicBlock*> successors_;
156 HInstruction* first_instruction_;
157 HInstruction* last_instruction_;
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000158 HLoopInformation* loop_information_;
159 HBasicBlock* dominator_;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000160 int block_id_;
161
162 DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
163};
164
165#define FOR_EACH_INSTRUCTION(M) \
166 M(Exit) \
167 M(Goto) \
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000168 M(If) \
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000169 M(ReturnVoid) \
170
171#define DECLARE_INSTRUCTION(type) \
172 virtual void Accept(HGraphVisitor* visitor); \
173 virtual const char* DebugName() const { return #type; } \
174
175class HInstruction : public ArenaObject {
176 public:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000177 HInstruction() : previous_(nullptr), next_(nullptr) { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000178 virtual ~HInstruction() { }
179
180 HInstruction* next() const { return next_; }
181 HInstruction* previous() const { return previous_; }
182
183 virtual intptr_t InputCount() const = 0;
184 virtual HInstruction* InputAt(intptr_t i) const = 0;
185
186 virtual void Accept(HGraphVisitor* visitor) = 0;
187 virtual const char* DebugName() const = 0;
188
189 private:
190 HInstruction* previous_;
191 HInstruction* next_;
192
193 friend class HBasicBlock;
194
195 DISALLOW_COPY_AND_ASSIGN(HInstruction);
196};
197
198class HInstructionIterator : public ValueObject {
199 public:
200 explicit HInstructionIterator(HBasicBlock* block)
201 : instruction_(block->first_instruction()) {
202 next_ = Done() ? nullptr : instruction_->next();
203 }
204
205 inline bool Done() const { return instruction_ == nullptr; }
206 inline HInstruction* Current() { return instruction_; }
207 inline void Advance() {
208 instruction_ = next_;
209 next_ = Done() ? nullptr : instruction_->next();
210 }
211
212 private:
213 HInstruction* instruction_;
214 HInstruction* next_;
215};
216
217// An embedded container with N elements of type T. Used (with partial
218// specialization for N=0) because embedded arrays cannot have size 0.
219template<typename T, intptr_t N>
220class EmbeddedArray {
221 public:
222 EmbeddedArray() : elements_() { }
223
224 intptr_t length() const { return N; }
225
226 const T& operator[](intptr_t i) const {
227 ASSERT(i < length());
228 return elements_[i];
229 }
230
231 T& operator[](intptr_t i) {
232 ASSERT(i < length());
233 return elements_[i];
234 }
235
236 const T& At(intptr_t i) const {
237 return (*this)[i];
238 }
239
240 void SetAt(intptr_t i, const T& val) {
241 (*this)[i] = val;
242 }
243
244 private:
245 T elements_[N];
246};
247
248template<typename T>
249class EmbeddedArray<T, 0> {
250 public:
251 intptr_t length() const { return 0; }
252 const T& operator[](intptr_t i) const {
253 LOG(FATAL) << "Unreachable";
254 static T sentinel = 0;
255 return sentinel;
256 }
257 T& operator[](intptr_t i) {
258 LOG(FATAL) << "Unreachable";
259 static T sentinel = 0;
260 return sentinel;
261 }
262};
263
264template<intptr_t N>
265class HTemplateInstruction: public HInstruction {
266 public:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000267 HTemplateInstruction<N>() : inputs_() { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000268 virtual ~HTemplateInstruction() { }
269
270 virtual intptr_t InputCount() const { return N; }
271 virtual HInstruction* InputAt(intptr_t i) const { return inputs_[i]; }
272
273 private:
274 EmbeddedArray<HInstruction*, N> inputs_;
275};
276
277// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
278// instruction that branches to the exit block.
279class HReturnVoid : public HTemplateInstruction<0> {
280 public:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000281 HReturnVoid() { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000282
283 DECLARE_INSTRUCTION(ReturnVoid)
284
285 private:
286 DISALLOW_COPY_AND_ASSIGN(HReturnVoid);
287};
288
289// The exit instruction is the only instruction of the exit block.
290// Instructions aborting the method (HTrow and HReturn) must branch to the
291// exit block.
292class HExit : public HTemplateInstruction<0> {
293 public:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000294 HExit() { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000295
296 DECLARE_INSTRUCTION(Exit)
297
298 private:
299 DISALLOW_COPY_AND_ASSIGN(HExit);
300};
301
302// Jumps from one block to another.
303class HGoto : public HTemplateInstruction<0> {
304 public:
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000305 HGoto() { }
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000306
307 DECLARE_INSTRUCTION(Goto)
308
309 private:
310 DISALLOW_COPY_AND_ASSIGN(HGoto);
311};
312
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000313// Conditional branch. A block ending with an HIf instruction must have
314// two successors.
315// TODO: Make it take an input.
316class HIf : public HTemplateInstruction<0> {
317 public:
318 HIf() { }
319
320 DECLARE_INSTRUCTION(If)
321
322 private:
323 DISALLOW_COPY_AND_ASSIGN(HIf);
324};
325
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000326class HGraphVisitor : public ValueObject {
327 public:
328 explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
329 virtual ~HGraphVisitor() { }
330
331 virtual void VisitInstruction(HInstruction* instruction) { }
332 virtual void VisitBasicBlock(HBasicBlock* block);
333
334 void VisitInsertionOrder();
335
336 // Visit functions for instruction classes.
337#define DECLARE_VISIT_INSTRUCTION(name) \
338 virtual void Visit##name(H##name* instr) { VisitInstruction(instr); }
339
340 FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
341
342#undef DECLARE_VISIT_INSTRUCTION
343
344 private:
345 HGraph* graph_;
346
347 DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
348};
349
350} // namespace art
351
352#endif // ART_COMPILER_OPTIMIZING_NODES_H_