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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 scheduler.ScheduleLate(); | 57 scheduler.ScheduleLate(); |
58 | 58 |
59 had_floating_control = scheduler.ConnectFloatingControl(); | 59 had_floating_control = scheduler.ConnectFloatingControl(); |
60 } while (had_floating_control); | 60 } while (had_floating_control); |
61 | 61 |
62 return schedule; | 62 return schedule; |
63 } | 63 } |
64 | 64 |
65 | 65 |
66 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { | 66 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { |
67 SchedulerData def = {NULL, 0, false, false, kUnknown}; | 67 SchedulerData def = {schedule_->start(), 0, false, false, kUnknown}; |
68 return def; | 68 return def; |
69 } | 69 } |
70 | 70 |
71 | 71 |
72 Scheduler::SchedulerData* Scheduler::GetData(Node* node) { | 72 Scheduler::SchedulerData* Scheduler::GetData(Node* node) { |
73 DCHECK(node->id() < static_cast<int>(node_data_.size())); | 73 DCHECK(node->id() < static_cast<int>(node_data_.size())); |
74 return &node_data_[node->id()]; | 74 return &node_data_[node->id()]; |
75 } | 75 } |
76 | 76 |
77 | 77 |
(...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 // node's uses are scheduled before the node itself. | 945 // node's uses are scheduled before the node itself. |
946 PrepareUsesVisitor prepare_uses(this); | 946 PrepareUsesVisitor prepare_uses(this); |
947 graph_->VisitNodeInputsFromEnd(&prepare_uses); | 947 graph_->VisitNodeInputsFromEnd(&prepare_uses); |
948 } | 948 } |
949 | 949 |
950 | 950 |
951 // ----------------------------------------------------------------------------- | 951 // ----------------------------------------------------------------------------- |
952 // Phase 4: Schedule nodes early. | 952 // Phase 4: Schedule nodes early. |
953 | 953 |
954 | 954 |
955 class ScheduleEarlyNodeVisitor : public NullNodeVisitor { | 955 class ScheduleEarlyNodeVisitor { |
956 public: | 956 public: |
957 explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler) | 957 ScheduleEarlyNodeVisitor(Zone* zone, Scheduler* scheduler) |
958 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} | 958 : scheduler_(scheduler), schedule_(scheduler->schedule_), queue_(zone) {} |
959 | 959 |
960 GenericGraphVisit::Control Pre(Node* node) { | 960 // Run the schedule early algorithm on a set of fixed root nodes. |
961 Scheduler::SchedulerData* data = scheduler_->GetData(node); | 961 void Run(NodeVector* roots) { |
962 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) { | 962 for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) { |
963 // Fixed nodes already know their schedule early position. | 963 queue_.push(*i); |
964 if (data->minimum_block_ == NULL) { | 964 while (!queue_.empty()) { |
965 data->minimum_block_ = schedule_->block(node); | 965 VisitNode(queue_.front()); |
966 Trace("Preschedule #%d:%s minimum_rpo = %d (fixed)\n", node->id(), | 966 queue_.pop(); |
967 node->op()->mnemonic(), data->minimum_block_->rpo_number()); | |
968 } | |
969 } else { | |
970 // For unfixed nodes the minimum RPO is the max of all of the inputs. | |
971 if (data->minimum_block_ == NULL) { | |
972 data->minimum_block_ = ComputeMaximumInputRPO(node); | |
973 if (data->minimum_block_ == NULL) return GenericGraphVisit::REENTER; | |
974 Trace("Preschedule #%d:%s minimum_rpo = %d\n", node->id(), | |
975 node->op()->mnemonic(), data->minimum_block_->rpo_number()); | |
976 } | 967 } |
977 } | 968 } |
978 DCHECK_NE(data->minimum_block_, NULL); | |
979 return GenericGraphVisit::CONTINUE; | |
980 } | |
981 | |
982 GenericGraphVisit::Control Post(Node* node) { | |
983 Scheduler::SchedulerData* data = scheduler_->GetData(node); | |
984 if (scheduler_->GetPlacement(node) != Scheduler::kFixed) { | |
985 // For unfixed nodes the minimum RPO is the max of all of the inputs. | |
986 if (data->minimum_block_ == NULL) { | |
987 data->minimum_block_ = ComputeMaximumInputRPO(node); | |
988 Trace("Postschedule #%d:%s minimum_rpo = %d\n", node->id(), | |
989 node->op()->mnemonic(), data->minimum_block_->rpo_number()); | |
990 } | |
991 } | |
992 DCHECK_NE(data->minimum_block_, NULL); | |
993 return GenericGraphVisit::CONTINUE; | |
994 } | |
995 | |
996 // Computes the maximum of the minimum RPOs for all inputs. If the maximum | |
997 // cannot be determined (i.e. minimum RPO for at least one input is {NULL}), | |
998 // then {NULL} is returned. | |
999 BasicBlock* ComputeMaximumInputRPO(Node* node) { | |
1000 BasicBlock* max_block = schedule_->start(); | |
1001 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { | |
1002 DCHECK_NE(node, *i); // Loops only exist for fixed nodes. | |
1003 BasicBlock* block = scheduler_->GetData(*i)->minimum_block_; | |
1004 if (block == NULL) return NULL; | |
1005 if (block->rpo_number() > max_block->rpo_number()) { | |
1006 max_block = block; | |
1007 } | |
1008 } | |
1009 return max_block; | |
1010 } | 969 } |
1011 | 970 |
1012 private: | 971 private: |
| 972 // Visits one node from the queue and propagates its current schedule early |
| 973 // position to all uses. This in turn might push more nodes onto the queue. |
| 974 void VisitNode(Node* node) { |
| 975 Scheduler::SchedulerData* data = scheduler_->GetData(node); |
| 976 |
| 977 // Fixed nodes already know their schedule early position. |
| 978 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) { |
| 979 DCHECK_EQ(schedule_->start(), data->minimum_block_); |
| 980 data->minimum_block_ = schedule_->block(node); |
| 981 Trace("Fixing #%d:%s minimum_rpo = %d\n", node->id(), |
| 982 node->op()->mnemonic(), data->minimum_block_->rpo_number()); |
| 983 } |
| 984 |
| 985 // No need to propagate unconstrained schedule early positions. |
| 986 if (data->minimum_block_ == schedule_->start()) return; |
| 987 |
| 988 // Propagate schedule early position. |
| 989 DCHECK(data->minimum_block_ != NULL); |
| 990 Node::Uses uses = node->uses(); |
| 991 for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) { |
| 992 PropagateMinimumRPOToNode(data->minimum_block_, *i); |
| 993 } |
| 994 } |
| 995 |
| 996 // Propagates {block} as another minimum RPO placement into the given {node}. |
| 997 // This has the net effect of computing the maximum of the minimum RPOs for |
| 998 // all inputs to {node} when the queue has been fully processed. |
| 999 void PropagateMinimumRPOToNode(BasicBlock* block, Node* node) { |
| 1000 Scheduler::SchedulerData* data = scheduler_->GetData(node); |
| 1001 |
| 1002 // No need to propagate to fixed node, it's guaranteed to be a root. |
| 1003 if (scheduler_->GetPlacement(node) == Scheduler::kFixed) return; |
| 1004 |
| 1005 // Propagate new position if it is larger than the current. |
| 1006 if (block->rpo_number() > data->minimum_block_->rpo_number()) { |
| 1007 data->minimum_block_ = block; |
| 1008 queue_.push(node); |
| 1009 Trace("Propagating #%d:%s minimum_rpo = %d\n", node->id(), |
| 1010 node->op()->mnemonic(), data->minimum_block_->rpo_number()); |
| 1011 } |
| 1012 } |
| 1013 |
1013 Scheduler* scheduler_; | 1014 Scheduler* scheduler_; |
1014 Schedule* schedule_; | 1015 Schedule* schedule_; |
| 1016 ZoneQueue<Node*> queue_; |
1015 }; | 1017 }; |
1016 | 1018 |
1017 | 1019 |
1018 void Scheduler::ScheduleEarly() { | 1020 void Scheduler::ScheduleEarly() { |
1019 Trace("--- SCHEDULE EARLY -----------------------------------------\n"); | 1021 Trace("--- SCHEDULE EARLY -----------------------------------------\n"); |
| 1022 if (FLAG_trace_turbo_scheduler) { |
| 1023 Trace("roots: "); |
| 1024 for (NodeVectorIter i = schedule_root_nodes_.begin(); |
| 1025 i != schedule_root_nodes_.end(); ++i) { |
| 1026 Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic()); |
| 1027 } |
| 1028 Trace("\n"); |
| 1029 } |
1020 | 1030 |
1021 // Compute the minimum RPO for each node thereby determining the earliest | 1031 // Compute the minimum RPO for each node thereby determining the earliest |
1022 // position each node could be placed within a valid schedule. | 1032 // position each node could be placed within a valid schedule. |
1023 ScheduleEarlyNodeVisitor visitor(this); | 1033 ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this); |
1024 graph_->VisitNodeInputsFromEnd(&visitor); | 1034 schedule_early_visitor.Run(&schedule_root_nodes_); |
1025 } | 1035 } |
1026 | 1036 |
1027 | 1037 |
1028 // ----------------------------------------------------------------------------- | 1038 // ----------------------------------------------------------------------------- |
1029 // Phase 5: Schedule nodes late. | 1039 // Phase 5: Schedule nodes late. |
1030 | 1040 |
1031 | 1041 |
1032 class ScheduleLateNodeVisitor { | 1042 class ScheduleLateNodeVisitor { |
1033 public: | 1043 public: |
1034 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) | 1044 ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler) |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 Trace(" hoisting #%d:%s to block %d\n", node->id(), | 1101 Trace(" hoisting #%d:%s to block %d\n", node->id(), |
1092 node->op()->mnemonic(), hoist_block->id().ToInt()); | 1102 node->op()->mnemonic(), hoist_block->id().ToInt()); |
1093 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); | 1103 DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); |
1094 block = hoist_block; | 1104 block = hoist_block; |
1095 hoist_block = GetPreHeader(hoist_block); | 1105 hoist_block = GetPreHeader(hoist_block); |
1096 } | 1106 } |
1097 | 1107 |
1098 ScheduleNode(block, node); | 1108 ScheduleNode(block, node); |
1099 } | 1109 } |
1100 | 1110 |
1101 private: | |
1102 BasicBlock* GetPreHeader(BasicBlock* block) { | 1111 BasicBlock* GetPreHeader(BasicBlock* block) { |
1103 if (block->IsLoopHeader()) { | 1112 if (block->IsLoopHeader()) { |
1104 return block->dominator(); | 1113 return block->dominator(); |
1105 } else if (block->loop_header() != NULL) { | 1114 } else if (block->loop_header() != NULL) { |
1106 return block->loop_header()->dominator(); | 1115 return block->loop_header()->dominator(); |
1107 } else { | 1116 } else { |
1108 return NULL; | 1117 return NULL; |
1109 } | 1118 } |
1110 } | 1119 } |
1111 | 1120 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1288 start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start); | 1297 start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start); |
1289 | 1298 |
1290 Trace(" Connecting floating control start %d:%s to %d:%s\n", start->id(), | 1299 Trace(" Connecting floating control start %d:%s to %d:%s\n", start->id(), |
1291 start->op()->mnemonic(), block_start->id(), | 1300 start->op()->mnemonic(), block_start->id(), |
1292 block_start->op()->mnemonic()); | 1301 block_start->op()->mnemonic()); |
1293 } | 1302 } |
1294 | 1303 |
1295 } // namespace compiler | 1304 } // namespace compiler |
1296 } // namespace internal | 1305 } // namespace internal |
1297 } // namespace v8 | 1306 } // namespace v8 |
OLD | NEW |