| 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 |