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 10 matching lines...) Expand all Loading... |
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(ZonePool* zone_pool, Zone* zone, Graph* graph, | 31 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) |
32 Schedule* schedule) | 32 : zone_(zone), |
33 : zone_pool_(zone_pool), | |
34 zone_(zone), | |
35 graph_(graph), | 33 graph_(graph), |
36 schedule_(schedule), | 34 schedule_(schedule), |
37 scheduled_nodes_(zone), | 35 scheduled_nodes_(zone), |
38 schedule_root_nodes_(zone), | 36 schedule_root_nodes_(zone), |
| 37 schedule_queue_(zone), |
39 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone), | 38 node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone), |
40 has_floating_control_(false) {} | 39 has_floating_control_(false) {} |
41 | 40 |
42 | 41 |
43 Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { | 42 Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { |
44 Schedule* schedule; | 43 Schedule* schedule; |
45 bool had_floating_control = false; | 44 bool had_floating_control = false; |
46 do { | 45 do { |
47 ZonePool::Scope zone_scope(zone_pool); | 46 ZonePool::Scope zone_scope(zone_pool); |
48 schedule = new (graph->zone()) | 47 schedule = new (graph->zone()) |
49 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); | 48 Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount())); |
50 Scheduler scheduler(zone_pool, zone_scope.zone(), graph, schedule); | 49 Scheduler scheduler(zone_scope.zone(), graph, schedule); |
51 | 50 |
52 scheduler.BuildCFG(); | 51 scheduler.BuildCFG(); |
53 Scheduler::ComputeSpecialRPO(zone_pool, schedule); | 52 Scheduler::ComputeSpecialRPO(zone_pool, schedule); |
54 scheduler.GenerateImmediateDominatorTree(); | 53 scheduler.GenerateImmediateDominatorTree(); |
55 | 54 |
56 scheduler.PrepareUses(); | 55 scheduler.PrepareUses(); |
57 scheduler.ScheduleEarly(); | 56 scheduler.ScheduleEarly(); |
58 scheduler.ScheduleLate(); | 57 scheduler.ScheduleLate(); |
59 | 58 |
60 had_floating_control = scheduler.ConnectFloatingControl(); | 59 had_floating_control = scheduler.ConnectFloatingControl(); |
61 } while (had_floating_control); | 60 } while (had_floating_control); |
62 | 61 |
63 return schedule; | 62 return schedule; |
64 } | 63 } |
65 | 64 |
66 | 65 |
67 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { | 66 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { |
68 SchedulerData def = {NULL, 0, false, false, kUnknown}; | 67 SchedulerData def = {NULL, 0, false, false, kUnknown}; |
69 return def; | 68 return def; |
70 } | 69 } |
71 | 70 |
72 | 71 |
| 72 Scheduler::SchedulerData* Scheduler::GetData(Node* node) { |
| 73 DCHECK(node->id() < static_cast<int>(node_data_.size())); |
| 74 return &node_data_[node->id()]; |
| 75 } |
| 76 |
| 77 |
73 Scheduler::Placement Scheduler::GetPlacement(Node* node) { | 78 Scheduler::Placement Scheduler::GetPlacement(Node* node) { |
74 SchedulerData* data = GetData(node); | 79 SchedulerData* data = GetData(node); |
75 if (data->placement_ == kUnknown) { // Compute placement, once, on demand. | 80 if (data->placement_ == kUnknown) { // Compute placement, once, on demand. |
76 switch (node->opcode()) { | 81 switch (node->opcode()) { |
77 case IrOpcode::kParameter: | 82 case IrOpcode::kParameter: |
78 // Parameters are always fixed to the start node. | 83 // Parameters are always fixed to the start node. |
79 data->placement_ = kFixed; | 84 data->placement_ = kFixed; |
80 break; | 85 break; |
81 case IrOpcode::kPhi: | 86 case IrOpcode::kPhi: |
82 case IrOpcode::kEffectPhi: { | 87 case IrOpcode::kEffectPhi: { |
83 // Phis and effect phis are fixed if their control inputs are. | 88 // Phis and effect phis are fixed if their control inputs are, whereas |
84 data->placement_ = GetPlacement(NodeProperties::GetControlInput(node)); | 89 // otherwise they are coupled to a floating control node. |
| 90 Placement p = GetPlacement(NodeProperties::GetControlInput(node)); |
| 91 data->placement_ = (p == kFixed ? kFixed : kCoupled); |
85 break; | 92 break; |
86 } | 93 } |
87 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: | 94 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: |
88 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) | 95 CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE) |
89 #undef DEFINE_FLOATING_CONTROL_CASE | 96 #undef DEFINE_FLOATING_CONTROL_CASE |
90 { | 97 { |
91 // Control nodes that were not control-reachable from end may float. | 98 // Control nodes that were not control-reachable from end may float. |
92 data->placement_ = kSchedulable; | 99 data->placement_ = kSchedulable; |
93 if (!data->is_connected_control_) { | 100 if (!data->is_connected_control_) { |
94 data->is_floating_control_ = true; | 101 data->is_floating_control_ = true; |
95 has_floating_control_ = true; | 102 has_floating_control_ = true; |
96 Trace("Floating control found: #%d:%s\n", node->id(), | 103 Trace("Floating control found: #%d:%s\n", node->id(), |
97 node->op()->mnemonic()); | 104 node->op()->mnemonic()); |
98 } | 105 } |
99 break; | 106 break; |
100 } | 107 } |
101 default: | 108 default: |
102 data->placement_ = kSchedulable; | 109 data->placement_ = kSchedulable; |
103 break; | 110 break; |
104 } | 111 } |
105 } | 112 } |
106 return data->placement_; | 113 return data->placement_; |
107 } | 114 } |
108 | 115 |
109 | 116 |
| 117 void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) { |
| 118 if (GetPlacement(node) == kCoupled) { |
| 119 // Use count for coupled nodes is summed up on their control. |
| 120 Node* control = NodeProperties::GetControlInput(node); |
| 121 return IncrementUnscheduledUseCount(control, from); |
| 122 } |
| 123 ++(GetData(node)->unscheduled_count_); |
| 124 if (FLAG_trace_turbo_scheduler) { |
| 125 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(), |
| 126 node->op()->mnemonic(), from->id(), from->op()->mnemonic(), |
| 127 GetData(node)->unscheduled_count_); |
| 128 } |
| 129 } |
| 130 |
| 131 |
| 132 void Scheduler::DecrementUnscheduledUseCount(Node* node, Node* from) { |
| 133 if (GetPlacement(node) == kCoupled) { |
| 134 // Use count for coupled nodes is summed up on their control. |
| 135 Node* control = NodeProperties::GetControlInput(node); |
| 136 return DecrementUnscheduledUseCount(control, from); |
| 137 } |
| 138 DCHECK(GetData(node)->unscheduled_count_ > 0); |
| 139 --(GetData(node)->unscheduled_count_); |
| 140 if (FLAG_trace_turbo_scheduler) { |
| 141 Trace(" Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(), |
| 142 node->op()->mnemonic(), from->id(), from->op()->mnemonic(), |
| 143 GetData(node)->unscheduled_count_); |
| 144 } |
| 145 if (GetData(node)->unscheduled_count_ == 0) { |
| 146 Trace(" newly eligible #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 147 schedule_queue_.push(node); |
| 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 |
110 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { | 160 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { |
111 while (b1 != b2) { | 161 while (b1 != b2) { |
112 int b1_rpo = GetRPONumber(b1); | 162 int b1_rpo = GetRPONumber(b1); |
113 int b2_rpo = GetRPONumber(b2); | 163 int b2_rpo = GetRPONumber(b2); |
114 DCHECK(b1_rpo != b2_rpo); | 164 DCHECK(b1_rpo != b2_rpo); |
115 if (b1_rpo < b2_rpo) { | 165 if (b1_rpo < b2_rpo) { |
116 b2 = b2->dominator(); | 166 b2 = b2->dominator(); |
117 } else { | 167 } else { |
118 b1 = b1->dominator(); | 168 b1 = b1->dominator(); |
119 } | 169 } |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 DCHECK(block != NULL); | 452 DCHECK(block != NULL); |
403 schedule_->AddNode(block, node); | 453 schedule_->AddNode(block, node); |
404 } | 454 } |
405 } | 455 } |
406 | 456 |
407 return GenericGraphVisit::CONTINUE; | 457 return GenericGraphVisit::CONTINUE; |
408 } | 458 } |
409 | 459 |
410 void PostEdge(Node* from, int index, Node* to) { | 460 void PostEdge(Node* from, int index, Node* to) { |
411 // If the edge is from an unscheduled node, then tally it in the use count | 461 // If the edge is from an unscheduled node, then tally it in the use count |
412 // for all of its inputs. The same criterion will be used in ScheduleLate | 462 // for all of its inputs. Also make sure that control edges from coupled |
| 463 // nodes are not counted. The same criterion will be used in ScheduleLate |
413 // for decrementing use counts. | 464 // for decrementing use counts. |
414 if (!schedule_->IsScheduled(from)) { | 465 if (!schedule_->IsScheduled(from) && !IsCoupledControlEdge(from, index)) { |
415 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from)); | 466 DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from)); |
416 ++(scheduler_->GetData(to)->unscheduled_count_); | 467 scheduler_->IncrementUnscheduledUseCount(to, from); |
417 Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(), | |
418 to->op()->mnemonic(), from->id(), from->op()->mnemonic(), | |
419 scheduler_->GetData(to)->unscheduled_count_); | |
420 if (OperatorProperties::IsBasicBlockBegin(to->op()) && | |
421 (from->opcode() == IrOpcode::kEffectPhi || | |
422 from->opcode() == IrOpcode::kPhi) && | |
423 scheduler_->GetData(to)->is_floating_control_ && | |
424 !scheduler_->GetData(to)->is_connected_control_) { | |
425 for (InputIter i = from->inputs().begin(); i != from->inputs().end(); | |
426 ++i) { | |
427 if (!NodeProperties::IsControlEdge(i.edge())) { | |
428 ++(scheduler_->GetData(*i)->unscheduled_count_); | |
429 Trace( | |
430 " Use count of #%d:%s (additional dependency of #%d:%s)++ = " | |
431 "%d\n", | |
432 (*i)->id(), (*i)->op()->mnemonic(), to->id(), | |
433 to->op()->mnemonic(), | |
434 scheduler_->GetData(*i)->unscheduled_count_); | |
435 } | |
436 } | |
437 } | |
438 } | 468 } |
439 } | 469 } |
440 | 470 |
| 471 bool IsCoupledControlEdge(Node* node, int index) { |
| 472 return scheduler_->GetPlacement(node) == Scheduler::kCoupled && |
| 473 NodeProperties::FirstControlIndex(node) == index; |
| 474 } |
| 475 |
441 private: | 476 private: |
442 Scheduler* scheduler_; | 477 Scheduler* scheduler_; |
443 Schedule* schedule_; | 478 Schedule* schedule_; |
444 }; | 479 }; |
445 | 480 |
446 | 481 |
447 void Scheduler::PrepareUses() { | 482 void Scheduler::PrepareUses() { |
448 Trace("--- PREPARE USES -------------------------------------------\n"); | 483 Trace("--- PREPARE USES -------------------------------------------\n"); |
449 | 484 |
450 // Count the uses of every node, it will be used to ensure that all of a | 485 // Count the uses of every node, it will be used to ensure that all of a |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 } | 566 } |
532 | 567 |
533 | 568 |
534 // ----------------------------------------------------------------------------- | 569 // ----------------------------------------------------------------------------- |
535 // Phase 4: Schedule nodes late. | 570 // Phase 4: Schedule nodes late. |
536 | 571 |
537 | 572 |
538 class ScheduleLateNodeVisitor { | 573 class ScheduleLateNodeVisitor { |
539 public: | 574 public: |
540 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) | 575 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) |
541 : scheduler_(scheduler), schedule_(scheduler_->schedule_), queue_(zone) {} | 576 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} |
542 | 577 |
543 // Run the schedule late algorithm on a set of fixed root nodes. | 578 // Run the schedule late algorithm on a set of fixed root nodes. |
544 void Run(NodeVector* roots) { | 579 void Run(NodeVector* roots) { |
545 for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) { | 580 for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) { |
546 ProcessQueue(*i); | 581 ProcessQueue(*i); |
547 } | 582 } |
548 } | 583 } |
549 | 584 |
550 private: | 585 private: |
551 void ProcessQueue(Node* root) { | 586 void ProcessQueue(Node* root) { |
| 587 ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_); |
552 for (InputIter i = root->inputs().begin(); i != root->inputs().end(); ++i) { | 588 for (InputIter i = root->inputs().begin(); i != root->inputs().end(); ++i) { |
553 if (scheduler_->GetData(*i)->unscheduled_count_ != 0) continue; | 589 Node* node = *i; |
554 queue_.push(*i); | 590 |
555 while (!queue_.empty()) { | 591 // Don't schedule coupled nodes on their own. |
556 VisitNode(queue_.front()); | 592 if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) { |
557 queue_.pop(); | 593 node = NodeProperties::GetControlInput(node); |
| 594 } |
| 595 |
| 596 // Test schedulability condition by looking at unscheduled use count. |
| 597 if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue; |
| 598 |
| 599 queue->push(node); |
| 600 while (!queue->empty()) { |
| 601 VisitNode(queue->front()); |
| 602 queue->pop(); |
558 } | 603 } |
559 } | 604 } |
560 } | 605 } |
561 | 606 |
562 // Visits one node from the queue of schedulable nodes and determines its | 607 // Visits one node from the queue of schedulable nodes and determines its |
563 // schedule late position. Also hoists nodes out of loops to find a more | 608 // schedule late position. Also hoists nodes out of loops to find a more |
564 // optimal scheduling position. | 609 // optimal scheduling position. |
565 void VisitNode(Node* node) { | 610 void VisitNode(Node* node) { |
566 DCHECK(scheduler_->GetData(node)->unscheduled_count_ == 0); | 611 DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_); |
567 | 612 |
568 // Don't schedule nodes that are already scheduled. | 613 // Don't schedule nodes that are already scheduled. |
569 if (schedule_->IsScheduled(node)) return; | 614 if (schedule_->IsScheduled(node)) return; |
570 | 615 DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node)); |
571 Scheduler::SchedulerData* data = scheduler_->GetData(node); | |
572 DCHECK_EQ(Scheduler::kSchedulable, data->placement_); | |
573 | 616 |
574 // Determine the dominating block for all of the uses of this node. It is | 617 // Determine the dominating block for all of the uses of this node. It is |
575 // the latest block that this node can be scheduled in. | 618 // the latest block that this node can be scheduled in. |
576 BasicBlock* block = NULL; | 619 BasicBlock* block = GetCommonDominatorOfUses(node); |
577 for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end(); | 620 DCHECK_NOT_NULL(block); |
578 ++i) { | |
579 BasicBlock* use_block = GetBlockForUse(i.edge()); | |
580 block = block == NULL ? use_block : use_block == NULL | |
581 ? block | |
582 : scheduler_->GetCommonDominator( | |
583 block, use_block); | |
584 } | |
585 DCHECK(block != NULL); | |
586 | 621 |
587 int min_rpo = data->minimum_block_->rpo_number(); | 622 int min_rpo = scheduler_->GetData(node)->minimum_block_->rpo_number(); |
588 Trace( | 623 Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n", |
589 "Schedule late conservative for #%d:%s is B%d at loop depth %d, " | 624 node->id(), node->op()->mnemonic(), block->id().ToInt(), |
590 "minimum_rpo = %d\n", | 625 block->loop_depth(), min_rpo); |
591 node->id(), node->op()->mnemonic(), block->id().ToInt(), | 626 |
592 block->loop_depth(), min_rpo); | |
593 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively | 627 // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
594 // into enclosing loop pre-headers until they would preceed their | 628 // into enclosing loop pre-headers until they would preceed their |
595 // ScheduleEarly position. | 629 // ScheduleEarly position. |
596 BasicBlock* hoist_block = block; | 630 BasicBlock* hoist_block = block; |
597 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { | 631 while (hoist_block != NULL && hoist_block->rpo_number() >= min_rpo) { |
598 if (hoist_block->loop_depth() < block->loop_depth()) { | 632 if (hoist_block->loop_depth() < block->loop_depth()) { |
599 block = hoist_block; | 633 block = hoist_block; |
600 Trace(" hoisting #%d:%s to block %d\n", node->id(), | 634 Trace(" hoisting #%d:%s to block %d\n", node->id(), |
601 node->op()->mnemonic(), block->id().ToInt()); | 635 node->op()->mnemonic(), block->id().ToInt()); |
602 } | 636 } |
603 // Try to hoist to the pre-header of the loop header. | 637 // Try to hoist to the pre-header of the loop header. |
604 hoist_block = hoist_block->loop_header(); | 638 hoist_block = hoist_block->loop_header(); |
605 if (hoist_block != NULL) { | 639 if (hoist_block != NULL) { |
606 BasicBlock* pre_header = hoist_block->dominator(); | 640 BasicBlock* pre_header = hoist_block->dominator(); |
607 DCHECK(pre_header == NULL || | 641 DCHECK(pre_header == NULL || |
608 *hoist_block->predecessors_begin() == pre_header); | 642 *hoist_block->predecessors_begin() == pre_header); |
609 Trace( | 643 Trace( |
610 " hoist to pre-header B%d of loop header B%d, depth would be %d\n", | 644 " hoist to pre-header B%d of loop header B%d, depth would be %d\n", |
611 pre_header->id().ToInt(), hoist_block->id().ToInt(), | 645 pre_header->id().ToInt(), hoist_block->id().ToInt(), |
612 pre_header->loop_depth()); | 646 pre_header->loop_depth()); |
613 hoist_block = pre_header; | 647 hoist_block = pre_header; |
614 } | 648 } |
615 } | 649 } |
616 | 650 |
617 ScheduleNode(block, node); | 651 ScheduleNode(block, node); |
618 } | 652 } |
619 | 653 |
| 654 private: |
| 655 BasicBlock* GetCommonDominatorOfUses(Node* node) { |
| 656 BasicBlock* block = NULL; |
| 657 Node::Uses uses = node->uses(); |
| 658 for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) { |
| 659 BasicBlock* use_block = GetBlockForUse(i.edge()); |
| 660 block = block == NULL ? use_block : use_block == NULL |
| 661 ? block |
| 662 : scheduler_->GetCommonDominator( |
| 663 block, use_block); |
| 664 } |
| 665 return block; |
| 666 } |
| 667 |
620 BasicBlock* GetBlockForUse(Node::Edge edge) { | 668 BasicBlock* GetBlockForUse(Node::Edge edge) { |
621 Node* use = edge.from(); | 669 Node* use = edge.from(); |
622 IrOpcode::Value opcode = use->opcode(); | 670 IrOpcode::Value opcode = use->opcode(); |
623 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 671 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
| 672 // If the use is from a coupled (i.e. floating) phi, compute the common |
| 673 // dominator of its uses. This will not recurse more than one level. |
| 674 if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) { |
| 675 Trace(" inspecting uses of coupled phi #%d:%s\n", use->id(), |
| 676 use->op()->mnemonic()); |
| 677 DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use)); |
| 678 return GetCommonDominatorOfUses(use); |
| 679 } |
624 // If the use is from a fixed (i.e. non-floating) phi, use the block | 680 // If the use is from a fixed (i.e. non-floating) phi, use the block |
625 // of the corresponding control input to the merge. | 681 // of the corresponding control input to the merge. |
626 int index = edge.index(); | |
627 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { | 682 if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { |
628 Trace(" input@%d into a fixed phi #%d:%s\n", index, use->id(), | 683 Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(), |
629 use->op()->mnemonic()); | 684 use->op()->mnemonic()); |
630 Node* merge = NodeProperties::GetControlInput(use, 0); | 685 Node* merge = NodeProperties::GetControlInput(use, 0); |
631 opcode = merge->opcode(); | 686 opcode = merge->opcode(); |
632 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); | 687 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); |
633 use = NodeProperties::GetControlInput(merge, index); | 688 use = NodeProperties::GetControlInput(merge, edge.index()); |
634 } | 689 } |
635 } | 690 } |
636 BasicBlock* result = schedule_->block(use); | 691 BasicBlock* result = schedule_->block(use); |
637 if (result == NULL) return NULL; | 692 if (result == NULL) return NULL; |
638 Trace(" must dominate use #%d:%s in B%d\n", use->id(), | 693 Trace(" must dominate use #%d:%s in B%d\n", use->id(), |
639 use->op()->mnemonic(), result->id().ToInt()); | 694 use->op()->mnemonic(), result->id().ToInt()); |
640 return result; | 695 return result; |
641 } | 696 } |
642 | 697 |
643 void ScheduleNode(BasicBlock* block, Node* node) { | 698 void ScheduleNode(BasicBlock* block, Node* node) { |
644 schedule_->PlanNode(block, node); | 699 schedule_->PlanNode(block, node); |
645 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); | 700 scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node); |
646 | 701 |
647 // Reduce the use count of the node's inputs to potentially make them | 702 // Reduce the use count of the node's inputs to potentially make them |
648 // schedulable. If all the uses of a node have been scheduled, then the node | 703 // schedulable. If all the uses of a node have been scheduled, then the node |
649 // itself can be scheduled. | 704 // itself can be scheduled. |
650 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { | 705 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { |
651 Scheduler::SchedulerData* data = scheduler_->GetData(*i); | 706 scheduler_->DecrementUnscheduledUseCount(*i, i.edge().from()); |
652 DCHECK(data->unscheduled_count_ > 0); | |
653 --data->unscheduled_count_; | |
654 if (FLAG_trace_turbo_scheduler) { | |
655 Trace(" Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(), | |
656 (*i)->op()->mnemonic(), i.edge().from()->id(), | |
657 i.edge().from()->op()->mnemonic(), data->unscheduled_count_); | |
658 } | |
659 if (data->unscheduled_count_ == 0) { | |
660 Trace(" newly eligible #%d:%s\n", (*i)->id(), (*i)->op()->mnemonic()); | |
661 queue_.push(*i); | |
662 } | |
663 } | |
664 | |
665 for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) { | |
666 Node* use = *i; | |
667 if (use->opcode() == IrOpcode::kPhi || | |
668 use->opcode() == IrOpcode::kEffectPhi) { | |
669 Node* control = NodeProperties::GetControlInput(use); | |
670 Scheduler::SchedulerData* data = scheduler_->GetData(control); | |
671 if (data->is_floating_control_ && !data->is_connected_control_) { | |
672 --data->unscheduled_count_; | |
673 if (FLAG_trace_turbo_scheduler) { | |
674 Trace( | |
675 " Use count for #%d:%s (additional dependency of #%d:%s)-- = " | |
676 "%d\n", | |
677 (*i)->id(), (*i)->op()->mnemonic(), node->id(), | |
678 node->op()->mnemonic(), data->unscheduled_count_); | |
679 } | |
680 if (data->unscheduled_count_ == 0) { | |
681 Trace(" newly eligible #%d:%s\n", (*i)->id(), | |
682 (*i)->op()->mnemonic()); | |
683 queue_.push(*i); | |
684 } | |
685 } | |
686 } | |
687 } | 707 } |
688 } | 708 } |
689 | 709 |
690 Scheduler* scheduler_; | 710 Scheduler* scheduler_; |
691 Schedule* schedule_; | 711 Schedule* schedule_; |
692 ZoneQueue<Node*> queue_; | |
693 }; | 712 }; |
694 | 713 |
695 | 714 |
696 void Scheduler::ScheduleLate() { | 715 void Scheduler::ScheduleLate() { |
697 Trace("--- SCHEDULE LATE ------------------------------------------\n"); | 716 Trace("--- SCHEDULE LATE ------------------------------------------\n"); |
698 if (FLAG_trace_turbo_scheduler) { | 717 if (FLAG_trace_turbo_scheduler) { |
699 Trace("roots: "); | 718 Trace("roots: "); |
700 for (NodeVectorIter i = schedule_root_nodes_.begin(); | 719 for (NodeVectorIter i = schedule_root_nodes_.begin(); |
701 i != schedule_root_nodes_.end(); ++i) { | 720 i != schedule_root_nodes_.end(); ++i) { |
702 Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic()); | 721 Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic()); |
703 } | 722 } |
704 Trace("\n"); | 723 Trace("\n"); |
705 } | 724 } |
706 | 725 |
707 // Schedule: Places nodes in dominator block of all their uses. | 726 // Schedule: Places nodes in dominator block of all their uses. |
708 { | 727 ScheduleLateNodeVisitor schedule_late_visitor(zone_, this); |
709 ZonePool::Scope zone_scope(zone_pool_); | 728 schedule_late_visitor.Run(&schedule_root_nodes_); |
710 ScheduleLateNodeVisitor schedule_late_visitor(zone_scope.zone(), this); | |
711 schedule_late_visitor.Run(&schedule_root_nodes_); | |
712 } | |
713 | 729 |
714 // Add collected nodes for basic blocks to their blocks in the right order. | 730 // Add collected nodes for basic blocks to their blocks in the right order. |
715 int block_num = 0; | 731 int block_num = 0; |
716 for (NodeVectorVectorIter i = scheduled_nodes_.begin(); | 732 for (NodeVectorVectorIter i = scheduled_nodes_.begin(); |
717 i != scheduled_nodes_.end(); ++i) { | 733 i != scheduled_nodes_.end(); ++i) { |
718 for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) { | 734 for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) { |
719 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); | 735 schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j); |
720 } | 736 } |
721 block_num++; | 737 block_num++; |
722 } | 738 } |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1234 #if DEBUG | 1250 #if DEBUG |
1235 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); | 1251 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); |
1236 VerifySpecialRPO(num_loops, loops, final_order); | 1252 VerifySpecialRPO(num_loops, loops, final_order); |
1237 #endif | 1253 #endif |
1238 return final_order; | 1254 return final_order; |
1239 } | 1255 } |
1240 | 1256 |
1241 } // namespace compiler | 1257 } // namespace compiler |
1242 } // namespace internal | 1258 } // namespace internal |
1243 } // namespace v8 | 1259 } // namespace v8 |
OLD | NEW |