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

Side by Side Diff: src/compiler/scheduler.cc

Issue 642803003: Improve comments and readability of scheduler. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « src/compiler/scheduler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 10 matching lines...) Expand all
21 static inline void Trace(const char* msg, ...) { 21 static inline void Trace(const char* msg, ...) {
22 if (FLAG_trace_turbo_scheduler) { 22 if (FLAG_trace_turbo_scheduler) {
23 va_list arguments; 23 va_list arguments;
24 va_start(arguments, msg); 24 va_start(arguments, msg);
25 base::OS::VPrint(msg, arguments); 25 base::OS::VPrint(msg, arguments);
26 va_end(arguments); 26 va_end(arguments);
27 } 27 }
28 } 28 }
29 29
30 30
31 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
32 : zone_(zone),
33 graph_(graph),
34 schedule_(schedule),
35 scheduled_nodes_(zone),
36 schedule_root_nodes_(zone),
37 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
38 has_floating_control_(false) {}
39
40
41 Schedule* Scheduler::ComputeSchedule(Graph* graph) {
42 Schedule* schedule;
43 bool had_floating_control = false;
44 do {
45 Zone tmp_zone(graph->zone()->isolate());
46 schedule = new (graph->zone())
47 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
48 Scheduler scheduler(&tmp_zone, graph, schedule);
49
50 scheduler.BuildCFG();
51 Scheduler::ComputeSpecialRPO(schedule);
52 scheduler.GenerateImmediateDominatorTree();
53
54 scheduler.PrepareUses();
55 scheduler.ScheduleEarly();
56 scheduler.ScheduleLate();
57
58 had_floating_control = scheduler.ConnectFloatingControl();
59 } while (had_floating_control);
60
61 return schedule;
62 }
63
64
65 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
66 SchedulerData def = {0, -1, false, false, kUnknown};
67 return def;
68 }
69
70
71 Scheduler::Placement Scheduler::GetPlacement(Node* node) {
72 SchedulerData* data = GetData(node);
73 if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
74 switch (node->opcode()) {
75 case IrOpcode::kParameter:
76 // Parameters are always fixed to the start node.
77 data->placement_ = kFixed;
78 break;
79 case IrOpcode::kPhi:
80 case IrOpcode::kEffectPhi: {
81 // Phis and effect phis are fixed if their control inputs are.
82 data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
83 break;
84 }
85 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
86 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
87 #undef DEFINE_FLOATING_CONTROL_CASE
88 {
89 // Control nodes that were not control-reachable from end may float.
90 data->placement_ = kSchedulable;
91 if (!data->is_connected_control_) {
92 data->is_floating_control_ = true;
93 has_floating_control_ = true;
94 Trace("Floating control found: #%d:%s\n", node->id(),
95 node->op()->mnemonic());
96 }
97 break;
98 }
99 default:
100 data->placement_ = kSchedulable;
101 break;
102 }
103 }
104 return data->placement_;
105 }
106
107
108 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
109 while (b1 != b2) {
110 int b1_rpo = GetRPONumber(b1);
111 int b2_rpo = GetRPONumber(b2);
112 DCHECK(b1_rpo != b2_rpo);
113 if (b1_rpo < b2_rpo) {
114 b2 = b2->dominator();
115 } else {
116 b1 = b1->dominator();
117 }
118 }
119 return b1;
120 }
121
122
123 // -----------------------------------------------------------------------------
124 // Phase 1: Build control-flow graph and dominator tree.
125
126
31 // Internal class to build a control flow graph (i.e the basic blocks and edges 127 // Internal class to build a control flow graph (i.e the basic blocks and edges
32 // between them within a Schedule) from the node graph. 128 // between them within a Schedule) from the node graph.
33 // Visits the control edges of the graph backwards from end in order to find 129 // Visits the control edges of the graph backwards from end in order to find
34 // the connected control subgraph, needed for scheduling. 130 // the connected control subgraph, needed for scheduling.
35 class CFGBuilder { 131 class CFGBuilder {
36 public: 132 public:
37 Scheduler* scheduler_; 133 Scheduler* scheduler_;
38 Schedule* schedule_; 134 Schedule* schedule_;
39 ZoneQueue<Node*> queue_; 135 ZoneQueue<Node*> queue_;
40 NodeVector control_; 136 NodeVector control_;
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(), 307 Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(),
212 block->id().ToInt()); 308 block->id().ToInt());
213 } else { 309 } else {
214 Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(), 310 Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(),
215 block->id().ToInt(), succ->id().ToInt()); 311 block->id().ToInt(), succ->id().ToInt());
216 } 312 }
217 } 313 }
218 }; 314 };
219 315
220 316
221 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
222 SchedulerData def = {0, -1, false, false, kUnknown};
223 return def;
224 }
225
226
227 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
228 : zone_(zone),
229 graph_(graph),
230 schedule_(schedule),
231 scheduled_nodes_(zone),
232 schedule_root_nodes_(zone),
233 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
234 has_floating_control_(false) {}
235
236
237 Schedule* Scheduler::ComputeSchedule(Graph* graph) {
238 Schedule* schedule;
239 bool had_floating_control = false;
240 do {
241 Zone tmp_zone(graph->zone()->isolate());
242 schedule = new (graph->zone())
243 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
244 Scheduler scheduler(&tmp_zone, graph, schedule);
245
246 scheduler.BuildCFG();
247
248 Scheduler::ComputeSpecialRPO(schedule);
249 scheduler.GenerateImmediateDominatorTree();
250
251 scheduler.PrepareUses();
252 scheduler.ScheduleEarly();
253 scheduler.ScheduleLate();
254
255 had_floating_control = scheduler.ConnectFloatingControl();
256 } while (had_floating_control);
257
258 return schedule;
259 }
260
261
262 Scheduler::Placement Scheduler::GetPlacement(Node* node) {
263 SchedulerData* data = GetData(node);
264 if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
265 switch (node->opcode()) {
266 case IrOpcode::kParameter:
267 // Parameters are always fixed to the start node.
268 data->placement_ = kFixed;
269 break;
270 case IrOpcode::kPhi:
271 case IrOpcode::kEffectPhi: {
272 // Phis and effect phis are fixed if their control inputs are.
273 data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
274 break;
275 }
276 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
277 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
278 #undef DEFINE_FLOATING_CONTROL_CASE
279 {
280 // Control nodes that were not control-reachable from end may float.
281 data->placement_ = kSchedulable;
282 if (!data->is_connected_control_) {
283 data->is_floating_control_ = true;
284 has_floating_control_ = true;
285 Trace("Floating control found: #%d:%s\n", node->id(),
286 node->op()->mnemonic());
287 }
288 break;
289 }
290 default:
291 data->placement_ = kSchedulable;
292 break;
293 }
294 }
295 return data->placement_;
296 }
297
298
299 void Scheduler::BuildCFG() { 317 void Scheduler::BuildCFG() {
300 Trace("---------------- CREATING CFG ------------------\n"); 318 Trace("---------------- CREATING CFG ------------------\n");
301 CFGBuilder cfg_builder(zone_, this); 319 CFGBuilder cfg_builder(zone_, this);
302 cfg_builder.Run(); 320 cfg_builder.Run();
303 // Initialize per-block data. 321 // Initialize per-block data.
304 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); 322 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
305 } 323 }
306 324
307 325
308 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
309 while (b1 != b2) {
310 int b1_rpo = GetRPONumber(b1);
311 int b2_rpo = GetRPONumber(b2);
312 DCHECK(b1_rpo != b2_rpo);
313 if (b1_rpo < b2_rpo) {
314 b2 = b2->dominator();
315 } else {
316 b1 = b1->dominator();
317 }
318 }
319 return b1;
320 }
321
322
323 void Scheduler::GenerateImmediateDominatorTree() { 326 void Scheduler::GenerateImmediateDominatorTree() {
324 // Build the dominator graph. TODO(danno): consider using Lengauer & Tarjan's 327 // Build the dominator graph. TODO(danno): consider using Lengauer & Tarjan's
325 // if this becomes really slow. 328 // if this becomes really slow.
326 Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n"); 329 Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n");
327 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) { 330 for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) {
328 BasicBlock* current_rpo = schedule_->rpo_order_[i]; 331 BasicBlock* current_rpo = schedule_->rpo_order_[i];
329 if (current_rpo != schedule_->start()) { 332 if (current_rpo != schedule_->start()) {
330 BasicBlock::Predecessors::iterator current_pred = 333 BasicBlock::Predecessors::iterator current_pred =
331 current_rpo->predecessors_begin(); 334 current_rpo->predecessors_begin();
332 BasicBlock::Predecessors::iterator end = current_rpo->predecessors_end(); 335 BasicBlock::Predecessors::iterator end = current_rpo->predecessors_end();
(...skipping 12 matching lines...) Expand all
345 ++current_pred; 348 ++current_pred;
346 } 349 }
347 current_rpo->set_dominator(dominator); 350 current_rpo->set_dominator(dominator);
348 Trace("Block %d's idom is %d\n", current_rpo->id().ToInt(), 351 Trace("Block %d's idom is %d\n", current_rpo->id().ToInt(),
349 dominator->id().ToInt()); 352 dominator->id().ToInt());
350 } 353 }
351 } 354 }
352 } 355 }
353 356
354 357
358 // -----------------------------------------------------------------------------
359 // Phase 2: Prepare use counts for nodes.
360
361
362 class PrepareUsesVisitor : public NullNodeVisitor {
363 public:
364 explicit PrepareUsesVisitor(Scheduler* scheduler)
365 : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
366
367 GenericGraphVisit::Control Pre(Node* node) {
368 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
369 // Fixed nodes are always roots for schedule late.
370 scheduler_->schedule_root_nodes_.push_back(node);
371 if (!schedule_->IsScheduled(node)) {
372 // Make sure root nodes are scheduled in their respective blocks.
373 Trace(" Scheduling fixed position node #%d:%s\n", node->id(),
374 node->op()->mnemonic());
375 IrOpcode::Value opcode = node->opcode();
376 BasicBlock* block =
377 opcode == IrOpcode::kParameter
378 ? schedule_->start()
379 : schedule_->block(NodeProperties::GetControlInput(node));
380 DCHECK(block != NULL);
381 schedule_->AddNode(block, node);
382 }
383 }
384
385 return GenericGraphVisit::CONTINUE;
386 }
387
388 void PostEdge(Node* from, int index, Node* to) {
389 // If the edge is from an unscheduled node, then tally it in the use count
390 // for all of its inputs. The same criterion will be used in ScheduleLate
391 // for decrementing use counts.
392 if (!schedule_->IsScheduled(from)) {
393 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
394 ++(scheduler_->GetData(to)->unscheduled_count_);
395 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
396 to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
397 scheduler_->GetData(to)->unscheduled_count_);
398 }
399 }
400
401 private:
402 Scheduler* scheduler_;
403 Schedule* schedule_;
404 };
405
406
407 void Scheduler::PrepareUses() {
408 Trace("------------------- PREPARE USES ------------------\n");
409
410 // Count the uses of every node, it will be used to ensure that all of a
411 // node's uses are scheduled before the node itself.
412 PrepareUsesVisitor prepare_uses(this);
413 graph_->VisitNodeInputsFromEnd(&prepare_uses);
414 }
415
416
417 // -----------------------------------------------------------------------------
418 // Phase 3: Schedule nodes early.
419
420
355 class ScheduleEarlyNodeVisitor : public NullNodeVisitor { 421 class ScheduleEarlyNodeVisitor : public NullNodeVisitor {
356 public: 422 public:
357 explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler) 423 explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler)
358 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} 424 : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
359 425
360 GenericGraphVisit::Control Pre(Node* node) { 426 GenericGraphVisit::Control Pre(Node* node) {
361 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) { 427 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
362 // Fixed nodes already know their schedule early position. 428 // Fixed nodes already know their schedule early position.
363 Scheduler::SchedulerData* data = scheduler_->GetData(node); 429 Scheduler::SchedulerData* data = scheduler_->GetData(node);
364 BasicBlock* block = schedule_->block(node); 430 BasicBlock* block = schedule_->block(node);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 void Scheduler::ScheduleEarly() { 488 void Scheduler::ScheduleEarly() {
423 Trace("------------------- SCHEDULE EARLY ----------------\n"); 489 Trace("------------------- SCHEDULE EARLY ----------------\n");
424 490
425 // Compute the minimum RPO for each node thereby determining the earliest 491 // Compute the minimum RPO for each node thereby determining the earliest
426 // position each node could be placed within a valid schedule. 492 // position each node could be placed within a valid schedule.
427 ScheduleEarlyNodeVisitor visitor(this); 493 ScheduleEarlyNodeVisitor visitor(this);
428 graph_->VisitNodeInputsFromEnd(&visitor); 494 graph_->VisitNodeInputsFromEnd(&visitor);
429 } 495 }
430 496
431 497
432 class PrepareUsesVisitor : public NullNodeVisitor { 498 // -----------------------------------------------------------------------------
433 public: 499 // Phase 4: Schedule nodes late.
434 explicit PrepareUsesVisitor(Scheduler* scheduler)
435 : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
436
437 GenericGraphVisit::Control Pre(Node* node) {
438 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
439 // Fixed nodes are always roots for schedule late.
440 scheduler_->schedule_root_nodes_.push_back(node);
441 if (!schedule_->IsScheduled(node)) {
442 // Make sure root nodes are scheduled in their respective blocks.
443 Trace(" Scheduling fixed position node #%d:%s\n", node->id(),
444 node->op()->mnemonic());
445 IrOpcode::Value opcode = node->opcode();
446 BasicBlock* block =
447 opcode == IrOpcode::kParameter
448 ? schedule_->start()
449 : schedule_->block(NodeProperties::GetControlInput(node));
450 DCHECK(block != NULL);
451 schedule_->AddNode(block, node);
452 }
453 }
454
455 return GenericGraphVisit::CONTINUE;
456 }
457
458 void PostEdge(Node* from, int index, Node* to) {
459 // If the edge is from an unscheduled node, then tally it in the use count
460 // for all of its inputs. The same criterion will be used in ScheduleLate
461 // for decrementing use counts.
462 if (!schedule_->IsScheduled(from)) {
463 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
464 ++(scheduler_->GetData(to)->unscheduled_count_);
465 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
466 to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
467 scheduler_->GetData(to)->unscheduled_count_);
468 }
469 }
470
471 private:
472 Scheduler* scheduler_;
473 Schedule* schedule_;
474 };
475
476
477 void Scheduler::PrepareUses() {
478 Trace("------------------- PREPARE USES ------------------\n");
479
480 // Count the uses of every node, it will be used to ensure that all of a
481 // node's uses are scheduled before the node itself.
482 PrepareUsesVisitor prepare_uses(this);
483 graph_->VisitNodeInputsFromEnd(&prepare_uses);
484 }
485 500
486 501
487 class ScheduleLateNodeVisitor : public NullNodeVisitor { 502 class ScheduleLateNodeVisitor : public NullNodeVisitor {
488 public: 503 public:
489 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) 504 explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
490 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} 505 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
491 506
492 GenericGraphVisit::Control Pre(Node* node) { 507 GenericGraphVisit::Control Pre(Node* node) {
493 // Don't schedule nodes that are already scheduled. 508 // Don't schedule nodes that are already scheduled.
494 if (schedule_->IsScheduled(node)) { 509 if (schedule_->IsScheduled(node)) {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 for (NodeVectorVectorIter i = scheduled_nodes_.begin(); 645 for (NodeVectorVectorIter i = scheduled_nodes_.begin();
631 i != scheduled_nodes_.end(); ++i) { 646 i != scheduled_nodes_.end(); ++i) {
632 for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) { 647 for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) {
633 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); 648 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j);
634 } 649 }
635 block_num++; 650 block_num++;
636 } 651 }
637 } 652 }
638 653
639 654
655 // -----------------------------------------------------------------------------
656
657
640 bool Scheduler::ConnectFloatingControl() { 658 bool Scheduler::ConnectFloatingControl() {
641 if (!has_floating_control_) return false; 659 if (!has_floating_control_) return false;
642 660
643 Trace("Connecting floating control...\n"); 661 Trace("Connecting floating control...\n");
644 662
645 // Process blocks and instructions backwards to find and connect floating 663 // Process blocks and instructions backwards to find and connect floating
646 // control nodes into the control graph according to the block they were 664 // control nodes into the control graph according to the block they were
647 // scheduled into. 665 // scheduled into.
648 int max = static_cast<int>(schedule_->rpo_order()->size()); 666 int max = static_cast<int>(schedule_->rpo_order()->size());
649 for (int i = max - 1; i >= 0; i--) { 667 for (int i = max - 1; i >= 0; i--) {
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 current->loop_header()->id().ToInt(), current->loop_depth()); 1148 current->loop_header()->id().ToInt(), current->loop_depth());
1131 } 1149 }
1132 } 1150 }
1133 1151
1134 #if DEBUG 1152 #if DEBUG
1135 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); 1153 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
1136 VerifySpecialRPO(num_loops, loops, final_order); 1154 VerifySpecialRPO(num_loops, loops, final_order);
1137 #endif 1155 #endif
1138 return final_order; 1156 return final_order;
1139 } 1157 }
1140 } 1158
1141 } 1159 } // namespace compiler
1142 } // namespace v8::internal::compiler 1160 } // namespace internal
1161 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/scheduler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698