Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: src/flow-graph.h

Issue 1530003: Rework flow graph construction. (Closed)
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 18 matching lines...) Expand all
29 #define V8_FLOW_GRAPH_H_ 29 #define V8_FLOW_GRAPH_H_
30 30
31 #include "v8.h" 31 #include "v8.h"
32 32
33 #include "data-flow.h" 33 #include "data-flow.h"
34 #include "zone.h" 34 #include "zone.h"
35 35
36 namespace v8 { 36 namespace v8 {
37 namespace internal { 37 namespace internal {
38 38
39 // Flow-graph nodes. 39 // The nodes of a flow graph are basic blocks. Basic blocks consist of
40 class Node: public ZoneObject { 40 // instructions represented as pointers to AST nodes in the order that they
41 // would be visited by the code generator. A block can have arbitrarily many
42 // (even zero) predecessors and up to two successors. Blocks with multiple
43 // predecessors are "join nodes" and blocks with multiple successors are
44 // "branch nodes". A block can be both a branch and a join node.
45 //
46 // Flow graphs are in edge split form: a branch node is never the
47 // predecessor of a merge node. Empty basic blocks are inserted to maintain
48 // edge split form.
49 class BasicBlock: public ZoneObject {
41 public: 50 public:
42 Node() : number_(-1), mark_(false) {} 51 // Construct a basic block with a given predecessor. NULL indicates no
52 // predecessor or that the predecessor will be set later.
53 BasicBlock(BasicBlock* predecessor)
fschneider 2010/03/29 13:49:59 explicit for 1-argument constructors?
Kevin Millikin (Chromium) 2010/03/29 14:22:53 Done.
54 : predecessors_(2),
55 instructions_(8),
56 left_successor_(NULL),
57 right_successor_(NULL),
58 mark_(false) {
59 if (predecessor != NULL) AddPredecessor(predecessor);
60 }
43 61
44 virtual ~Node() {} 62 bool HasPredecessor() { return !predecessors_.is_empty(); }
63 bool HasSuccessor() { return left_successor_ != NULL; }
45 64
46 virtual bool IsExitNode() { return false; } 65 // Add a given basic block as a predecessor of this block. This function
47 virtual bool IsBlockNode() { return false; } 66 // also adds this block as a successor of the given block.
48 virtual bool IsBranchNode() { return false; } 67 void AddPredecessor(BasicBlock* predecessor) {
49 virtual bool IsJoinNode() { return false; } 68 ASSERT(predecessor != NULL);
69 predecessors_.Add(predecessor);
70 predecessor->AddSuccessor(this);
71 }
50 72
51 virtual void AddPredecessor(Node* predecessor) = 0; 73 // Add an instruction to the end of this block. The block must be "open"
52 virtual void AddSuccessor(Node* successor) = 0; 74 // by not having a successor yet.
75 void AddInstruction(AstNode* instruction) {
76 ASSERT(!HasSuccessor() && instruction != NULL);
77 instructions_.Add(instruction);
78 }
53 79
54 bool IsMarkedWith(bool mark) { return mark_ == mark; } 80 // Perform a depth-first traversal of graph rooted at this node,
55 void MarkWith(bool mark) { mark_ = mark; } 81 // accumulating pre- and postorder traversal orders. Visited nodes are
56 82 // marked with mark.
57 // Perform a depth first search and record preorder and postorder 83 void BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
58 // traversal orders. 84 ZoneList<BasicBlock*>* postorder,
59 virtual void Traverse(bool mark, 85 bool mark);
60 ZoneList<Node*>* preorder, 86 bool GetMark() { return mark_; }
61 ZoneList<Node*>* postorder) = 0;
62
63 int number() { return number_; }
64 void set_number(int number) { number_ = number; }
65
66 // Functions used by data-flow analyses.
67 virtual void InitializeReachingDefinitions(int definition_count,
68 List<BitVector*>* variables,
69 WorkList<Node>* worklist,
70 bool mark);
71 virtual void ComputeRDOut(BitVector* result) = 0;
72 virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;
73 virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
74
75 // Functions used by dead-code elimination.
76 virtual void MarkCriticalInstructions(
77 List<AstNode*>* stack,
78 ZoneList<Expression*>* body_definitions,
79 int variable_count);
80 87
81 #ifdef DEBUG 88 #ifdef DEBUG
82 void AssignNodeNumber(); 89 // In debug mode, blocks are numbered in reverse postorder to help with
83 void PrintReachingDefinitions(); 90 // printing.
84 virtual void PrintText() = 0; 91 int number() { return number_; }
92 void set_number(int n) { number_ = n; }
93
94 // Print a basic block, given the number of the first instruction.
95 // Returns the next number after the number of the last instruction.
96 int PrintAsText(int instruction_number);
85 #endif 97 #endif
86 98
87 protected: 99 private:
88 ReachingDefinitionsData rd_; 100 // Add a given basic block as successor to this block. This function does
101 // not add this block as a predecessor of the given block so as to avoid
102 // circularity.
103 void AddSuccessor(BasicBlock* successor) {
104 ASSERT(right_successor_ == NULL && successor != NULL);
105 if (HasSuccessor()) {
106 right_successor_ = successor;
107 } else {
108 left_successor_ = successor;
109 }
110 }
89 111
90 private: 112 ZoneList<BasicBlock*> predecessors_;
91 int number_; 113 ZoneList<AstNode*> instructions_;
fschneider 2010/03/29 13:49:59 We probably need an accessor for instructions_. Bu
114 BasicBlock* left_successor_;
115 BasicBlock* right_successor_;
116
117 // Support for graph traversal. Before traversal, all nodes in the graph
118 // have the same mark (true or false). Traversal marks already-visited
119 // nodes with the opposite mark. After traversal, all nodes again have
120 // the same mark. Traversal of the same graph is not reentrant.
92 bool mark_; 121 bool mark_;
93 122
94 DISALLOW_COPY_AND_ASSIGN(Node); 123 #ifdef DEBUG
124 int number_;
125 #endif
126
127 DISALLOW_COPY_AND_ASSIGN(BasicBlock);
95 }; 128 };
96 129
97 130
98 // An exit node has a arbitrarily many predecessors and no successors. 131 // A flow graph has distinguished entry and exit blocks. The entry block is
99 class ExitNode: public Node { 132 // the only one with no predecessors and the exit block is the only one with
133 // no successors.
134 class FlowGraph: public ZoneObject {
100 public: 135 public:
101 ExitNode() : predecessors_(4) {} 136 FlowGraph(BasicBlock* entry, BasicBlock* exit)
102 137 : entry_(entry), exit_(exit), preorder_(8), postorder_(8) {
103 virtual bool IsExitNode() { return true; }
104
105 virtual void AddPredecessor(Node* predecessor) {
106 ASSERT(predecessor != NULL);
107 predecessors_.Add(predecessor);
108 } 138 }
109 139
110 virtual void AddSuccessor(Node* successor) { UNREACHABLE(); } 140 ZoneList<BasicBlock*>* preorder() { return &preorder_; }
111 141 ZoneList<BasicBlock*>* postorder() { return &postorder_; }
112 virtual void Traverse(bool mark,
113 ZoneList<Node*>* preorder,
114 ZoneList<Node*>* postorder);
115
116 virtual void ComputeRDOut(BitVector* result);
117 virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
118 142
119 #ifdef DEBUG 143 #ifdef DEBUG
120 virtual void PrintText(); 144 void PrintAsText(Handle<String> name);
121 #endif 145 #endif
122 146
123 private: 147 private:
124 ZoneList<Node*> predecessors_; 148 BasicBlock* entry_;
125 149 BasicBlock* exit_;
126 DISALLOW_COPY_AND_ASSIGN(ExitNode); 150 ZoneList<BasicBlock*> preorder_;
151 ZoneList<BasicBlock*> postorder_;
127 }; 152 };
128 153
129 154
130 // Block nodes have a single successor and predecessor and a list of 155 // The flow graph builder walks the AST adding reachable AST nodes to the
131 // instructions. 156 // flow graph as instructions. It remembers the entry and exit nodes of the
132 class BlockNode: public Node { 157 // graph, and keeps a pointer to the current block being constructed.
158 class FlowGraphBuilder: public AstVisitor {
133 public: 159 public:
134 BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {} 160 FlowGraphBuilder() {}
135 161
136 static BlockNode* cast(Node* node) { 162 FlowGraph* Build(FunctionLiteral* lit);
137 ASSERT(node->IsBlockNode());
138 return reinterpret_cast<BlockNode*>(node);
139 }
140
141 virtual bool IsBlockNode() { return true; }
142
143 bool is_empty() { return instructions_.is_empty(); }
144
145 ZoneList<AstNode*>* instructions() { return &instructions_; }
146
147 virtual void AddPredecessor(Node* predecessor) {
148 ASSERT(predecessor_ == NULL && predecessor != NULL);
149 predecessor_ = predecessor;
150 }
151
152 virtual void AddSuccessor(Node* successor) {
153 ASSERT(successor_ == NULL && successor != NULL);
154 successor_ = successor;
155 }
156
157 void AddInstruction(AstNode* instruction) {
158 instructions_.Add(instruction);
159 }
160
161 virtual void Traverse(bool mark,
162 ZoneList<Node*>* preorder,
163 ZoneList<Node*>* postorder);
164
165 virtual void InitializeReachingDefinitions(int definition_count,
166 List<BitVector*>* variables,
167 WorkList<Node>* worklist,
168 bool mark);
169 virtual void ComputeRDOut(BitVector* result);
170 virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
171 virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
172
173 virtual void MarkCriticalInstructions(
174 List<AstNode*>* stack,
175 ZoneList<Expression*>* body_definitions,
176 int variable_count);
177
178 #ifdef DEBUG
179 virtual void PrintText();
180 #endif
181 163
182 private: 164 private:
183 Node* predecessor_;
184 Node* successor_;
185 ZoneList<AstNode*> instructions_;
186
187 DISALLOW_COPY_AND_ASSIGN(BlockNode);
188 };
189
190
191 // Branch nodes have a single predecessor and a pair of successors.
192 class BranchNode: public Node {
193 public:
194 BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
195
196 virtual bool IsBranchNode() { return true; }
197
198 virtual void AddPredecessor(Node* predecessor) {
199 ASSERT(predecessor_ == NULL && predecessor != NULL);
200 predecessor_ = predecessor;
201 }
202
203 virtual void AddSuccessor(Node* successor) {
204 ASSERT(successor1_ == NULL && successor != NULL);
205 if (successor0_ == NULL) {
206 successor0_ = successor;
207 } else {
208 successor1_ = successor;
209 }
210 }
211
212 virtual void Traverse(bool mark,
213 ZoneList<Node*>* preorder,
214 ZoneList<Node*>* postorder);
215
216 virtual void ComputeRDOut(BitVector* result);
217 virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
218
219 #ifdef DEBUG
220 virtual void PrintText();
221 #endif
222
223 private:
224 Node* predecessor_;
225 Node* successor0_;
226 Node* successor1_;
227
228 DISALLOW_COPY_AND_ASSIGN(BranchNode);
229 };
230
231
232 // Join nodes have arbitrarily many predecessors and a single successor.
233 class JoinNode: public Node {
234 public:
235 JoinNode() : predecessors_(2), successor_(NULL) {}
236
237 static JoinNode* cast(Node* node) {
238 ASSERT(node->IsJoinNode());
239 return reinterpret_cast<JoinNode*>(node);
240 }
241
242 virtual bool IsJoinNode() { return true; }
243
244 virtual void AddPredecessor(Node* predecessor) {
245 ASSERT(predecessor != NULL);
246 predecessors_.Add(predecessor);
247 }
248
249 virtual void AddSuccessor(Node* successor) {
250 ASSERT(successor_ == NULL && successor != NULL);
251 successor_ = successor;
252 }
253
254 virtual void Traverse(bool mark,
255 ZoneList<Node*>* preorder,
256 ZoneList<Node*>* postorder);
257
258 virtual void ComputeRDOut(BitVector* result);
259 virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
260
261 #ifdef DEBUG
262 virtual void PrintText();
263 #endif
264
265 private:
266 ZoneList<Node*> predecessors_;
267 Node* successor_;
268
269 DISALLOW_COPY_AND_ASSIGN(JoinNode);
270 };
271
272
273 // Flow graphs have a single entry and single exit. The empty flowgraph is
274 // represented by both entry and exit being NULL.
275 class FlowGraph BASE_EMBEDDED {
276 public:
277 static FlowGraph Empty() {
278 FlowGraph graph;
279 graph.entry_ = new BlockNode();
280 graph.exit_ = graph.entry_;
281 return graph;
282 }
283
284 bool is_empty() const {
285 return entry_ == exit_ && BlockNode::cast(entry_)->is_empty();
286 }
287 Node* entry() const { return entry_; }
288 Node* exit() const { return exit_; }
289
290 // Add a single instruction to the end of this flowgraph.
291 void AppendInstruction(AstNode* instruction);
292
293 // Add a single node to the end of this flow graph.
294 void AppendNode(Node* node);
295
296 // Add a flow graph fragment to the end of this one.
297 void AppendGraph(FlowGraph* graph);
298
299 // Concatenate an if-then-else flow-graph to this one. Control is split
300 // and merged, so the graph remains single-entry, single-exit.
301 void Split(BranchNode* branch,
302 FlowGraph* left,
303 FlowGraph* right,
304 JoinNode* merge);
305
306 // Concatenate a forward loop (e.g., while or for loop) flow-graph to this
307 // one. Control is split by the condition and merged back from the back
308 // edge at end of the body to the beginning of the condition. The single
309 // (free) exit of the result graph is the right (false) arm of the branch
310 // node.
311 void Loop(JoinNode* merge,
312 FlowGraph* condition,
313 BranchNode* branch,
314 FlowGraph* body);
315
316 #ifdef DEBUG
317 void PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder);
318 #endif
319
320 private:
321 FlowGraph() : entry_(NULL), exit_(NULL) {}
322
323 Node* entry_;
324 Node* exit_;
325 };
326
327
328 // Construct a flow graph from a function literal. Build pre- and postorder
329 // traversal orders as a byproduct.
330 class FlowGraphBuilder: public AstVisitor {
331 public:
332 explicit FlowGraphBuilder(int variable_count)
333 : graph_(FlowGraph::Empty()),
334 global_exit_(NULL),
335 preorder_(4),
336 postorder_(4),
337 variable_count_(variable_count),
338 body_definitions_(4) {
339 }
340
341 void Build(FunctionLiteral* lit);
342
343 FlowGraph* graph() { return &graph_; }
344 ZoneList<Node*>* preorder() { return &preorder_; }
345 ZoneList<Node*>* postorder() { return &postorder_; }
346 ZoneList<Expression*>* body_definitions() { return &body_definitions_; }
347
348 private:
349 ExitNode* global_exit() { return global_exit_; }
350
351 // Helpers to allow tranforming the ast during flow graph construction.
352 void VisitStatements(ZoneList<Statement*>* stmts);
353 Statement* ProcessStatement(Statement* stmt);
354
355 // AST node visit functions. 165 // AST node visit functions.
356 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 166 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
357 AST_NODE_LIST(DECLARE_VISIT) 167 AST_NODE_LIST(DECLARE_VISIT)
358 #undef DECLARE_VISIT 168 #undef DECLARE_VISIT
359 169
360 FlowGraph graph_; 170 BasicBlock* entry_;
361 ExitNode* global_exit_; 171 BasicBlock* exit_;
362 ZoneList<Node*> preorder_; 172 BasicBlock* current_;
363 ZoneList<Node*> postorder_;
364
365 // The flow graph builder collects a list of explicit definitions
366 // (assignments and count operations) to stack-allocated variables to use
367 // for reaching definitions analysis. It does not count the implicit
368 // definition at function entry. AST node numbers in the AST are used to
369 // refer into this list.
370 int variable_count_;
371 ZoneList<Expression*> body_definitions_;
372 173
373 DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder); 174 DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
374 }; 175 };
375 176
376 177
377 } } // namespace v8::internal 178 } } // namespace v8::internal
378 179
379 #endif // V8_FLOW_GRAPH_H_ 180 #endif // V8_FLOW_GRAPH_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698