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 #include <deque> | 5 #include <deque> |
6 #include <queue> | 6 #include <queue> |
7 | 7 |
8 #include "src/compiler/scheduler.h" | 8 #include "src/compiler/scheduler.h" |
9 | 9 |
10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 } | 28 } |
29 | 29 |
30 | 30 |
31 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) | 31 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) |
32 : zone_(zone), | 32 : zone_(zone), |
33 graph_(graph), | 33 graph_(graph), |
34 schedule_(schedule), | 34 schedule_(schedule), |
35 scheduled_nodes_(zone), | 35 scheduled_nodes_(zone), |
36 schedule_root_nodes_(zone), | 36 schedule_root_nodes_(zone), |
37 schedule_queue_(zone), | 37 schedule_queue_(zone), |
38 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone), | 38 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone) {} |
39 has_floating_control_(false) {} | |
40 | 39 |
41 | 40 |
42 Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { | 41 Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { |
43 Schedule* schedule; | 42 ZonePool::Scope zone_scope(zone_pool); |
44 bool had_floating_control = false; | 43 Schedule* schedule = new (graph->zone()) |
45 do { | 44 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); |
46 ZonePool::Scope zone_scope(zone_pool); | 45 Scheduler scheduler(zone_scope.zone(), graph, schedule); |
47 schedule = new (graph->zone()) | |
48 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); | |
49 Scheduler scheduler(zone_scope.zone(), graph, schedule); | |
50 | 46 |
51 scheduler.BuildCFG(); | 47 scheduler.BuildCFG(); |
52 scheduler.ComputeSpecialRPONumbering(); | 48 scheduler.ComputeSpecialRPONumbering(); |
53 scheduler.GenerateImmediateDominatorTree(); | 49 scheduler.GenerateImmediateDominatorTree(); |
54 | 50 |
55 scheduler.PrepareUses(); | 51 scheduler.PrepareUses(); |
56 scheduler.ScheduleEarly(); | 52 scheduler.ScheduleEarly(); |
57 scheduler.ScheduleLate(); | 53 scheduler.ScheduleLate(); |
58 | |
59 had_floating_control = scheduler.ConnectFloatingControl(); | |
60 } while (had_floating_control); | |
61 | 54 |
62 return schedule; | 55 return schedule; |
63 } | 56 } |
64 | 57 |
65 | 58 |
66 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { | 59 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { |
67 SchedulerData def = {schedule_->start(), 0, false, false, kUnknown}; | 60 SchedulerData def = {schedule_->start(), 0, false, false, kUnknown}; |
68 return def; | 61 return def; |
69 } | 62 } |
70 | 63 |
(...skipping 14 matching lines...) Expand all Loading... |
85 break; | 78 break; |
86 case IrOpcode::kPhi: | 79 case IrOpcode::kPhi: |
87 case IrOpcode::kEffectPhi: { | 80 case IrOpcode::kEffectPhi: { |
88 // Phis and effect phis are fixed if their control inputs are, whereas | 81 // Phis and effect phis are fixed if their control inputs are, whereas |
89 // otherwise they are coupled to a floating control node. | 82 // otherwise they are coupled to a floating control node. |
90 Placement p = GetPlacement(NodeProperties::GetControlInput(node)); | 83 Placement p = GetPlacement(NodeProperties::GetControlInput(node)); |
91 data->placement_ = (p == kFixed ? kFixed : kCoupled); | 84 data->placement_ = (p == kFixed ? kFixed : kCoupled); |
92 break; | 85 break; |
93 } | 86 } |
94 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: | 87 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: |
95 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) | 88 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) |
96 #undef DEFINE_FLOATING_CONTROL_CASE | 89 #undef DEFINE_FLOATING_CONTROL_CASE |
97 { | 90 { |
98 // Control nodes that were not control-reachable from end may float. | 91 // Control nodes that were not control-reachable from end may float. |
99 data->placement_ = kSchedulable; | 92 data->placement_ = kSchedulable; |
100 if (!data->is_connected_control_) { | 93 if (!data->is_connected_control_) { |
101 data->is_floating_control_ = true; | 94 data->is_floating_control_ = true; |
102 has_floating_control_ = true; | 95 Trace("Floating control found: #%d:%s\n", node->id(), |
103 Trace("Floating control found: #%d:%s\n", node->id(), | 96 node->op()->mnemonic()); |
104 node->op()->mnemonic()); | |
105 } | |
106 break; | |
107 } | 97 } |
| 98 break; |
| 99 } |
108 default: | 100 default: |
109 data->placement_ = kSchedulable; | 101 data->placement_ = kSchedulable; |
110 break; | 102 break; |
111 } | 103 } |
112 } | 104 } |
113 return data->placement_; | 105 return data->placement_; |
114 } | 106 } |
115 | 107 |
116 | 108 |
| 109 void Scheduler::UpdatePlacement(Node* node, Placement placement) { |
| 110 SchedulerData* data = GetData(node); |
| 111 if (data->placement_ != kUnknown) { // Trap on mutation, not initialization. |
| 112 switch (node->opcode()) { |
| 113 case IrOpcode::kParameter: |
| 114 // Parameters are fixed once and for all. |
| 115 UNREACHABLE(); |
| 116 break; |
| 117 case IrOpcode::kPhi: |
| 118 case IrOpcode::kEffectPhi: { |
| 119 // Phis and effect phis are coupled to their respective blocks. |
| 120 DCHECK_EQ(Scheduler::kCoupled, data->placement_); |
| 121 DCHECK_EQ(Scheduler::kFixed, placement); |
| 122 Node* control = NodeProperties::GetControlInput(node); |
| 123 BasicBlock* block = schedule_->block(control); |
| 124 schedule_->AddNode(block, node); |
| 125 // TODO(mstarzinger): Cheap hack to make sure unscheduled use count of |
| 126 // control does not drop below zero. This might cause the control to be |
| 127 // queued for scheduling more than once, which makes this ugly! |
| 128 ++(GetData(control)->unscheduled_count_); |
| 129 break; |
| 130 } |
| 131 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: |
| 132 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) |
| 133 #undef DEFINE_FLOATING_CONTROL_CASE |
| 134 { |
| 135 // Control nodes force coupled uses to be placed. |
| 136 Node::Uses uses = node->uses(); |
| 137 for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) { |
| 138 if (GetPlacement(*i) == Scheduler::kCoupled) { |
| 139 DCHECK_EQ(node, NodeProperties::GetControlInput(*i)); |
| 140 UpdatePlacement(*i, placement); |
| 141 } |
| 142 } |
| 143 break; |
| 144 } |
| 145 default: |
| 146 DCHECK_EQ(Scheduler::kSchedulable, data->placement_); |
| 147 DCHECK_EQ(Scheduler::kScheduled, placement); |
| 148 break; |
| 149 } |
| 150 // Reduce the use count of the node's inputs to potentially make them |
| 151 // schedulable. If all the uses of a node have been scheduled, then the node |
| 152 // itself can be scheduled. |
| 153 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { |
| 154 // TODO(mstarzinger): Another cheap hack for use counts. |
| 155 if (GetData(*i)->placement_ == kFixed) continue; |
| 156 DecrementUnscheduledUseCount(*i, i.edge().from()); |
| 157 } |
| 158 } |
| 159 data->placement_ = placement; |
| 160 } |
| 161 |
| 162 |
117 void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) { | 163 void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) { |
118 if (GetPlacement(node) == kCoupled) { | 164 if (GetPlacement(node) == kCoupled) { |
119 // Use count for coupled nodes is summed up on their control. | 165 // Use count for coupled nodes is summed up on their control. |
120 Node* control = NodeProperties::GetControlInput(node); | 166 Node* control = NodeProperties::GetControlInput(node); |
121 return IncrementUnscheduledUseCount(control, from); | 167 return IncrementUnscheduledUseCount(control, from); |
122 } | 168 } |
123 ++(GetData(node)->unscheduled_count_); | 169 ++(GetData(node)->unscheduled_count_); |
124 if (FLAG_trace_turbo_scheduler) { | 170 if (FLAG_trace_turbo_scheduler) { |
125 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(), | 171 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(), |
126 node->op()->mnemonic(), from->id(), from->op()->mnemonic(), | 172 node->op()->mnemonic(), from->id(), from->op()->mnemonic(), |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 } | 216 } |
171 return b1; | 217 return b1; |
172 } | 218 } |
173 | 219 |
174 | 220 |
175 // ----------------------------------------------------------------------------- | 221 // ----------------------------------------------------------------------------- |
176 // Phase 1: Build control-flow graph. | 222 // Phase 1: Build control-flow graph. |
177 | 223 |
178 | 224 |
179 // Internal class to build a control flow graph (i.e the basic blocks and edges | 225 // Internal class to build a control flow graph (i.e the basic blocks and edges |
180 // between them within a Schedule) from the node graph. | 226 // between them within a Schedule) from the node graph. Visits control edges of |
181 // Visits the control edges of the graph backwards from end in order to find | 227 // the graph backwards from an end node in order to find the connected control |
182 // the connected control subgraph, needed for scheduling. | 228 // subgraph, needed for scheduling. |
183 class CFGBuilder { | 229 class CFGBuilder { |
184 public: | 230 public: |
185 Scheduler* scheduler_; | |
186 Schedule* schedule_; | |
187 ZoneQueue<Node*> queue_; | |
188 NodeVector control_; | |
189 | |
190 CFGBuilder(Zone* zone, Scheduler* scheduler) | 231 CFGBuilder(Zone* zone, Scheduler* scheduler) |
191 : scheduler_(scheduler), | 232 : scheduler_(scheduler), |
192 schedule_(scheduler->schedule_), | 233 schedule_(scheduler->schedule_), |
193 queue_(zone), | 234 queue_(zone), |
194 control_(zone) {} | 235 control_(zone), |
| 236 component_head_(NULL), |
| 237 component_start_(NULL), |
| 238 component_end_(NULL) {} |
195 | 239 |
196 // Run the control flow graph construction algorithm by walking the graph | 240 // Run the control flow graph construction algorithm by walking the graph |
197 // backwards from end through control edges, building and connecting the | 241 // backwards from end through control edges, building and connecting the |
198 // basic blocks for control nodes. | 242 // basic blocks for control nodes. |
199 void Run() { | 243 void Run() { |
200 Graph* graph = scheduler_->graph_; | 244 Graph* graph = scheduler_->graph_; |
201 FixNode(schedule_->start(), graph->start()); | 245 FixNode(schedule_->start(), graph->start()); |
202 Queue(graph->end()); | 246 Queue(graph->end()); |
203 | 247 |
204 while (!queue_.empty()) { // Breadth-first backwards traversal. | 248 while (!queue_.empty()) { // Breadth-first backwards traversal. |
205 Node* node = queue_.front(); | 249 Node* node = queue_.front(); |
206 queue_.pop(); | 250 queue_.pop(); |
207 int max = NodeProperties::PastControlIndex(node); | 251 int max = NodeProperties::PastControlIndex(node); |
208 for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) { | 252 for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) { |
209 Queue(node->InputAt(i)); | 253 Queue(node->InputAt(i)); |
210 } | 254 } |
211 } | 255 } |
212 | 256 |
213 for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) { | 257 for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) { |
214 ConnectBlocks(*i); // Connect block to its predecessor/successors. | 258 ConnectBlocks(*i); // Connect block to its predecessor/successors. |
215 } | 259 } |
216 | 260 |
217 FixNode(schedule_->end(), graph->end()); | 261 FixNode(schedule_->end(), graph->end()); |
218 } | 262 } |
219 | 263 |
| 264 // Run the control flow graph construction for a minimal control-connected |
| 265 // component ending in {node} and merge that component into an existing |
| 266 // control flow graph at the bottom of {block}. |
| 267 void Run(BasicBlock* block, Node* node) { |
| 268 Queue(node); |
| 269 |
| 270 component_start_ = block; |
| 271 component_end_ = schedule_->block(node); |
| 272 while (!queue_.empty()) { // Breadth-first backwards traversal. |
| 273 Node* node = queue_.front(); |
| 274 queue_.pop(); |
| 275 bool is_dom = true; |
| 276 int max = NodeProperties::PastControlIndex(node); |
| 277 for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) { |
| 278 is_dom = is_dom && |
| 279 !scheduler_->GetData(node->InputAt(i))->is_floating_control_; |
| 280 Queue(node->InputAt(i)); |
| 281 } |
| 282 // TODO(mstarzinger): This is a hacky way to find component dominator. |
| 283 if (is_dom) component_head_ = node; |
| 284 } |
| 285 DCHECK_NOT_NULL(component_head_); |
| 286 |
| 287 for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) { |
| 288 scheduler_->GetData(*i)->is_floating_control_ = false; |
| 289 ConnectBlocks(*i); // Connect block to its predecessor/successors. |
| 290 } |
| 291 } |
| 292 |
| 293 private: |
220 void FixNode(BasicBlock* block, Node* node) { | 294 void FixNode(BasicBlock* block, Node* node) { |
221 schedule_->AddNode(block, node); | 295 schedule_->AddNode(block, node); |
222 scheduler_->GetData(node)->is_connected_control_ = true; | 296 scheduler_->GetData(node)->is_connected_control_ = true; |
223 scheduler_->GetData(node)->placement_ = Scheduler::kFixed; | 297 scheduler_->UpdatePlacement(node, Scheduler::kFixed); |
224 } | 298 } |
225 | 299 |
226 void Queue(Node* node) { | 300 void Queue(Node* node) { |
227 // Mark the connected control nodes as they queued. | 301 // Mark the connected control nodes as they queued. |
228 Scheduler::SchedulerData* data = scheduler_->GetData(node); | 302 Scheduler::SchedulerData* data = scheduler_->GetData(node); |
229 if (!data->is_connected_control_) { | 303 if (!data->is_connected_control_) { |
230 BuildBlocks(node); | 304 BuildBlocks(node); |
231 queue_.push(node); | 305 queue_.push(node); |
232 control_.push_back(node); | 306 control_.push_back(node); |
233 data->is_connected_control_ = true; | 307 data->is_connected_control_ = true; |
(...skipping 16 matching lines...) Expand all Loading... |
250 } | 324 } |
251 } | 325 } |
252 | 326 |
253 void ConnectBlocks(Node* node) { | 327 void ConnectBlocks(Node* node) { |
254 switch (node->opcode()) { | 328 switch (node->opcode()) { |
255 case IrOpcode::kLoop: | 329 case IrOpcode::kLoop: |
256 case IrOpcode::kMerge: | 330 case IrOpcode::kMerge: |
257 ConnectMerge(node); | 331 ConnectMerge(node); |
258 break; | 332 break; |
259 case IrOpcode::kBranch: | 333 case IrOpcode::kBranch: |
260 scheduler_->schedule_root_nodes_.push_back(node); | 334 scheduler_->UpdatePlacement(node, Scheduler::kFixed); |
261 ConnectBranch(node); | 335 ConnectBranch(node); |
262 break; | 336 break; |
263 case IrOpcode::kReturn: | 337 case IrOpcode::kReturn: |
264 scheduler_->schedule_root_nodes_.push_back(node); | 338 scheduler_->UpdatePlacement(node, Scheduler::kFixed); |
265 ConnectReturn(node); | 339 ConnectReturn(node); |
266 break; | 340 break; |
267 default: | 341 default: |
268 break; | 342 break; |
269 } | 343 } |
270 } | 344 } |
271 | 345 |
272 void BuildBlockForNode(Node* node) { | 346 void BuildBlockForNode(Node* node) { |
273 if (schedule_->block(node) == NULL) { | 347 if (schedule_->block(node) == NULL) { |
274 BasicBlock* block = schedule_->NewBasicBlock(); | 348 BasicBlock* block = schedule_->NewBasicBlock(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 void CollectSuccessorBlocks(Node* node, BasicBlock** buffer, | 385 void CollectSuccessorBlocks(Node* node, BasicBlock** buffer, |
312 IrOpcode::Value true_opcode, | 386 IrOpcode::Value true_opcode, |
313 IrOpcode::Value false_opcode) { | 387 IrOpcode::Value false_opcode) { |
314 Node* successors[2]; | 388 Node* successors[2]; |
315 CollectSuccessorProjections(node, successors, true_opcode, false_opcode); | 389 CollectSuccessorProjections(node, successors, true_opcode, false_opcode); |
316 buffer[0] = schedule_->block(successors[0]); | 390 buffer[0] = schedule_->block(successors[0]); |
317 buffer[1] = schedule_->block(successors[1]); | 391 buffer[1] = schedule_->block(successors[1]); |
318 } | 392 } |
319 | 393 |
320 void ConnectBranch(Node* branch) { | 394 void ConnectBranch(Node* branch) { |
321 Node* branch_block_node = NodeProperties::GetControlInput(branch); | |
322 BasicBlock* branch_block = schedule_->block(branch_block_node); | |
323 DCHECK(branch_block != NULL); | |
324 | |
325 BasicBlock* successor_blocks[2]; | 395 BasicBlock* successor_blocks[2]; |
326 CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue, | 396 CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue, |
327 IrOpcode::kIfFalse); | 397 IrOpcode::kIfFalse); |
328 | 398 |
329 TraceConnect(branch, branch_block, successor_blocks[0]); | |
330 TraceConnect(branch, branch_block, successor_blocks[1]); | |
331 | |
332 // Consider branch hints. | 399 // Consider branch hints. |
333 // TODO(turbofan): Propagate the deferred flag to all blocks dominated by | 400 // TODO(turbofan): Propagate the deferred flag to all blocks dominated by |
334 // this IfTrue/IfFalse later. | 401 // this IfTrue/IfFalse later. |
335 switch (BranchHintOf(branch->op())) { | 402 switch (BranchHintOf(branch->op())) { |
336 case BranchHint::kNone: | 403 case BranchHint::kNone: |
337 break; | 404 break; |
338 case BranchHint::kTrue: | 405 case BranchHint::kTrue: |
339 successor_blocks[1]->set_deferred(true); | 406 successor_blocks[1]->set_deferred(true); |
340 break; | 407 break; |
341 case BranchHint::kFalse: | 408 case BranchHint::kFalse: |
342 successor_blocks[0]->set_deferred(true); | 409 successor_blocks[0]->set_deferred(true); |
343 break; | 410 break; |
344 } | 411 } |
345 | 412 |
346 schedule_->AddBranch(branch_block, branch, successor_blocks[0], | 413 if (branch == component_head_) { |
347 successor_blocks[1]); | 414 TraceConnect(branch, component_start_, successor_blocks[0]); |
| 415 TraceConnect(branch, component_start_, successor_blocks[1]); |
| 416 schedule_->InsertBranch(component_start_, component_end_, branch, |
| 417 successor_blocks[0], successor_blocks[1]); |
| 418 } else { |
| 419 Node* branch_block_node = NodeProperties::GetControlInput(branch); |
| 420 BasicBlock* branch_block = schedule_->block(branch_block_node); |
| 421 DCHECK(branch_block != NULL); |
| 422 |
| 423 TraceConnect(branch, branch_block, successor_blocks[0]); |
| 424 TraceConnect(branch, branch_block, successor_blocks[1]); |
| 425 schedule_->AddBranch(branch_block, branch, successor_blocks[0], |
| 426 successor_blocks[1]); |
| 427 } |
348 } | 428 } |
349 | 429 |
350 void ConnectMerge(Node* merge) { | 430 void ConnectMerge(Node* merge) { |
351 // Don't connect the special merge at the end to its predecessors. | 431 // Don't connect the special merge at the end to its predecessors. |
352 if (IsFinalMerge(merge)) return; | 432 if (IsFinalMerge(merge)) return; |
353 | 433 |
354 BasicBlock* block = schedule_->block(merge); | 434 BasicBlock* block = schedule_->block(merge); |
355 DCHECK(block != NULL); | 435 DCHECK(block != NULL); |
356 // For all of the merge's control inputs, add a goto at the end to the | 436 // For all of the merge's control inputs, add a goto at the end to the |
357 // merge's basic block. | 437 // merge's basic block. |
(...skipping 20 matching lines...) Expand all Loading... |
378 } else { | 458 } else { |
379 Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(), | 459 Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(), |
380 block->id().ToInt(), succ->id().ToInt()); | 460 block->id().ToInt(), succ->id().ToInt()); |
381 } | 461 } |
382 } | 462 } |
383 | 463 |
384 bool IsFinalMerge(Node* node) { | 464 bool IsFinalMerge(Node* node) { |
385 return (node->opcode() == IrOpcode::kMerge && | 465 return (node->opcode() == IrOpcode::kMerge && |
386 node == scheduler_->graph_->end()->InputAt(0)); | 466 node == scheduler_->graph_->end()->InputAt(0)); |
387 } | 467 } |
| 468 |
| 469 Scheduler* scheduler_; |
| 470 Schedule* schedule_; |
| 471 ZoneQueue<Node*> queue_; |
| 472 NodeVector control_; |
| 473 Node* component_head_; |
| 474 BasicBlock* component_start_; |
| 475 BasicBlock* component_end_; |
388 }; | 476 }; |
389 | 477 |
390 | 478 |
391 void Scheduler::BuildCFG() { | 479 void Scheduler::BuildCFG() { |
392 Trace("--- CREATING CFG -------------------------------------------\n"); | 480 Trace("--- CREATING CFG -------------------------------------------\n"); |
| 481 |
| 482 // Build a control-flow graph for the main control-connected component that |
| 483 // is being spanned by the graph's start and end nodes. |
393 CFGBuilder cfg_builder(zone_, this); | 484 CFGBuilder cfg_builder(zone_, this); |
394 cfg_builder.Run(); | 485 cfg_builder.Run(); |
| 486 |
395 // Initialize per-block data. | 487 // Initialize per-block data. |
396 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); | 488 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); |
397 } | 489 } |
398 | 490 |
399 | 491 |
400 // ----------------------------------------------------------------------------- | 492 // ----------------------------------------------------------------------------- |
401 // Phase 2: Compute special RPO and dominator tree. | 493 // Phase 2: Compute special RPO and dominator tree. |
402 | 494 |
403 | 495 |
404 // Compute the special reverse-post-order block ordering, which is essentially | 496 // Compute the special reverse-post-order block ordering, which is essentially |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 // TODO(danno): consider using Lengauer & Tarjan's if this becomes too slow. | 952 // TODO(danno): consider using Lengauer & Tarjan's if this becomes too slow. |
861 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { | 953 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { |
862 BasicBlock* current_rpo = schedule_->rpo_order_[i]; | 954 BasicBlock* current_rpo = schedule_->rpo_order_[i]; |
863 if (current_rpo != schedule_->start()) { | 955 if (current_rpo != schedule_->start()) { |
864 BasicBlock::Predecessors::iterator current_pred = | 956 BasicBlock::Predecessors::iterator current_pred = |
865 current_rpo->predecessors_begin(); | 957 current_rpo->predecessors_begin(); |
866 BasicBlock::Predecessors::iterator end = current_rpo->predecessors_end(); | 958 BasicBlock::Predecessors::iterator end = current_rpo->predecessors_end(); |
867 DCHECK(current_pred != end); | 959 DCHECK(current_pred != end); |
868 BasicBlock* dominator = *current_pred; | 960 BasicBlock* dominator = *current_pred; |
869 ++current_pred; | 961 ++current_pred; |
870 // For multiple predecessors, walk up the rpo ordering until a common | 962 // For multiple predecessors, walk up the RPO ordering until a common |
871 // dominator is found. | 963 // dominator is found. |
872 int current_rpo_pos = GetRPONumber(current_rpo); | 964 int current_rpo_pos = GetRPONumber(current_rpo); |
873 while (current_pred != end) { | 965 while (current_pred != end) { |
874 // Don't examine backwards edges | 966 // Don't examine backwards edges |
875 BasicBlock* pred = *current_pred; | 967 BasicBlock* pred = *current_pred; |
876 if (GetRPONumber(pred) < current_rpo_pos) { | 968 if (GetRPONumber(pred) < current_rpo_pos) { |
877 dominator = GetCommonDominator(dominator, *current_pred); | 969 dominator = GetCommonDominator(dominator, *current_pred); |
878 } | 970 } |
879 ++current_pred; | 971 ++current_pred; |
880 } | 972 } |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 // optimal scheduling position. | 1176 // optimal scheduling position. |
1085 void VisitNode(Node* node) { | 1177 void VisitNode(Node* node) { |
1086 DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_); | 1178 DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_); |
1087 | 1179 |
1088 // Don't schedule nodes that are already scheduled. | 1180 // Don't schedule nodes that are already scheduled. |
1089 if (schedule_->IsScheduled(node)) return; | 1181 if (schedule_->IsScheduled(node)) return; |
1090 DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node)); | 1182 DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node)); |
1091 | 1183 |
1092 // Determine the dominating block for all of the uses of this node. It is | 1184 // Determine the dominating block for all of the uses of this node. It is |
1093 // the latest block that this node can be scheduled in. | 1185 // the latest block that this node can be scheduled in. |
| 1186 Trace("Scheduling #%d:%s\n", node->id(), node->op()->mnemonic()); |
1094 BasicBlock* block = GetCommonDominatorOfUses(node); | 1187 BasicBlock* block = GetCommonDominatorOfUses(node); |
1095 DCHECK_NOT_NULL(block); | 1188 DCHECK_NOT_NULL(block); |
1096 | 1189 |
1097 int min_rpo = scheduler_->GetData(node)->minimum_block_->rpo_number(); | 1190 int min_rpo = scheduler_->GetData(node)->minimum_block_->rpo_number(); |
1098 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n", | 1191 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n", |
1099 node->id(), node->op()->mnemonic(), block->id().ToInt(), | 1192 node->id(), node->op()->mnemonic(), block->id().ToInt(), |
1100 block->loop_depth(), min_rpo); | 1193 block->loop_depth(), min_rpo); |
1101 | 1194 |
1102 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively | 1195 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
1103 // into enclosing loop pre-headers until they would preceed their | 1196 // into enclosing loop pre-headers until they would preceed their |
1104 // ScheduleEarly position. | 1197 // ScheduleEarly position. |
1105 BasicBlock* hoist_block = GetPreHeader(block); | 1198 BasicBlock* hoist_block = GetPreHeader(block); |
1106 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { | 1199 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { |
1107 Trace(" hoisting #%d:%s to block %d\n", node->id(), | 1200 Trace(" hoisting #%d:%s to block %d\n", node->id(), |
1108 node->op()->mnemonic(), hoist_block->id().ToInt()); | 1201 node->op()->mnemonic(), hoist_block->id().ToInt()); |
1109 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); | 1202 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); |
1110 block = hoist_block; | 1203 block = hoist_block; |
1111 hoist_block = GetPreHeader(hoist_block); | 1204 hoist_block = GetPreHeader(hoist_block); |
1112 } | 1205 } |
1113 | 1206 |
1114 ScheduleNode(block, node); | 1207 // Schedule the node or a floating control structure. |
| 1208 if (NodeProperties::IsControl(node)) { |
| 1209 ScheduleFloatingControl(block, node); |
| 1210 } else { |
| 1211 ScheduleNode(block, node); |
| 1212 } |
1115 } | 1213 } |
1116 | 1214 |
1117 BasicBlock* GetPreHeader(BasicBlock* block) { | 1215 BasicBlock* GetPreHeader(BasicBlock* block) { |
1118 if (block->IsLoopHeader()) { | 1216 if (block->IsLoopHeader()) { |
1119 return block->dominator(); | 1217 return block->dominator(); |
1120 } else if (block->loop_header() != NULL) { | 1218 } else if (block->loop_header() != NULL) { |
1121 return block->loop_header()->dominator(); | 1219 return block->loop_header()->dominator(); |
1122 } else { | 1220 } else { |
1123 return NULL; | 1221 return NULL; |
1124 } | 1222 } |
(...skipping 12 matching lines...) Expand all Loading... |
1137 return block; | 1235 return block; |
1138 } | 1236 } |
1139 | 1237 |
1140 BasicBlock* GetBlockForUse(Node::Edge edge) { | 1238 BasicBlock* GetBlockForUse(Node::Edge edge) { |
1141 Node* use = edge.from(); | 1239 Node* use = edge.from(); |
1142 IrOpcode::Value opcode = use->opcode(); | 1240 IrOpcode::Value opcode = use->opcode(); |
1143 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 1241 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
1144 // If the use is from a coupled (i.e. floating) phi, compute the common | 1242 // If the use is from a coupled (i.e. floating) phi, compute the common |
1145 // dominator of its uses. This will not recurse more than one level. | 1243 // dominator of its uses. This will not recurse more than one level. |
1146 if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) { | 1244 if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) { |
1147 Trace(" inspecting uses of coupled phi #%d:%s\n", use->id(), | 1245 Trace(" inspecting uses of coupled #%d:%s\n", use->id(), |
1148 use->op()->mnemonic()); | 1246 use->op()->mnemonic()); |
1149 DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use)); | 1247 DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use)); |
1150 return GetCommonDominatorOfUses(use); | 1248 return GetCommonDominatorOfUses(use); |
1151 } | 1249 } |
1152 // If the use is from a fixed (i.e. non-floating) phi, use the block | 1250 // If the use is from a fixed (i.e. non-floating) phi, use the block |
1153 // of the corresponding control input to the merge. | 1251 // of the corresponding control input to the merge. |
1154 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { | 1252 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { |
1155 Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(), | 1253 Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(), |
1156 use->op()->mnemonic()); | 1254 use->op()->mnemonic()); |
1157 Node* merge = NodeProperties::GetControlInput(use, 0); | 1255 Node* merge = NodeProperties::GetControlInput(use, 0); |
1158 opcode = merge->opcode(); | 1256 opcode = merge->opcode(); |
1159 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); | 1257 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); |
1160 use = NodeProperties::GetControlInput(merge, edge.index()); | 1258 use = NodeProperties::GetControlInput(merge, edge.index()); |
1161 } | 1259 } |
1162 } | 1260 } |
1163 BasicBlock* result = schedule_->block(use); | 1261 BasicBlock* result = schedule_->block(use); |
1164 if (result == NULL) return NULL; | 1262 if (result == NULL) return NULL; |
1165 Trace(" must dominate use #%d:%s in B%d\n", use->id(), | 1263 Trace(" must dominate use #%d:%s in B%d\n", use->id(), |
1166 use->op()->mnemonic(), result->id().ToInt()); | 1264 use->op()->mnemonic(), result->id().ToInt()); |
1167 return result; | 1265 return result; |
1168 } | 1266 } |
1169 | 1267 |
| 1268 void ScheduleFloatingControl(BasicBlock* block, Node* node) { |
| 1269 DCHECK(scheduler_->GetData(node)->is_floating_control_); |
| 1270 scheduler_->FuseFloatingControl(block, node); |
| 1271 } |
| 1272 |
1170 void ScheduleNode(BasicBlock* block, Node* node) { | 1273 void ScheduleNode(BasicBlock* block, Node* node) { |
1171 schedule_->PlanNode(block, node); | 1274 schedule_->PlanNode(block, node); |
1172 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); | 1275 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); |
1173 | 1276 scheduler_->UpdatePlacement(node, Scheduler::kScheduled); |
1174 // Reduce the use count of the node's inputs to potentially make them | |
1175 // schedulable. If all the uses of a node have been scheduled, then the node | |
1176 // itself can be scheduled. | |
1177 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { | |
1178 scheduler_->DecrementUnscheduledUseCount(*i, i.edge().from()); | |
1179 } | |
1180 } | 1277 } |
1181 | 1278 |
1182 Scheduler* scheduler_; | 1279 Scheduler* scheduler_; |
1183 Schedule* schedule_; | 1280 Schedule* schedule_; |
1184 }; | 1281 }; |
1185 | 1282 |
1186 | 1283 |
1187 void Scheduler::ScheduleLate() { | 1284 void Scheduler::ScheduleLate() { |
1188 Trace("--- SCHEDULE LATE ------------------------------------------\n"); | 1285 Trace("--- SCHEDULE LATE ------------------------------------------\n"); |
1189 if (FLAG_trace_turbo_scheduler) { | 1286 if (FLAG_trace_turbo_scheduler) { |
(...skipping 17 matching lines...) Expand all Loading... |
1207 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); | 1304 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); |
1208 } | 1305 } |
1209 block_num++; | 1306 block_num++; |
1210 } | 1307 } |
1211 } | 1308 } |
1212 | 1309 |
1213 | 1310 |
1214 // ----------------------------------------------------------------------------- | 1311 // ----------------------------------------------------------------------------- |
1215 | 1312 |
1216 | 1313 |
1217 bool Scheduler::ConnectFloatingControl() { | 1314 void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) { |
1218 if (!has_floating_control_) return false; | 1315 Trace("--- FUSE FLOATING CONTROL ----------------------------------\n"); |
1219 | 1316 if (FLAG_trace_turbo_scheduler) { |
1220 Trace("Connecting floating control...\n"); | 1317 OFStream os(stdout); |
1221 | 1318 os << "Schedule before control flow fusion:\n" << *schedule_; |
1222 // Process blocks and instructions backwards to find and connect floating | |
1223 // control nodes into the control graph according to the block they were | |
1224 // scheduled into. | |
1225 int max = static_cast<int>(schedule_->rpo_order()->size()); | |
1226 for (int i = max - 1; i >= 0; i--) { | |
1227 BasicBlock* block = schedule_->rpo_order()->at(i); | |
1228 // TODO(titzer): we place at most one floating control structure per | |
1229 // basic block because scheduling currently can interleave phis from | |
1230 // one subgraph with the merges from another subgraph. | |
1231 for (size_t j = 0; j < block->NodeCount(); j++) { | |
1232 Node* node = block->NodeAt(block->NodeCount() - 1 - j); | |
1233 SchedulerData* data = GetData(node); | |
1234 if (data->is_floating_control_ && !data->is_connected_control_) { | |
1235 Trace(" Floating control #%d:%s was scheduled in B%d\n", node->id(), | |
1236 node->op()->mnemonic(), block->id().ToInt()); | |
1237 ConnectFloatingControlSubgraph(block, node); | |
1238 break; | |
1239 } | |
1240 } | |
1241 } | 1319 } |
1242 | 1320 |
1243 return true; | 1321 // Iterate on phase 1: Build control-flow graph. |
| 1322 CFGBuilder cfg_builder(zone_, this); |
| 1323 cfg_builder.Run(block, node); |
| 1324 |
| 1325 // Iterate on phase 2: Compute special RPO and dominator tree. |
| 1326 // TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that. |
| 1327 BasicBlockVector* rpo = schedule_->rpo_order(); |
| 1328 for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) { |
| 1329 BasicBlock* block = *i; |
| 1330 block->set_rpo_number(-1); |
| 1331 block->set_loop_header(NULL); |
| 1332 block->set_loop_depth(0); |
| 1333 block->set_loop_end(-1); |
| 1334 } |
| 1335 schedule_->rpo_order()->clear(); |
| 1336 SpecialRPONumberer numberer(zone_, schedule_); |
| 1337 numberer.ComputeSpecialRPO(); |
| 1338 GenerateImmediateDominatorTree(); |
| 1339 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); |
| 1340 |
| 1341 // Move previously planned nodes. |
| 1342 // TODO(mstarzinger): Improve that by supporting bulk moves. |
| 1343 MovePlannedNodes(block, schedule_->block(node)); |
| 1344 |
| 1345 if (FLAG_trace_turbo_scheduler) { |
| 1346 OFStream os(stdout); |
| 1347 os << "Schedule after control flow fusion:" << *schedule_; |
| 1348 } |
1244 } | 1349 } |
1245 | 1350 |
1246 | 1351 |
1247 void Scheduler::ConnectFloatingControlSubgraph(BasicBlock* block, Node* end) { | 1352 void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) { |
1248 Node* block_start = block->NodeAt(0); | 1353 Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(), |
1249 DCHECK(IrOpcode::IsControlOpcode(block_start->opcode())); | 1354 to->id().ToInt()); |
1250 // Find the current "control successor" of the node that starts the block | 1355 NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]); |
1251 // by searching the control uses for a control input edge from a connected | 1356 for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) { |
1252 // control node. | 1357 schedule_->SetBlockForNode(to, *i); |
1253 Node* control_succ = NULL; | 1358 scheduled_nodes_[to->id().ToSize()].push_back(*i); |
1254 for (UseIter i = block_start->uses().begin(); i != block_start->uses().end(); | |
1255 ++i) { | |
1256 Node::Edge edge = i.edge(); | |
1257 if (NodeProperties::IsControlEdge(edge) && | |
1258 GetData(edge.from())->is_connected_control_) { | |
1259 DCHECK_EQ(NULL, control_succ); | |
1260 control_succ = edge.from(); | |
1261 control_succ->ReplaceInput(edge.index(), end); | |
1262 } | |
1263 } | 1359 } |
1264 DCHECK_NE(NULL, control_succ); | 1360 nodes->clear(); |
1265 Trace(" Inserting floating control end %d:%s between %d:%s -> %d:%s\n", | |
1266 end->id(), end->op()->mnemonic(), control_succ->id(), | |
1267 control_succ->op()->mnemonic(), block_start->id(), | |
1268 block_start->op()->mnemonic()); | |
1269 | |
1270 // Find the "start" node of the control subgraph, which should be the | |
1271 // unique node that is itself floating control but has a control input that | |
1272 // is not floating. | |
1273 Node* start = NULL; | |
1274 ZoneQueue<Node*> queue(zone_); | |
1275 queue.push(end); | |
1276 GetData(end)->is_connected_control_ = true; | |
1277 while (!queue.empty()) { | |
1278 Node* node = queue.front(); | |
1279 queue.pop(); | |
1280 Trace(" Search #%d:%s for control subgraph start\n", node->id(), | |
1281 node->op()->mnemonic()); | |
1282 int max = NodeProperties::PastControlIndex(node); | |
1283 for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) { | |
1284 Node* input = node->InputAt(i); | |
1285 SchedulerData* data = GetData(input); | |
1286 if (data->is_floating_control_) { | |
1287 // {input} is floating control. | |
1288 if (!data->is_connected_control_) { | |
1289 // First time seeing {input} during this traversal, queue it. | |
1290 queue.push(input); | |
1291 data->is_connected_control_ = true; | |
1292 } | |
1293 } else { | |
1294 // Otherwise, {node} is the start node, because it is floating control | |
1295 // but is connected to {input} that is not floating control. | |
1296 DCHECK_EQ(NULL, start); // There can be only one. | |
1297 start = node; | |
1298 } | |
1299 } | |
1300 } | |
1301 | |
1302 DCHECK_NE(NULL, start); | |
1303 start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start); | |
1304 | |
1305 Trace(" Connecting floating control start %d:%s to %d:%s\n", start->id(), | |
1306 start->op()->mnemonic(), block_start->id(), | |
1307 block_start->op()->mnemonic()); | |
1308 } | 1361 } |
1309 | 1362 |
1310 } // namespace compiler | 1363 } // namespace compiler |
1311 } // namespace internal | 1364 } // namespace internal |
1312 } // namespace v8 | 1365 } // namespace v8 |
OLD | NEW |