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 "src/compiler/scheduler.h" | 5 #include "src/compiler/scheduler.h" |
6 | 6 |
7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
8 #include "src/compiler/graph-inl.h" | 8 #include "src/compiler/graph-inl.h" |
9 #include "src/compiler/node.h" | 9 #include "src/compiler/node.h" |
10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 scheduler.GenerateImmediateDominatorTree(); | 46 scheduler.GenerateImmediateDominatorTree(); |
47 | 47 |
48 scheduler.PrepareUses(); | 48 scheduler.PrepareUses(); |
49 scheduler.ScheduleEarly(); | 49 scheduler.ScheduleEarly(); |
50 scheduler.ScheduleLate(); | 50 scheduler.ScheduleLate(); |
51 | 51 |
52 return schedule; | 52 return schedule; |
53 } | 53 } |
54 | 54 |
55 | 55 |
| 56 bool Scheduler::IsBasicBlockBegin(Node* node) { |
| 57 return OperatorProperties::IsBasicBlockBegin(node->op()); |
| 58 } |
| 59 |
| 60 |
| 61 bool Scheduler::CanBeScheduled(Node* node) { return true; } |
| 62 |
| 63 |
| 64 bool Scheduler::HasFixedSchedulePosition(Node* node) { |
| 65 IrOpcode::Value opcode = node->opcode(); |
| 66 return (IrOpcode::IsControlOpcode(opcode)) || |
| 67 opcode == IrOpcode::kParameter || opcode == IrOpcode::kEffectPhi || |
| 68 opcode == IrOpcode::kPhi; |
| 69 } |
| 70 |
| 71 |
| 72 bool Scheduler::IsScheduleRoot(Node* node) { |
| 73 IrOpcode::Value opcode = node->opcode(); |
| 74 return opcode == IrOpcode::kEnd || opcode == IrOpcode::kEffectPhi || |
| 75 opcode == IrOpcode::kPhi; |
| 76 } |
| 77 |
| 78 |
56 class CreateBlockVisitor : public NullNodeVisitor { | 79 class CreateBlockVisitor : public NullNodeVisitor { |
57 public: | 80 public: |
58 explicit CreateBlockVisitor(Scheduler* scheduler) : scheduler_(scheduler) {} | 81 explicit CreateBlockVisitor(Scheduler* scheduler) : scheduler_(scheduler) {} |
59 | 82 |
60 GenericGraphVisit::Control Post(Node* node) { | 83 GenericGraphVisit::Control Post(Node* node) { |
61 Schedule* schedule = scheduler_->schedule_; | 84 Schedule* schedule = scheduler_->schedule_; |
62 switch (node->opcode()) { | 85 switch (node->opcode()) { |
63 case IrOpcode::kIfTrue: | 86 case IrOpcode::kIfTrue: |
64 case IrOpcode::kIfFalse: | 87 case IrOpcode::kIfFalse: |
65 case IrOpcode::kContinuation: | 88 case IrOpcode::kContinuation: |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 | 166 |
144 void Scheduler::AddPredecessorsForLoopsAndMerges() { | 167 void Scheduler::AddPredecessorsForLoopsAndMerges() { |
145 for (NodeVectorIter i = loops_and_merges_.begin(); | 168 for (NodeVectorIter i = loops_and_merges_.begin(); |
146 i != loops_and_merges_.end(); ++i) { | 169 i != loops_and_merges_.end(); ++i) { |
147 Node* merge_or_loop = *i; | 170 Node* merge_or_loop = *i; |
148 BasicBlock* block = schedule_->block(merge_or_loop); | 171 BasicBlock* block = schedule_->block(merge_or_loop); |
149 DCHECK(block != NULL); | 172 DCHECK(block != NULL); |
150 // For all of the merge's control inputs, add a goto at the end to the | 173 // For all of the merge's control inputs, add a goto at the end to the |
151 // merge's basic block. | 174 // merge's basic block. |
152 for (InputIter j = (*i)->inputs().begin(); j != (*i)->inputs().end(); ++j) { | 175 for (InputIter j = (*i)->inputs().begin(); j != (*i)->inputs().end(); ++j) { |
153 if (OperatorProperties::IsBasicBlockBegin((*i)->op())) { | 176 if (IsBasicBlockBegin((*i))) { |
154 BasicBlock* predecessor_block = schedule_->block(*j); | 177 BasicBlock* predecessor_block = schedule_->block(*j); |
155 if ((*j)->opcode() != IrOpcode::kReturn && | 178 if ((*j)->opcode() != IrOpcode::kReturn && |
156 (*j)->opcode() != IrOpcode::kDeoptimize) { | 179 (*j)->opcode() != IrOpcode::kDeoptimize) { |
157 DCHECK(predecessor_block != NULL); | 180 DCHECK(predecessor_block != NULL); |
158 if (FLAG_trace_turbo_scheduler) { | 181 if (FLAG_trace_turbo_scheduler) { |
159 IrOpcode::Value opcode = (*i)->opcode(); | 182 IrOpcode::Value opcode = (*i)->opcode(); |
160 PrintF("node %d (%s) in block %d -> block %d\n", (*i)->id(), | 183 PrintF("node %d (%s) in block %d -> block %d\n", (*i)->id(), |
161 IrOpcode::Mnemonic(opcode), predecessor_block->id(), | 184 IrOpcode::Mnemonic(opcode), predecessor_block->id(), |
162 block->id()); | 185 block->id()); |
163 } | 186 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 } | 384 } |
362 } | 385 } |
363 return GenericGraphVisit::CONTINUE; | 386 return GenericGraphVisit::CONTINUE; |
364 } | 387 } |
365 | 388 |
366 GenericGraphVisit::Control Post(Node* node) { | 389 GenericGraphVisit::Control Post(Node* node) { |
367 int id = node->id(); | 390 int id = node->id(); |
368 int max_rpo = 0; | 391 int max_rpo = 0; |
369 // Otherwise, the minimum rpo for the node is the max of all of the inputs. | 392 // Otherwise, the minimum rpo for the node is the max of all of the inputs. |
370 if (!IsFixedNode(node)) { | 393 if (!IsFixedNode(node)) { |
371 DCHECK(!OperatorProperties::IsBasicBlockBegin(node->op())); | 394 DCHECK(!scheduler_->IsBasicBlockBegin(node)); |
372 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); | 395 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); |
373 ++i) { | 396 ++i) { |
374 int control_rpo = scheduler_->schedule_early_rpo_index_[(*i)->id()]; | 397 int control_rpo = scheduler_->schedule_early_rpo_index_[(*i)->id()]; |
375 if (control_rpo > max_rpo) { | 398 if (control_rpo > max_rpo) { |
376 max_rpo = control_rpo; | 399 max_rpo = control_rpo; |
377 } | 400 } |
378 } | 401 } |
379 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { | 402 if (scheduler_->schedule_early_rpo_index_[id] != max_rpo) { |
380 has_changed_rpo_constraints_ = true; | 403 has_changed_rpo_constraints_ = true; |
381 } | 404 } |
382 scheduler_->schedule_early_rpo_index_[id] = max_rpo; | 405 scheduler_->schedule_early_rpo_index_[id] = max_rpo; |
383 if (FLAG_trace_turbo_scheduler) { | 406 if (FLAG_trace_turbo_scheduler) { |
384 PrintF("Node %d post-scheduled early at rpo limit %d\n", id, max_rpo); | 407 PrintF("Node %d post-scheduled early at rpo limit %d\n", id, max_rpo); |
385 } | 408 } |
386 } | 409 } |
387 return GenericGraphVisit::CONTINUE; | 410 return GenericGraphVisit::CONTINUE; |
388 } | 411 } |
389 | 412 |
390 static bool IsFixedNode(Node* node) { | 413 bool IsFixedNode(Node* node) { |
391 return OperatorProperties::HasFixedSchedulePosition(node->op()) || | 414 return scheduler_->HasFixedSchedulePosition(node) || |
392 !OperatorProperties::CanBeScheduled(node->op()); | 415 !scheduler_->CanBeScheduled(node); |
393 } | 416 } |
394 | 417 |
395 // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be | 418 // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be |
396 // rewritten to use a pre-order traversal from the start instead. | 419 // rewritten to use a pre-order traversal from the start instead. |
397 bool has_changed_rpo_constraints_; | 420 bool has_changed_rpo_constraints_; |
398 | 421 |
399 private: | 422 private: |
400 Scheduler* scheduler_; | 423 Scheduler* scheduler_; |
401 Schedule* schedule_; | 424 Schedule* schedule_; |
402 }; | 425 }; |
(...skipping 21 matching lines...) Expand all Loading... |
424 class PrepareUsesVisitor : public NullNodeVisitor { | 447 class PrepareUsesVisitor : public NullNodeVisitor { |
425 public: | 448 public: |
426 explicit PrepareUsesVisitor(Scheduler* scheduler) | 449 explicit PrepareUsesVisitor(Scheduler* scheduler) |
427 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} | 450 : scheduler_(scheduler), schedule_(scheduler->schedule_) {} |
428 | 451 |
429 GenericGraphVisit::Control Pre(Node* node) { | 452 GenericGraphVisit::Control Pre(Node* node) { |
430 // Some nodes must be scheduled explicitly to ensure they are in exactly the | 453 // Some nodes must be scheduled explicitly to ensure they are in exactly the |
431 // right place; it's a convenient place during the preparation of use counts | 454 // right place; it's a convenient place during the preparation of use counts |
432 // to schedule them. | 455 // to schedule them. |
433 if (!schedule_->IsScheduled(node) && | 456 if (!schedule_->IsScheduled(node) && |
434 OperatorProperties::HasFixedSchedulePosition(node->op())) { | 457 scheduler_->HasFixedSchedulePosition(node)) { |
435 if (FLAG_trace_turbo_scheduler) { | 458 if (FLAG_trace_turbo_scheduler) { |
436 PrintF("Fixed position node %d is unscheduled, scheduling now\n", | 459 PrintF("Fixed position node %d is unscheduled, scheduling now\n", |
437 node->id()); | 460 node->id()); |
438 } | 461 } |
439 IrOpcode::Value opcode = node->opcode(); | 462 IrOpcode::Value opcode = node->opcode(); |
440 BasicBlock* block = | 463 BasicBlock* block = |
441 opcode == IrOpcode::kParameter | 464 opcode == IrOpcode::kParameter |
442 ? schedule_->entry() | 465 ? schedule_->entry() |
443 : schedule_->block(NodeProperties::GetControlInput(node)); | 466 : schedule_->block(NodeProperties::GetControlInput(node)); |
444 DCHECK(block != NULL); | 467 DCHECK(block != NULL); |
445 schedule_->AddNode(block, node); | 468 schedule_->AddNode(block, node); |
446 } | 469 } |
447 | 470 |
448 if (OperatorProperties::IsScheduleRoot(node->op())) { | 471 if (scheduler_->IsScheduleRoot(node)) { |
449 scheduler_->schedule_root_nodes_.push_back(node); | 472 scheduler_->schedule_root_nodes_.push_back(node); |
450 } | 473 } |
451 | 474 |
452 return GenericGraphVisit::CONTINUE; | 475 return GenericGraphVisit::CONTINUE; |
453 } | 476 } |
454 | 477 |
455 void PostEdge(Node* from, int index, Node* to) { | 478 void PostEdge(Node* from, int index, Node* to) { |
456 // If the edge is from an unscheduled node, then tally it in the use count | 479 // If the edge is from an unscheduled node, then tally it in the use count |
457 // for all of its inputs. The same criterion will be used in ScheduleLate | 480 // for all of its inputs. The same criterion will be used in ScheduleLate |
458 // for decrementing use counts. | 481 // for decrementing use counts. |
459 if (!schedule_->IsScheduled(from) && | 482 if (!schedule_->IsScheduled(from) && scheduler_->CanBeScheduled(from)) { |
460 OperatorProperties::CanBeScheduled(from->op())) { | 483 DCHECK(!scheduler_->HasFixedSchedulePosition(from)); |
461 DCHECK(!OperatorProperties::HasFixedSchedulePosition(from->op())); | |
462 ++scheduler_->unscheduled_uses_[to->id()]; | 484 ++scheduler_->unscheduled_uses_[to->id()]; |
463 if (FLAG_trace_turbo_scheduler) { | 485 if (FLAG_trace_turbo_scheduler) { |
464 PrintF("Incrementing uses of node %d from %d to %d\n", to->id(), | 486 PrintF("Incrementing uses of node %d from %d to %d\n", to->id(), |
465 from->id(), scheduler_->unscheduled_uses_[to->id()]); | 487 from->id(), scheduler_->unscheduled_uses_[to->id()]); |
466 } | 488 } |
467 } | 489 } |
468 } | 490 } |
469 | 491 |
470 private: | 492 private: |
471 Scheduler* scheduler_; | 493 Scheduler* scheduler_; |
(...skipping 12 matching lines...) Expand all Loading... |
484 } | 506 } |
485 | 507 |
486 | 508 |
487 class ScheduleLateNodeVisitor : public NullNodeVisitor { | 509 class ScheduleLateNodeVisitor : public NullNodeVisitor { |
488 public: | 510 public: |
489 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) | 511 explicit ScheduleLateNodeVisitor(Scheduler* scheduler) |
490 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} | 512 : scheduler_(scheduler), schedule_(scheduler_->schedule_) {} |
491 | 513 |
492 GenericGraphVisit::Control Pre(Node* node) { | 514 GenericGraphVisit::Control Pre(Node* node) { |
493 // Don't schedule nodes that cannot be scheduled or are already scheduled. | 515 // Don't schedule nodes that cannot be scheduled or are already scheduled. |
494 if (!OperatorProperties::CanBeScheduled(node->op()) || | 516 if (!scheduler_->CanBeScheduled(node) || schedule_->IsScheduled(node)) { |
495 schedule_->IsScheduled(node)) { | |
496 return GenericGraphVisit::CONTINUE; | 517 return GenericGraphVisit::CONTINUE; |
497 } | 518 } |
498 DCHECK(!OperatorProperties::HasFixedSchedulePosition(node->op())); | 519 DCHECK(!scheduler_->HasFixedSchedulePosition(node)); |
499 | 520 |
500 // If all the uses of a node have been scheduled, then the node itself can | 521 // If all the uses of a node have been scheduled, then the node itself can |
501 // be scheduled. | 522 // be scheduled. |
502 bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0; | 523 bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0; |
503 if (FLAG_trace_turbo_scheduler) { | 524 if (FLAG_trace_turbo_scheduler) { |
504 PrintF("Testing for schedule eligibility for node %d -> %s\n", node->id(), | 525 PrintF("Testing for schedule eligibility for node %d -> %s\n", node->id(), |
505 eligible ? "true" : "false"); | 526 eligible ? "true" : "false"); |
506 } | 527 } |
507 if (!eligible) return GenericGraphVisit::DEFER; | 528 if (!eligible) return GenericGraphVisit::DEFER; |
508 | 529 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 | 576 |
556 ScheduleNode(block, node); | 577 ScheduleNode(block, node); |
557 | 578 |
558 return GenericGraphVisit::CONTINUE; | 579 return GenericGraphVisit::CONTINUE; |
559 } | 580 } |
560 | 581 |
561 private: | 582 private: |
562 BasicBlock* GetBlockForUse(Node::Edge edge) { | 583 BasicBlock* GetBlockForUse(Node::Edge edge) { |
563 Node* use = edge.from(); | 584 Node* use = edge.from(); |
564 IrOpcode::Value opcode = use->opcode(); | 585 IrOpcode::Value opcode = use->opcode(); |
565 // If the use is a phi, forward through the the phi to the basic block | 586 // If the use is a phi, forward through the phi to the basic block |
566 // corresponding to the phi's input. | 587 // corresponding to the phi's input. |
567 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { | 588 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { |
568 int index = edge.index(); | 589 int index = edge.index(); |
569 if (FLAG_trace_turbo_scheduler) { | 590 if (FLAG_trace_turbo_scheduler) { |
570 PrintF("Use %d is input %d to a phi\n", use->id(), index); | 591 PrintF("Use %d is input %d to a phi\n", use->id(), index); |
571 } | 592 } |
572 use = NodeProperties::GetControlInput(use, 0); | 593 use = NodeProperties::GetControlInput(use, 0); |
573 opcode = use->opcode(); | 594 opcode = use->opcode(); |
574 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); | 595 DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); |
575 use = NodeProperties::GetControlInput(use, index); | 596 use = NodeProperties::GetControlInput(use, index); |
576 } | 597 } |
577 BasicBlock* result = schedule_->block(use); | 598 BasicBlock* result = schedule_->block(use); |
578 if (result == NULL) return NULL; | 599 if (result == NULL) return NULL; |
579 if (FLAG_trace_turbo_scheduler) { | 600 if (FLAG_trace_turbo_scheduler) { |
580 PrintF("Must dominate use %d in block %d\n", use->id(), result->id()); | 601 PrintF("Must dominate use %d in block %d\n", use->id(), result->id()); |
581 } | 602 } |
582 return result; | 603 return result; |
583 } | 604 } |
584 | 605 |
585 bool IsNodeEligible(Node* node) { | |
586 bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0; | |
587 return eligible; | |
588 } | |
589 | |
590 void ScheduleNode(BasicBlock* block, Node* node) { | 606 void ScheduleNode(BasicBlock* block, Node* node) { |
591 schedule_->PlanNode(block, node); | 607 schedule_->PlanNode(block, node); |
592 scheduler_->scheduled_nodes_[block->id()].push_back(node); | 608 scheduler_->scheduled_nodes_[block->id()].push_back(node); |
593 | 609 |
594 // Reduce the use count of the node's inputs to potentially make them | 610 // Reduce the use count of the node's inputs to potentially make them |
595 // scheduable. | 611 // scheduable. |
596 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { | 612 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { |
597 DCHECK(scheduler_->unscheduled_uses_[(*i)->id()] > 0); | 613 DCHECK(scheduler_->unscheduled_uses_[(*i)->id()] > 0); |
598 --scheduler_->unscheduled_uses_[(*i)->id()]; | 614 --scheduler_->unscheduled_uses_[(*i)->id()]; |
599 if (FLAG_trace_turbo_scheduler) { | 615 if (FLAG_trace_turbo_scheduler) { |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1040 | 1056 |
1041 #if DEBUG | 1057 #if DEBUG |
1042 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); | 1058 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); |
1043 VerifySpecialRPO(num_loops, loops, final_order); | 1059 VerifySpecialRPO(num_loops, loops, final_order); |
1044 #endif | 1060 #endif |
1045 return final_order; | 1061 return final_order; |
1046 } | 1062 } |
1047 } | 1063 } |
1048 } | 1064 } |
1049 } // namespace v8::internal::compiler | 1065 } // namespace v8::internal::compiler |
OLD | NEW |