OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_SCHEDULE_H_ | 5 #ifndef V8_COMPILER_SCHEDULE_H_ |
6 #define V8_COMPILER_SCHEDULE_H_ | 6 #define V8_COMPILER_SCHEDULE_H_ |
7 | 7 |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "src/v8.h" | 10 #include "src/v8.h" |
11 | 11 |
12 #include "src/compiler/generic-algorithm.h" | |
13 #include "src/compiler/generic-graph.h" | |
14 #include "src/compiler/generic-node.h" | |
15 #include "src/compiler/generic-node-inl.h" | |
16 #include "src/compiler/node.h" | 12 #include "src/compiler/node.h" |
17 #include "src/compiler/opcodes.h" | 13 #include "src/compiler/opcodes.h" |
18 #include "src/zone.h" | 14 #include "src/zone.h" |
19 | 15 |
20 namespace v8 { | 16 namespace v8 { |
21 namespace internal { | 17 namespace internal { |
22 namespace compiler { | 18 namespace compiler { |
23 | 19 |
24 class BasicBlock; | 20 class BasicBlock; |
25 class BasicBlockInstrumentor; | 21 class BasicBlockInstrumentor; |
26 class Graph; | 22 class Graph; |
27 class ConstructScheduleData; | 23 class ConstructScheduleData; |
28 class CodeGenerator; // Because of a namespace bug in clang. | 24 class CodeGenerator; // Because of a namespace bug in clang. |
29 | 25 |
30 class BasicBlockData { | 26 // A basic block contains an ordered list of nodes and ends with a control |
| 27 // node. Note that if a basic block has phis, then all phis must appear as the |
| 28 // first nodes in the block. |
| 29 class BasicBlock FINAL : public ZoneObject { |
31 public: | 30 public: |
32 // Possible control nodes that can end a block. | 31 // Possible control nodes that can end a block. |
33 enum Control { | 32 enum Control { |
34 kNone, // Control not initialized yet. | 33 kNone, // Control not initialized yet. |
35 kGoto, // Goto a single successor block. | 34 kGoto, // Goto a single successor block. |
36 kBranch, // Branch if true to first successor, otherwise second. | 35 kBranch, // Branch if true to first successor, otherwise second. |
37 kReturn, // Return a value from this method. | 36 kReturn, // Return a value from this method. |
38 kThrow // Throw an exception. | 37 kThrow // Throw an exception. |
39 }; | 38 }; |
40 | 39 |
41 int32_t rpo_number_; // special RPO number of the block. | 40 class Id { |
42 BasicBlock* dominator_; // Immediate dominator of the block. | 41 public: |
43 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, | 42 int ToInt() const { return static_cast<int>(index_); } |
44 // NULL if none. For loop headers, this points to | 43 size_t ToSize() const { return index_; } |
45 // enclosing loop header. | 44 static Id FromSize(size_t index) { return Id(index); } |
46 int32_t loop_depth_; // loop nesting, 0 is top-level | 45 static Id FromInt(int index) { return Id(static_cast<size_t>(index)); } |
47 int32_t loop_end_; // end of the loop, if this block is a loop header. | |
48 int32_t code_start_; // start index of arch-specific code. | |
49 int32_t code_end_; // end index of arch-specific code. | |
50 bool deferred_; // {true} if this block is considered the slow | |
51 // path. | |
52 Control control_; // Control at the end of the block. | |
53 Node* control_input_; // Input value for control. | |
54 NodeVector nodes_; // nodes of this block in forward order. | |
55 | 46 |
56 explicit BasicBlockData(Zone* zone) | 47 private: |
57 : rpo_number_(-1), | 48 explicit Id(size_t index) : index_(index) {} |
58 dominator_(NULL), | 49 size_t index_; |
59 loop_header_(NULL), | 50 }; |
60 loop_depth_(0), | |
61 loop_end_(-1), | |
62 code_start_(-1), | |
63 code_end_(-1), | |
64 deferred_(false), | |
65 control_(kNone), | |
66 control_input_(NULL), | |
67 nodes_(zone) {} | |
68 | 51 |
69 inline bool IsLoopHeader() const { return loop_end_ >= 0; } | 52 BasicBlock(Zone* zone, Id id); |
70 inline bool LoopContains(BasicBlockData* block) const { | 53 |
71 // RPO numbers must be initialized. | 54 Id id() const { return id_; } |
72 DCHECK(rpo_number_ >= 0); | 55 |
73 DCHECK(block->rpo_number_ >= 0); | 56 // Instruction indexes (used by the register allocator). |
74 if (loop_end_ < 0) return false; // This is not a loop. | |
75 return block->rpo_number_ >= rpo_number_ && block->rpo_number_ < loop_end_; | |
76 } | |
77 int first_instruction_index() { | 57 int first_instruction_index() { |
78 DCHECK(code_start_ >= 0); | 58 DCHECK(code_start_ >= 0); |
79 DCHECK(code_end_ > 0); | 59 DCHECK(code_end_ > 0); |
80 DCHECK(code_end_ >= code_start_); | 60 DCHECK(code_end_ >= code_start_); |
81 return code_start_; | 61 return code_start_; |
82 } | 62 } |
83 int last_instruction_index() { | 63 int last_instruction_index() { |
84 DCHECK(code_start_ >= 0); | 64 DCHECK(code_start_ >= 0); |
85 DCHECK(code_end_ > 0); | 65 DCHECK(code_end_ > 0); |
86 DCHECK(code_end_ >= code_start_); | 66 DCHECK(code_end_ >= code_start_); |
87 return code_end_ - 1; | 67 return code_end_ - 1; |
88 } | 68 } |
89 }; | |
90 | 69 |
91 OStream& operator<<(OStream& os, const BasicBlockData::Control& c); | 70 // Predecessors and successors. |
| 71 typedef ZoneVector<BasicBlock*> Predecessors; |
| 72 Predecessors::iterator predecessors_begin() { return predecessors_.begin(); } |
| 73 Predecessors::iterator predecessors_end() { return predecessors_.end(); } |
| 74 size_t PredecessorCount() const { return predecessors_.size(); } |
| 75 BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; } |
| 76 size_t PredecessorIndexOf(BasicBlock* predecessor); |
| 77 void AddPredecessor(BasicBlock* predecessor); |
92 | 78 |
93 // A basic block contains an ordered list of nodes and ends with a control | 79 typedef ZoneVector<BasicBlock*> Successors; |
94 // node. Note that if a basic block has phis, then all phis must appear as the | 80 Successors::iterator successors_begin() { return successors_.begin(); } |
95 // first nodes in the block. | 81 Successors::iterator successors_end() { return successors_.end(); } |
96 class BasicBlock FINAL : public GenericNode<BasicBlockData, BasicBlock> { | 82 size_t SuccessorCount() const { return successors_.size(); } |
97 public: | 83 BasicBlock* SuccessorAt(size_t index) { return successors_[index]; } |
98 BasicBlock(GenericGraphBase* graph, int input_count) | 84 void AddSuccessor(BasicBlock* successor); |
99 : GenericNode<BasicBlockData, BasicBlock>(graph, input_count) {} | |
100 | 85 |
101 typedef Uses Successors; | 86 // Nodes in the basic block. |
102 typedef Inputs Predecessors; | 87 Node* NodeAt(size_t index) { return nodes_[index]; } |
103 | 88 size_t NodeCount() const { return nodes_.size(); } |
104 Successors successors() { return static_cast<Successors>(uses()); } | |
105 Predecessors predecessors() { return static_cast<Predecessors>(inputs()); } | |
106 | |
107 int PredecessorCount() { return InputCount(); } | |
108 BasicBlock* PredecessorAt(int index) { return InputAt(index); } | |
109 | |
110 int SuccessorCount() { return UseCount(); } | |
111 BasicBlock* SuccessorAt(int index) { return UseAt(index); } | |
112 | |
113 int PredecessorIndexOf(BasicBlock* predecessor) { | |
114 BasicBlock::Predecessors predecessors = this->predecessors(); | |
115 for (BasicBlock::Predecessors::iterator i = predecessors.begin(); | |
116 i != predecessors.end(); ++i) { | |
117 if (*i == predecessor) return i.index(); | |
118 } | |
119 return -1; | |
120 } | |
121 | |
122 inline BasicBlock* loop_header() { | |
123 return static_cast<BasicBlock*>(loop_header_); | |
124 } | |
125 inline BasicBlock* ContainingLoop() { | |
126 if (IsLoopHeader()) return this; | |
127 return static_cast<BasicBlock*>(loop_header_); | |
128 } | |
129 | 89 |
130 typedef NodeVector::iterator iterator; | 90 typedef NodeVector::iterator iterator; |
131 iterator begin() { return nodes_.begin(); } | 91 iterator begin() { return nodes_.begin(); } |
132 iterator end() { return nodes_.end(); } | 92 iterator end() { return nodes_.end(); } |
133 | 93 |
134 typedef NodeVector::const_iterator const_iterator; | 94 typedef NodeVector::const_iterator const_iterator; |
135 const_iterator begin() const { return nodes_.begin(); } | 95 const_iterator begin() const { return nodes_.begin(); } |
136 const_iterator end() const { return nodes_.end(); } | 96 const_iterator end() const { return nodes_.end(); } |
137 | 97 |
138 typedef NodeVector::reverse_iterator reverse_iterator; | 98 typedef NodeVector::reverse_iterator reverse_iterator; |
139 reverse_iterator rbegin() { return nodes_.rbegin(); } | 99 reverse_iterator rbegin() { return nodes_.rbegin(); } |
140 reverse_iterator rend() { return nodes_.rend(); } | 100 reverse_iterator rend() { return nodes_.rend(); } |
141 | 101 |
| 102 void AddNode(Node* node); |
| 103 template <class InputIterator> |
| 104 void InsertNodes(iterator insertion_point, InputIterator insertion_start, |
| 105 InputIterator insertion_end) { |
| 106 nodes_.insert(insertion_point, insertion_start, insertion_end); |
| 107 } |
| 108 |
| 109 // Accessors. |
| 110 Control control() const { return control_; } |
| 111 void set_control(Control control); |
| 112 |
| 113 Node* control_input() const { return control_input_; } |
| 114 void set_control_input(Node* control_input); |
| 115 |
| 116 BasicBlock* dominator() const { return dominator_; } |
| 117 void set_dominator(BasicBlock* dominator); |
| 118 |
| 119 BasicBlock* loop_header() const { return loop_header_; } |
| 120 void set_loop_header(BasicBlock* loop_header); |
| 121 |
| 122 int32_t loop_depth() const { return loop_depth_; } |
| 123 void set_loop_depth(int32_t loop_depth); |
| 124 |
| 125 int32_t loop_end() const { return loop_end_; } |
| 126 void set_loop_end(int32_t loop_end); |
| 127 |
| 128 int32_t rpo_number() const { return rpo_number_; } |
| 129 void set_rpo_number(int32_t rpo_number); |
| 130 |
| 131 int32_t code_start() const { return code_start_; } |
| 132 void set_code_start(int32_t start); |
| 133 |
| 134 int32_t code_end() const { return code_end_; } |
| 135 void set_code_end(int32_t end); |
| 136 |
| 137 bool deferred() const { return deferred_; } |
| 138 |
| 139 // Loop membership helpers. |
| 140 inline bool IsLoopHeader() const { return loop_end_ >= 0; } |
| 141 bool LoopContains(BasicBlock* block) const; |
| 142 BasicBlock* ContainingLoop(); |
| 143 |
142 private: | 144 private: |
| 145 int32_t rpo_number_; // special RPO number of the block. |
| 146 BasicBlock* dominator_; // Immediate dominator of the block. |
| 147 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, |
| 148 // NULL if none. For loop headers, this points to |
| 149 // enclosing loop header. |
| 150 int32_t loop_depth_; // loop nesting, 0 is top-level |
| 151 int32_t loop_end_; // end of the loop, if this block is a loop header. |
| 152 int32_t code_start_; // start index of arch-specific code. |
| 153 int32_t code_end_; // end index of arch-specific code. |
| 154 bool deferred_; // {true} if this block is considered the slow |
| 155 // path. |
| 156 Control control_; // Control at the end of the block. |
| 157 Node* control_input_; // Input value for control. |
| 158 NodeVector nodes_; // nodes of this block in forward order. |
| 159 |
| 160 Successors successors_; |
| 161 Predecessors predecessors_; |
| 162 Id id_; |
| 163 |
143 DISALLOW_COPY_AND_ASSIGN(BasicBlock); | 164 DISALLOW_COPY_AND_ASSIGN(BasicBlock); |
144 }; | 165 }; |
145 | 166 |
146 typedef GenericGraphVisit::NullNodeVisitor<BasicBlockData, BasicBlock> | 167 OStream& operator<<(OStream& os, const BasicBlock::Control& c); |
147 NullBasicBlockVisitor; | 168 OStream& operator<<(OStream& os, const BasicBlock::Id& id); |
148 | 169 |
149 typedef ZoneVector<BasicBlock*> BasicBlockVector; | 170 typedef ZoneVector<BasicBlock*> BasicBlockVector; |
150 typedef BasicBlockVector::iterator BasicBlockVectorIter; | 171 typedef BasicBlockVector::iterator BasicBlockVectorIter; |
151 typedef BasicBlockVector::reverse_iterator BasicBlockVectorRIter; | 172 typedef BasicBlockVector::reverse_iterator BasicBlockVectorRIter; |
152 | 173 |
153 // A schedule represents the result of assigning nodes to basic blocks | 174 // A schedule represents the result of assigning nodes to basic blocks |
154 // and ordering them within basic blocks. Prior to computing a schedule, | 175 // and ordering them within basic blocks. Prior to computing a schedule, |
155 // a graph has no notion of control flow ordering other than that induced | 176 // a graph has no notion of control flow ordering other than that induced |
156 // by the graph's dependencies. A schedule is required to generate code. | 177 // by the graph's dependencies. A schedule is required to generate code. |
157 class Schedule : public GenericGraph<BasicBlock> { | 178 class Schedule FINAL : public ZoneObject { |
158 public: | 179 public: |
159 explicit Schedule(Zone* zone, size_t node_count_hint = 0) | 180 explicit Schedule(Zone* zone, size_t node_count_hint = 0); |
160 : GenericGraph<BasicBlock>(zone), | |
161 zone_(zone), | |
162 all_blocks_(zone), | |
163 nodeid_to_block_(zone), | |
164 rpo_order_(zone) { | |
165 SetStart(NewBasicBlock()); // entry. | |
166 SetEnd(NewBasicBlock()); // exit. | |
167 nodeid_to_block_.reserve(node_count_hint); | |
168 } | |
169 | 181 |
170 // Return the block which contains {node}, if any. | 182 // Return the block which contains {node}, if any. |
171 BasicBlock* block(Node* node) const { | 183 BasicBlock* block(Node* node) const; |
172 if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) { | |
173 return nodeid_to_block_[node->id()]; | |
174 } | |
175 return NULL; | |
176 } | |
177 | 184 |
178 bool IsScheduled(Node* node) { | 185 bool IsScheduled(Node* node); |
179 int length = static_cast<int>(nodeid_to_block_.size()); | 186 BasicBlock* GetBlockById(BasicBlock::Id block_id); |
180 if (node->id() >= length) return false; | |
181 return nodeid_to_block_[node->id()] != NULL; | |
182 } | |
183 | 187 |
184 BasicBlock* GetBlockById(int block_id) { return all_blocks_[block_id]; } | 188 size_t BasicBlockCount() const { return all_blocks_.size(); } |
185 | 189 size_t RpoBlockCount() const { return rpo_order_.size(); } |
186 int BasicBlockCount() const { return NodeCount(); } | |
187 int RpoBlockCount() const { return static_cast<int>(rpo_order_.size()); } | |
188 | |
189 typedef ContainerPointerWrapper<BasicBlockVector> BasicBlocks; | |
190 | |
191 // Return a list of all the blocks in the schedule, in arbitrary order. | |
192 BasicBlocks all_blocks() { return BasicBlocks(&all_blocks_); } | |
193 | 190 |
194 // Check if nodes {a} and {b} are in the same block. | 191 // Check if nodes {a} and {b} are in the same block. |
195 inline bool SameBasicBlock(Node* a, Node* b) const { | 192 bool SameBasicBlock(Node* a, Node* b) const; |
196 BasicBlock* block = this->block(a); | |
197 return block != NULL && block == this->block(b); | |
198 } | |
199 | 193 |
200 // BasicBlock building: create a new block. | 194 // BasicBlock building: create a new block. |
201 inline BasicBlock* NewBasicBlock() { | 195 BasicBlock* NewBasicBlock(); |
202 BasicBlock* block = | |
203 BasicBlock::New(this, 0, static_cast<BasicBlock**>(NULL)); | |
204 all_blocks_.push_back(block); | |
205 return block; | |
206 } | |
207 | 196 |
208 // BasicBlock building: records that a node will later be added to a block but | 197 // BasicBlock building: records that a node will later be added to a block but |
209 // doesn't actually add the node to the block. | 198 // doesn't actually add the node to the block. |
210 inline void PlanNode(BasicBlock* block, Node* node) { | 199 void PlanNode(BasicBlock* block, Node* node); |
211 if (FLAG_trace_turbo_scheduler) { | |
212 PrintF("Planning #%d:%s for future add to B%d\n", node->id(), | |
213 node->op()->mnemonic(), block->id()); | |
214 } | |
215 DCHECK(this->block(node) == NULL); | |
216 SetBlockForNode(block, node); | |
217 } | |
218 | 200 |
219 // BasicBlock building: add a node to the end of the block. | 201 // BasicBlock building: add a node to the end of the block. |
220 inline void AddNode(BasicBlock* block, Node* node) { | 202 void AddNode(BasicBlock* block, Node* node); |
221 if (FLAG_trace_turbo_scheduler) { | |
222 PrintF("Adding #%d:%s to B%d\n", node->id(), node->op()->mnemonic(), | |
223 block->id()); | |
224 } | |
225 DCHECK(this->block(node) == NULL || this->block(node) == block); | |
226 block->nodes_.push_back(node); | |
227 SetBlockForNode(block, node); | |
228 } | |
229 | 203 |
230 // BasicBlock building: add a goto to the end of {block}. | 204 // BasicBlock building: add a goto to the end of {block}. |
231 void AddGoto(BasicBlock* block, BasicBlock* succ) { | 205 void AddGoto(BasicBlock* block, BasicBlock* succ); |
232 DCHECK(block->control_ == BasicBlock::kNone); | |
233 block->control_ = BasicBlock::kGoto; | |
234 AddSuccessor(block, succ); | |
235 } | |
236 | 206 |
237 // BasicBlock building: add a branch at the end of {block}. | 207 // BasicBlock building: add a branch at the end of {block}. |
238 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, | 208 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, |
239 BasicBlock* fblock) { | 209 BasicBlock* fblock); |
240 DCHECK(block->control_ == BasicBlock::kNone); | |
241 DCHECK(branch->opcode() == IrOpcode::kBranch); | |
242 block->control_ = BasicBlock::kBranch; | |
243 AddSuccessor(block, tblock); | |
244 AddSuccessor(block, fblock); | |
245 SetControlInput(block, branch); | |
246 if (branch->opcode() == IrOpcode::kBranch) { | |
247 // TODO(titzer): require a Branch node here. (sloppy tests). | |
248 SetBlockForNode(block, branch); | |
249 } | |
250 } | |
251 | 210 |
252 // BasicBlock building: add a return at the end of {block}. | 211 // BasicBlock building: add a return at the end of {block}. |
253 void AddReturn(BasicBlock* block, Node* input) { | 212 void AddReturn(BasicBlock* block, Node* input); |
254 DCHECK(block->control_ == BasicBlock::kNone); | |
255 block->control_ = BasicBlock::kReturn; | |
256 SetControlInput(block, input); | |
257 if (block != end()) AddSuccessor(block, end()); | |
258 if (input->opcode() == IrOpcode::kReturn) { | |
259 // TODO(titzer): require a Return node here. (sloppy tests). | |
260 SetBlockForNode(block, input); | |
261 } | |
262 } | |
263 | 213 |
264 // BasicBlock building: add a throw at the end of {block}. | 214 // BasicBlock building: add a throw at the end of {block}. |
265 void AddThrow(BasicBlock* block, Node* input) { | 215 void AddThrow(BasicBlock* block, Node* input); |
266 DCHECK(block->control_ == BasicBlock::kNone); | |
267 block->control_ = BasicBlock::kThrow; | |
268 SetControlInput(block, input); | |
269 if (block != end()) AddSuccessor(block, end()); | |
270 } | |
271 | 216 |
272 friend class Scheduler; | 217 void AddSuccessor(BasicBlock* block, BasicBlock* succ); |
273 friend class CodeGenerator; | |
274 | |
275 void AddSuccessor(BasicBlock* block, BasicBlock* succ) { | |
276 succ->AppendInput(zone_, block); | |
277 } | |
278 | 218 |
279 BasicBlockVector* rpo_order() { return &rpo_order_; } | 219 BasicBlockVector* rpo_order() { return &rpo_order_; } |
280 | 220 |
| 221 BasicBlock* start() { return start_; } |
| 222 BasicBlock* end() { return end_; } |
| 223 |
| 224 Zone* zone() { return zone_; } |
| 225 |
281 private: | 226 private: |
| 227 friend class Scheduler; |
| 228 friend class CodeGenerator; |
282 friend class ScheduleVisualizer; | 229 friend class ScheduleVisualizer; |
283 friend class BasicBlockInstrumentor; | 230 friend class BasicBlockInstrumentor; |
284 | 231 |
285 void SetControlInput(BasicBlock* block, Node* node) { | 232 void SetControlInput(BasicBlock* block, Node* node); |
286 block->control_input_ = node; | 233 void SetBlockForNode(BasicBlock* block, Node* node); |
287 SetBlockForNode(block, node); | |
288 } | |
289 | |
290 void SetBlockForNode(BasicBlock* block, Node* node) { | |
291 int length = static_cast<int>(nodeid_to_block_.size()); | |
292 if (node->id() >= length) { | |
293 nodeid_to_block_.resize(node->id() + 1); | |
294 } | |
295 nodeid_to_block_[node->id()] = block; | |
296 } | |
297 | 234 |
298 Zone* zone_; | 235 Zone* zone_; |
299 BasicBlockVector all_blocks_; // All basic blocks in the schedule. | 236 BasicBlockVector all_blocks_; // All basic blocks in the schedule. |
300 BasicBlockVector nodeid_to_block_; // Map from node to containing block. | 237 BasicBlockVector nodeid_to_block_; // Map from node to containing block. |
301 BasicBlockVector rpo_order_; // Reverse-post-order block list. | 238 BasicBlockVector rpo_order_; // Reverse-post-order block list. |
| 239 BasicBlock* start_; |
| 240 BasicBlock* end_; |
302 }; | 241 }; |
303 | 242 |
304 OStream& operator<<(OStream& os, const Schedule& s); | 243 OStream& operator<<(OStream& os, const Schedule& s); |
305 } | 244 } |
306 } | 245 } |
307 } // namespace v8::internal::compiler | 246 } // namespace v8::internal::compiler |
308 | 247 |
309 #endif // V8_COMPILER_SCHEDULE_H_ | 248 #endif // V8_COMPILER_SCHEDULE_H_ |
OLD | NEW |