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

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

Issue 669683002: Make sure floating phi nodes are coupled to their control. (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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 return schedule; 61 return schedule;
62 } 62 }
63 63
64 64
65 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { 65 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
66 SchedulerData def = {NULL, 0, false, false, kUnknown}; 66 SchedulerData def = {NULL, 0, false, false, kUnknown};
67 return def; 67 return def;
68 } 68 }
69 69
70 70
71 Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
72 DCHECK(node->id() < static_cast<int>(node_data_.size()));
73 return &node_data_[node->id()];
74 }
75
76
71 Scheduler::Placement Scheduler::GetPlacement(Node* node) { 77 Scheduler::Placement Scheduler::GetPlacement(Node* node) {
72 SchedulerData* data = GetData(node); 78 SchedulerData* data = GetData(node);
73 if (data->placement_ == kUnknown) { // Compute placement, once, on demand. 79 if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
74 switch (node->opcode()) { 80 switch (node->opcode()) {
75 case IrOpcode::kParameter: 81 case IrOpcode::kParameter:
76 // Parameters are always fixed to the start node. 82 // Parameters are always fixed to the start node.
77 data->placement_ = kFixed; 83 data->placement_ = kFixed;
78 break; 84 break;
79 case IrOpcode::kPhi: 85 case IrOpcode::kPhi:
80 case IrOpcode::kEffectPhi: { 86 case IrOpcode::kEffectPhi: {
81 // Phis and effect phis are fixed if their control inputs are. 87 // Phis and effect phis are fixed if their control inputs are, whereas
82 data->placement_ = GetPlacement(NodeProperties::GetControlInput(node)); 88 // otherwise they are coupled to a floating control node.
89 Placement p = GetPlacement(NodeProperties::GetControlInput(node));
90 data->placement_ = (p == kFixed ? kFixed : kCoupled);
83 break; 91 break;
84 } 92 }
85 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: 93 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
86 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) 94 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
87 #undef DEFINE_FLOATING_CONTROL_CASE 95 #undef DEFINE_FLOATING_CONTROL_CASE
88 { 96 {
89 // Control nodes that were not control-reachable from end may float. 97 // Control nodes that were not control-reachable from end may float.
90 data->placement_ = kSchedulable; 98 data->placement_ = kSchedulable;
91 if (!data->is_connected_control_) { 99 if (!data->is_connected_control_) {
92 data->is_floating_control_ = true; 100 data->is_floating_control_ = true;
93 has_floating_control_ = true; 101 has_floating_control_ = true;
102 // TODO(mstarzinger): Workaround to fix visitation order.
103 schedule_root_nodes_.push_back(node);
94 Trace("Floating control found: #%d:%s\n", node->id(), 104 Trace("Floating control found: #%d:%s\n", node->id(),
95 node->op()->mnemonic()); 105 node->op()->mnemonic());
96 } 106 }
97 break; 107 break;
98 } 108 }
99 default: 109 default:
100 data->placement_ = kSchedulable; 110 data->placement_ = kSchedulable;
101 break; 111 break;
102 } 112 }
103 } 113 }
104 return data->placement_; 114 return data->placement_;
105 } 115 }
106 116
107 117
118 void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) {
119 if (GetPlacement(node) == kCoupled) {
120 // Use count for coupled nodes is summed up on their control.
121 Node* control = NodeProperties::GetControlInput(node);
122 return IncrementUnscheduledUseCount(control, from);
123 }
124 ++(GetData(node)->unscheduled_count_);
125 if (FLAG_trace_turbo_scheduler) {
126 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
127 node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
128 GetData(node)->unscheduled_count_);
129 }
130 }
131
132
133 void Scheduler::DecrementUnscheduledUseCount(Node* node, Node* from) {
134 if (GetPlacement(node) == kCoupled) {
135 // Use count for coupled nodes is summed up on their control.
136 Node* control = NodeProperties::GetControlInput(node);
137 return DecrementUnscheduledUseCount(control, from);
138 }
139 DCHECK(GetData(node)->unscheduled_count_ > 0);
140 --(GetData(node)->unscheduled_count_);
141 if (FLAG_trace_turbo_scheduler) {
142 Trace(" Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(),
143 node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
144 GetData(node)->unscheduled_count_);
145 if (GetData(node)->unscheduled_count_ == 0) {
146 Trace(" newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
147 }
148 }
149 }
150
151
152 int Scheduler::GetRPONumber(BasicBlock* block) {
153 DCHECK(block->rpo_number() >= 0 &&
154 block->rpo_number() < static_cast<int>(schedule_->rpo_order_.size()));
155 DCHECK(schedule_->rpo_order_[block->rpo_number()] == block);
156 return block->rpo_number();
157 }
158
159
108 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { 160 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
109 while (b1 != b2) { 161 while (b1 != b2) {
110 int b1_rpo = GetRPONumber(b1); 162 int b1_rpo = GetRPONumber(b1);
111 int b2_rpo = GetRPONumber(b2); 163 int b2_rpo = GetRPONumber(b2);
112 DCHECK(b1_rpo != b2_rpo); 164 DCHECK(b1_rpo != b2_rpo);
113 if (b1_rpo < b2_rpo) { 165 if (b1_rpo < b2_rpo) {
114 b2 = b2->dominator(); 166 b2 = b2->dominator();
115 } else { 167 } else {
116 b1 = b1->dominator(); 168 b1 = b1->dominator();
117 } 169 }
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 437
386 return GenericGraphVisit::CONTINUE; 438 return GenericGraphVisit::CONTINUE;
387 } 439 }
388 440
389 void PostEdge(Node* from, int index, Node* to) { 441 void PostEdge(Node* from, int index, Node* to) {
390 // If the edge is from an unscheduled node, then tally it in the use count 442 // If the edge is from an unscheduled node, then tally it in the use count
391 // for all of its inputs. The same criterion will be used in ScheduleLate 443 // for all of its inputs. The same criterion will be used in ScheduleLate
392 // for decrementing use counts. 444 // for decrementing use counts.
393 if (!schedule_->IsScheduled(from)) { 445 if (!schedule_->IsScheduled(from)) {
394 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from)); 446 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
395 ++(scheduler_->GetData(to)->unscheduled_count_); 447 scheduler_->IncrementUnscheduledUseCount(to, from);
396 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
397 to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
398 scheduler_->GetData(to)->unscheduled_count_);
399 if (OperatorProperties::IsBasicBlockBegin(to->op()) &&
400 (from->opcode() == IrOpcode::kEffectPhi ||
401 from->opcode() == IrOpcode::kPhi) &&
402 scheduler_->GetData(to)->is_floating_control_ &&
403 !scheduler_->GetData(to)->is_connected_control_) {
404 for (InputIter i = from->inputs().begin(); i != from->inputs().end();
405 ++i) {
406 if (!NodeProperties::IsControlEdge(i.edge())) {
407 ++(scheduler_->GetData(*i)->unscheduled_count_);
408 Trace(
409 " Use count of #%d:%s (additional dependency of #%d:%s)++ = "
410 "%d\n",
411 (*i)->id(), (*i)->op()->mnemonic(), to->id(),
412 to->op()->mnemonic(),
413 scheduler_->GetData(*i)->unscheduled_count_);
414 }
415 }
416 }
417 } 448 }
418 } 449 }
419 450
420 private: 451 private:
421 Scheduler* scheduler_; 452 Scheduler* scheduler_;
422 Schedule* schedule_; 453 Schedule* schedule_;
423 }; 454 };
424 455
425 456
426 void Scheduler::PrepareUses() { 457 void Scheduler::PrepareUses() {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 public: 549 public:
519 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) 550 explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
520 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} 551 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
521 552
522 GenericGraphVisit::Control Pre(Node* node) { 553 GenericGraphVisit::Control Pre(Node* node) {
523 // Don't schedule nodes that are already scheduled. 554 // Don't schedule nodes that are already scheduled.
524 if (schedule_->IsScheduled(node)) { 555 if (schedule_->IsScheduled(node)) {
525 return GenericGraphVisit::CONTINUE; 556 return GenericGraphVisit::CONTINUE;
526 } 557 }
527 558
559 // Don't schedule coupled nodes on their own.
560 if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
561 Node* control = NodeProperties::GetControlInput(node);
562 scheduler_->DecrementUnscheduledUseCount(control, node);
563 return GenericGraphVisit::CONTINUE;
564 }
565
528 Scheduler::SchedulerData* data = scheduler_->GetData(node); 566 Scheduler::SchedulerData* data = scheduler_->GetData(node);
529 DCHECK_EQ(Scheduler::kSchedulable, data->placement_); 567 DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node));
530 568
531 // If all the uses of a node have been scheduled, then the node itself can 569 // If all the uses of a node have been scheduled, then the node itself can
532 // be scheduled. 570 // be scheduled.
533 bool eligible = data->unscheduled_count_ == 0; 571 bool eligible = data->unscheduled_count_ == 0;
534 Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(), 572 Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(),
535 node->op()->mnemonic(), eligible ? "true" : "false"); 573 node->op()->mnemonic(), eligible ? "true" : "false");
536 if (!eligible) return GenericGraphVisit::DEFER; 574 if (!eligible) return GenericGraphVisit::DEFER;
537 575
538 // Determine the dominating block for all of the uses of this node. It is 576 // Determine the dominating block for all of the uses of this node. It is
539 // the latest block that this node can be scheduled in. 577 // the latest block that this node can be scheduled in.
540 BasicBlock* block = NULL; 578 BasicBlock* block = GetCommonDominatorOfUses(node);
541 for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end(); 579 DCHECK_NE(NULL, block);
542 ++i) {
543 BasicBlock* use_block = GetBlockForUse(i.edge());
544 block = block == NULL ? use_block : use_block == NULL
545 ? block
546 : scheduler_->GetCommonDominator(
547 block, use_block);
548 }
549 DCHECK(block != NULL);
550 580
551 int min_rpo = data->minimum_block_->rpo_number(); 581 int min_rpo = data->minimum_block_->rpo_number();
552 Trace( 582 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n",
553 "Schedule late conservative for #%d:%s is B%d at loop depth %d, " 583 node->id(), node->op()->mnemonic(), block->id().ToInt(),
554 "minimum_rpo = %d\n", 584 block->loop_depth(), min_rpo);
555 node->id(), node->op()->mnemonic(), block->id().ToInt(), 585
556 block->loop_depth(), min_rpo);
557 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively 586 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
558 // into enclosing loop pre-headers until they would preceed their 587 // into enclosing loop pre-headers until they would preceed their
559 // ScheduleEarly position. 588 // ScheduleEarly position.
560 BasicBlock* hoist_block = block; 589 BasicBlock* hoist_block = block;
561 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { 590 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) {
562 if (hoist_block->loop_depth() < block->loop_depth()) { 591 if (hoist_block->loop_depth() < block->loop_depth()) {
563 block = hoist_block; 592 block = hoist_block;
564 Trace(" hoisting #%d:%s to block %d\n", node->id(), 593 Trace(" hoisting #%d:%s to block %d\n", node->id(),
565 node->op()->mnemonic(), block->id().ToInt()); 594 node->op()->mnemonic(), block->id().ToInt());
566 } 595 }
(...skipping 10 matching lines...) Expand all
577 hoist_block = pre_header; 606 hoist_block = pre_header;
578 } 607 }
579 } 608 }
580 609
581 ScheduleNode(block, node); 610 ScheduleNode(block, node);
582 611
583 return GenericGraphVisit::CONTINUE; 612 return GenericGraphVisit::CONTINUE;
584 } 613 }
585 614
586 private: 615 private:
616 BasicBlock* GetCommonDominatorOfUses(Node* node) {
617 BasicBlock* block = NULL;
618 Node::Uses uses = node->uses();
619 for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
620 BasicBlock* use_block = GetBlockForUse(i.edge());
621 block = block == NULL ? use_block : use_block == NULL
622 ? block
623 : scheduler_->GetCommonDominator(
624 block, use_block);
625 }
626 return block;
627 }
628
587 BasicBlock* GetBlockForUse(Node::Edge edge) { 629 BasicBlock* GetBlockForUse(Node::Edge edge) {
588 Node* use = edge.from(); 630 Node* use = edge.from();
589 IrOpcode::Value opcode = use->opcode(); 631 IrOpcode::Value opcode = use->opcode();
590 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { 632 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
633 // If the use is from a coupled (i.e. floating) phi, compute the common
634 // dominator of its uses. This will not recurse more than one level.
635 if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
636 Trace(" inspecting uses of coupled phi #%d:%s\n", use->id(),
637 use->op()->mnemonic());
638 DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
639 return GetCommonDominatorOfUses(use);
640 }
591 // If the use is from a fixed (i.e. non-floating) phi, use the block 641 // If the use is from a fixed (i.e. non-floating) phi, use the block
592 // of the corresponding control input to the merge. 642 // of the corresponding control input to the merge.
593 int index = edge.index();
594 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { 643 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
595 Trace(" input@%d into a fixed phi #%d:%s\n", index, use->id(), 644 Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
596 use->op()->mnemonic()); 645 use->op()->mnemonic());
597 Node* merge = NodeProperties::GetControlInput(use, 0); 646 Node* merge = NodeProperties::GetControlInput(use, 0);
598 opcode = merge->opcode(); 647 opcode = merge->opcode();
599 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); 648 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
600 use = NodeProperties::GetControlInput(merge, index); 649 use = NodeProperties::GetControlInput(merge, edge.index());
601 } 650 }
602 } 651 }
603 BasicBlock* result = schedule_->block(use); 652 BasicBlock* result = schedule_->block(use);
604 if (result == NULL) return NULL; 653 if (result == NULL) return NULL;
605 Trace(" must dominate use #%d:%s in B%d\n", use->id(), 654 Trace(" must dominate use #%d:%s in B%d\n", use->id(),
606 use->op()->mnemonic(), result->id().ToInt()); 655 use->op()->mnemonic(), result->id().ToInt());
607 return result; 656 return result;
608 } 657 }
609 658
610 void ScheduleNode(BasicBlock* block, Node* node) { 659 void ScheduleNode(BasicBlock* block, Node* node) {
611 schedule_->PlanNode(block, node); 660 schedule_->PlanNode(block, node);
612 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); 661 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node);
613 662
614 // Reduce the use count of the node's inputs to potentially make them 663 // Reduce the use count of the node's inputs to potentially make them
615 // schedulable. 664 // schedulable.
616 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { 665 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
617 Scheduler::SchedulerData* data = scheduler_->GetData(*i); 666 scheduler_->DecrementUnscheduledUseCount(*i, i.edge().from());
618 DCHECK(data->unscheduled_count_ > 0);
619 --data->unscheduled_count_;
620 if (FLAG_trace_turbo_scheduler) {
621 Trace(" Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(),
622 (*i)->op()->mnemonic(), i.edge().from()->id(),
623 i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
624 if (data->unscheduled_count_ == 0) {
625 Trace(" newly eligible #%d:%s\n", (*i)->id(),
626 (*i)->op()->mnemonic());
627 }
628 }
629 }
630
631 for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
632 Node* use = *i;
633 if (use->opcode() == IrOpcode::kPhi ||
634 use->opcode() == IrOpcode::kEffectPhi) {
635 Node* control = NodeProperties::GetControlInput(use);
636 Scheduler::SchedulerData* data = scheduler_->GetData(control);
637 if (data->is_floating_control_ && !data->is_connected_control_) {
638 --data->unscheduled_count_;
639 if (FLAG_trace_turbo_scheduler) {
640 Trace(
641 " Use count for #%d:%s (additional dependency of #%d:%s)-- = "
642 "%d\n",
643 (*i)->id(), (*i)->op()->mnemonic(), node->id(),
644 node->op()->mnemonic(), data->unscheduled_count_);
645 if (data->unscheduled_count_ == 0) {
646 Trace(" newly eligible #%d:%s\n", (*i)->id(),
647 (*i)->op()->mnemonic());
648 }
649 }
650 }
651 }
652 } 667 }
653 } 668 }
654 669
655 Scheduler* scheduler_; 670 Scheduler* scheduler_;
656 Schedule* schedule_; 671 Schedule* schedule_;
657 }; 672 };
658 673
659 674
660 void Scheduler::ScheduleLate() { 675 void Scheduler::ScheduleLate() {
661 Trace("--- SCHEDULE LATE ------------------------------------------\n"); 676 Trace("--- SCHEDULE LATE ------------------------------------------\n");
(...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 #if DEBUG 1204 #if DEBUG
1190 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); 1205 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
1191 VerifySpecialRPO(num_loops, loops, final_order); 1206 VerifySpecialRPO(num_loops, loops, final_order);
1192 #endif 1207 #endif
1193 return final_order; 1208 return final_order;
1194 } 1209 }
1195 1210
1196 } // namespace compiler 1211 } // namespace compiler
1197 } // namespace internal 1212 } // namespace internal
1198 } // namespace v8 1213 } // 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