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" |
(...skipping 22 matching lines...) Expand all Loading... |
33 kNone, // Control not initialized yet. | 33 kNone, // Control not initialized yet. |
34 kGoto, // Goto a single successor block. | 34 kGoto, // Goto a single successor block. |
35 kBranch, // Branch if true to first successor, otherwise second. | 35 kBranch, // Branch if true to first successor, otherwise second. |
36 kReturn, // Return a value from this method. | 36 kReturn, // Return a value from this method. |
37 kThrow, // Throw an exception. | 37 kThrow, // Throw an exception. |
38 kCall, // Call to a possibly deoptimizing or throwing function. | 38 kCall, // Call to a possibly deoptimizing or throwing function. |
39 kDeoptimize // Deoptimize. | 39 kDeoptimize // Deoptimize. |
40 }; | 40 }; |
41 | 41 |
42 int32_t rpo_number_; // special RPO number of the block. | 42 int32_t rpo_number_; // special RPO number of the block. |
| 43 BasicBlock* dominator_; // Immediate dominator of the block. |
43 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, | 44 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, |
44 // NULL if none. For loop headers, this points to | 45 // NULL if none. For loop headers, this points to |
45 // enclosing loop header. | 46 // enclosing loop header. |
46 int32_t loop_depth_; // loop nesting, 0 is top-level | 47 int32_t loop_depth_; // loop nesting, 0 is top-level |
47 int32_t loop_end_; // end of the loop, if this block is a loop header. | 48 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_start_; // start index of arch-specific code. |
49 int32_t code_end_; // end index of arch-specific code. | 50 int32_t code_end_; // end index of arch-specific code. |
50 bool deferred_; // {true} if this block is considered the slow | 51 bool deferred_; // {true} if this block is considered the slow |
51 // path. | 52 // path. |
52 Control control_; // Control at the end of the block. | 53 Control control_; // Control at the end of the block. |
53 Node* control_input_; // Input value for control. | 54 Node* control_input_; // Input value for control. |
54 NodeVector nodes_; // nodes of this block in forward order. | 55 NodeVector nodes_; // nodes of this block in forward order. |
55 | 56 |
56 explicit BasicBlockData(Zone* zone) | 57 explicit BasicBlockData(Zone* zone) |
57 : rpo_number_(-1), | 58 : rpo_number_(-1), |
| 59 dominator_(NULL), |
58 loop_header_(NULL), | 60 loop_header_(NULL), |
59 loop_depth_(0), | 61 loop_depth_(0), |
60 loop_end_(-1), | 62 loop_end_(-1), |
61 code_start_(-1), | 63 code_start_(-1), |
62 code_end_(-1), | 64 code_end_(-1), |
63 deferred_(false), | 65 deferred_(false), |
64 control_(kNone), | 66 control_(kNone), |
65 control_input_(NULL), | 67 control_input_(NULL), |
66 nodes_(NodeVector::allocator_type(zone)) {} | 68 nodes_(NodeVector::allocator_type(zone)) {} |
67 | 69 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 // and ordering them within basic blocks. Prior to computing a schedule, | 156 // 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 | 157 // 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. | 158 // by the graph's dependencies. A schedule is required to generate code. |
157 class Schedule : public GenericGraph<BasicBlock> { | 159 class Schedule : public GenericGraph<BasicBlock> { |
158 public: | 160 public: |
159 explicit Schedule(Zone* zone) | 161 explicit Schedule(Zone* zone) |
160 : GenericGraph<BasicBlock>(zone), | 162 : GenericGraph<BasicBlock>(zone), |
161 zone_(zone), | 163 zone_(zone), |
162 all_blocks_(BasicBlockVector::allocator_type(zone)), | 164 all_blocks_(BasicBlockVector::allocator_type(zone)), |
163 nodeid_to_block_(BasicBlockVector::allocator_type(zone)), | 165 nodeid_to_block_(BasicBlockVector::allocator_type(zone)), |
164 rpo_order_(BasicBlockVector::allocator_type(zone)), | 166 rpo_order_(BasicBlockVector::allocator_type(zone)) { |
165 immediate_dominator_(BasicBlockVector::allocator_type(zone)) { | |
166 SetStart(NewBasicBlock()); // entry. | 167 SetStart(NewBasicBlock()); // entry. |
167 SetEnd(NewBasicBlock()); // exit. | 168 SetEnd(NewBasicBlock()); // exit. |
168 } | 169 } |
169 | 170 |
170 // Return the block which contains {node}, if any. | 171 // Return the block which contains {node}, if any. |
171 BasicBlock* block(Node* node) const { | 172 BasicBlock* block(Node* node) const { |
172 if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) { | 173 if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) { |
173 return nodeid_to_block_[node->id()]; | 174 return nodeid_to_block_[node->id()]; |
174 } | 175 } |
175 return NULL; | 176 return NULL; |
176 } | 177 } |
177 | 178 |
178 BasicBlock* dominator(BasicBlock* block) { | |
179 return immediate_dominator_[block->id()]; | |
180 } | |
181 | |
182 bool IsScheduled(Node* node) { | 179 bool IsScheduled(Node* node) { |
183 int length = static_cast<int>(nodeid_to_block_.size()); | 180 int length = static_cast<int>(nodeid_to_block_.size()); |
184 if (node->id() >= length) return false; | 181 if (node->id() >= length) return false; |
185 return nodeid_to_block_[node->id()] != NULL; | 182 return nodeid_to_block_[node->id()] != NULL; |
186 } | 183 } |
187 | 184 |
188 BasicBlock* GetBlockById(int block_id) { return all_blocks_[block_id]; } | 185 BasicBlock* GetBlockById(int block_id) { return all_blocks_[block_id]; } |
189 | 186 |
190 int BasicBlockCount() const { return NodeCount(); } | 187 int BasicBlockCount() const { return NodeCount(); } |
191 int RpoBlockCount() const { return static_cast<int>(rpo_order_.size()); } | 188 int RpoBlockCount() const { return static_cast<int>(rpo_order_.size()); } |
(...skipping 14 matching lines...) Expand all Loading... |
206 BasicBlock* block = | 203 BasicBlock* block = |
207 BasicBlock::New(this, 0, static_cast<BasicBlock**>(NULL)); | 204 BasicBlock::New(this, 0, static_cast<BasicBlock**>(NULL)); |
208 all_blocks_.push_back(block); | 205 all_blocks_.push_back(block); |
209 return block; | 206 return block; |
210 } | 207 } |
211 | 208 |
212 // BasicBlock building: records that a node will later be added to a block but | 209 // BasicBlock building: records that a node will later be added to a block but |
213 // doesn't actually add the node to the block. | 210 // doesn't actually add the node to the block. |
214 inline void PlanNode(BasicBlock* block, Node* node) { | 211 inline void PlanNode(BasicBlock* block, Node* node) { |
215 if (FLAG_trace_turbo_scheduler) { | 212 if (FLAG_trace_turbo_scheduler) { |
216 PrintF("Planning node %d for future add to block %d\n", node->id(), | 213 PrintF("Planning #%d:%s for future add to B%d\n", node->id(), |
217 block->id()); | 214 node->op()->mnemonic(), block->id()); |
218 } | 215 } |
219 DCHECK(this->block(node) == NULL); | 216 DCHECK(this->block(node) == NULL); |
220 SetBlockForNode(block, node); | 217 SetBlockForNode(block, node); |
221 } | 218 } |
222 | 219 |
223 // BasicBlock building: add a node to the end of the block. | 220 // BasicBlock building: add a node to the end of the block. |
224 inline void AddNode(BasicBlock* block, Node* node) { | 221 inline void AddNode(BasicBlock* block, Node* node) { |
225 if (FLAG_trace_turbo_scheduler) { | 222 if (FLAG_trace_turbo_scheduler) { |
226 PrintF("Adding node %d to block %d\n", node->id(), block->id()); | 223 PrintF("Adding #%d:%s to B%d\n", node->id(), node->op()->mnemonic(), |
| 224 block->id()); |
227 } | 225 } |
228 DCHECK(this->block(node) == NULL || this->block(node) == block); | 226 DCHECK(this->block(node) == NULL || this->block(node) == block); |
229 block->nodes_.push_back(node); | 227 block->nodes_.push_back(node); |
230 SetBlockForNode(block, node); | 228 SetBlockForNode(block, node); |
231 } | 229 } |
232 | 230 |
233 // BasicBlock building: add a goto to the end of {block}. | 231 // BasicBlock building: add a goto to the end of {block}. |
234 void AddGoto(BasicBlock* block, BasicBlock* succ) { | 232 void AddGoto(BasicBlock* block, BasicBlock* succ) { |
235 DCHECK(block->control_ == BasicBlock::kNone); | 233 DCHECK(block->control_ == BasicBlock::kNone); |
236 block->control_ = BasicBlock::kGoto; | 234 block->control_ = BasicBlock::kGoto; |
237 AddSuccessor(block, succ); | 235 AddSuccessor(block, succ); |
238 } | 236 } |
239 | 237 |
240 // BasicBlock building: add a (branching) call at the end of {block}. | 238 // BasicBlock building: add a (branching) call at the end of {block}. |
241 void AddCall(BasicBlock* block, Node* call, BasicBlock* cont_block, | 239 void AddCall(BasicBlock* block, Node* call, BasicBlock* cont_block, |
242 BasicBlock* deopt_block) { | 240 BasicBlock* deopt_block) { |
243 DCHECK(block->control_ == BasicBlock::kNone); | 241 DCHECK(block->control_ == BasicBlock::kNone); |
244 DCHECK(call->opcode() == IrOpcode::kCall); | 242 DCHECK(call->opcode() == IrOpcode::kCall); |
245 block->control_ = BasicBlock::kCall; | 243 block->control_ = BasicBlock::kCall; |
246 // Insert the deopt block first so that the RPO order builder picks | 244 // Insert the deopt block first so that the RPO order builder picks |
247 // it first (and thus it ends up late in the RPO order). | 245 // it first (and thus it ends up late in the RPO order). |
248 AddSuccessor(block, deopt_block); | 246 AddSuccessor(block, deopt_block); |
249 AddSuccessor(block, cont_block); | 247 AddSuccessor(block, cont_block); |
250 SetControlInput(block, call); | 248 SetControlInput(block, call); |
| 249 SetBlockForNode(block, call); |
251 } | 250 } |
252 | 251 |
253 // BasicBlock building: add a branch at the end of {block}. | 252 // BasicBlock building: add a branch at the end of {block}. |
254 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, | 253 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, |
255 BasicBlock* fblock) { | 254 BasicBlock* fblock) { |
256 DCHECK(block->control_ == BasicBlock::kNone); | 255 DCHECK(block->control_ == BasicBlock::kNone); |
257 DCHECK(branch->opcode() == IrOpcode::kBranch); | 256 DCHECK(branch->opcode() == IrOpcode::kBranch); |
258 block->control_ = BasicBlock::kBranch; | 257 block->control_ = BasicBlock::kBranch; |
259 AddSuccessor(block, tblock); | 258 AddSuccessor(block, tblock); |
260 AddSuccessor(block, fblock); | 259 AddSuccessor(block, fblock); |
261 SetControlInput(block, branch); | 260 SetControlInput(block, branch); |
| 261 if (branch->opcode() == IrOpcode::kBranch) { |
| 262 // TODO(titzer): require a Branch node here. (sloppy tests). |
| 263 SetBlockForNode(block, branch); |
| 264 } |
262 } | 265 } |
263 | 266 |
264 // BasicBlock building: add a return at the end of {block}. | 267 // BasicBlock building: add a return at the end of {block}. |
265 void AddReturn(BasicBlock* block, Node* input) { | 268 void AddReturn(BasicBlock* block, Node* input) { |
266 // TODO(titzer): require a Return node here. | |
267 DCHECK(block->control_ == BasicBlock::kNone); | 269 DCHECK(block->control_ == BasicBlock::kNone); |
268 block->control_ = BasicBlock::kReturn; | 270 block->control_ = BasicBlock::kReturn; |
269 SetControlInput(block, input); | 271 SetControlInput(block, input); |
270 if (block != end()) AddSuccessor(block, end()); | 272 if (block != end()) AddSuccessor(block, end()); |
| 273 if (input->opcode() == IrOpcode::kReturn) { |
| 274 // TODO(titzer): require a Return node here. (sloppy tests). |
| 275 SetBlockForNode(block, input); |
| 276 } |
271 } | 277 } |
272 | 278 |
273 // BasicBlock building: add a throw at the end of {block}. | 279 // BasicBlock building: add a throw at the end of {block}. |
274 void AddThrow(BasicBlock* block, Node* input) { | 280 void AddThrow(BasicBlock* block, Node* input) { |
275 DCHECK(block->control_ == BasicBlock::kNone); | 281 DCHECK(block->control_ == BasicBlock::kNone); |
276 block->control_ = BasicBlock::kThrow; | 282 block->control_ = BasicBlock::kThrow; |
277 SetControlInput(block, input); | 283 SetControlInput(block, input); |
278 if (block != end()) AddSuccessor(block, end()); | 284 if (block != end()) AddSuccessor(block, end()); |
279 } | 285 } |
280 | 286 |
(...skipping 28 matching lines...) Expand all Loading... |
309 if (node->id() >= length) { | 315 if (node->id() >= length) { |
310 nodeid_to_block_.resize(node->id() + 1); | 316 nodeid_to_block_.resize(node->id() + 1); |
311 } | 317 } |
312 nodeid_to_block_[node->id()] = block; | 318 nodeid_to_block_[node->id()] = block; |
313 } | 319 } |
314 | 320 |
315 Zone* zone_; | 321 Zone* zone_; |
316 BasicBlockVector all_blocks_; // All basic blocks in the schedule. | 322 BasicBlockVector all_blocks_; // All basic blocks in the schedule. |
317 BasicBlockVector nodeid_to_block_; // Map from node to containing block. | 323 BasicBlockVector nodeid_to_block_; // Map from node to containing block. |
318 BasicBlockVector rpo_order_; // Reverse-post-order block list. | 324 BasicBlockVector rpo_order_; // Reverse-post-order block list. |
319 BasicBlockVector immediate_dominator_; // Maps to a block's immediate | |
320 // dominator, indexed by block | |
321 // id. | |
322 }; | 325 }; |
323 | 326 |
324 OStream& operator<<(OStream& os, const Schedule& s); | 327 OStream& operator<<(OStream& os, const Schedule& s); |
325 } | 328 } |
326 } | 329 } |
327 } // namespace v8::internal::compiler | 330 } // namespace v8::internal::compiler |
328 | 331 |
329 #endif // V8_COMPILER_SCHEDULE_H_ | 332 #endif // V8_COMPILER_SCHEDULE_H_ |
OLD | NEW |