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

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

Issue 685773002: Switch scheduler to iterative floating control placement. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments by Jaro. Created 6 years, 1 month 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 17 matching lines...) Expand all
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
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
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
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
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
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
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
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
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
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
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