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/bit-vector.h" | 10 #include "src/bit-vector.h" |
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 #if DEBUG | 575 #if DEBUG |
576 if (FLAG_trace_turbo_scheduler) PrintRPO(); | 576 if (FLAG_trace_turbo_scheduler) PrintRPO(); |
577 VerifySpecialRPO(); | 577 VerifySpecialRPO(); |
578 #endif | 578 #endif |
579 } | 579 } |
580 | 580 |
581 private: | 581 private: |
582 // TODO(mstarzinger): Only for Scheduler::GenerateImmediateDominatorTree. | 582 // TODO(mstarzinger): Only for Scheduler::GenerateImmediateDominatorTree. |
583 friend class Scheduler; | 583 friend class Scheduler; |
584 | 584 |
585 // Numbering for BasicBlockData.rpo_number_ for this block traversal: | 585 // Numbering for BasicBlock::rpo_number for this block traversal: |
586 static const int kBlockOnStack = -2; | 586 static const int kBlockOnStack = -2; |
587 static const int kBlockVisited1 = -3; | 587 static const int kBlockVisited1 = -3; |
588 static const int kBlockVisited2 = -4; | 588 static const int kBlockVisited2 = -4; |
589 static const int kBlockUnvisited1 = -1; | 589 static const int kBlockUnvisited1 = -1; |
590 static const int kBlockUnvisited2 = kBlockVisited1; | 590 static const int kBlockUnvisited2 = kBlockVisited1; |
591 | 591 |
592 struct SpecialRPOStackFrame { | 592 struct SpecialRPOStackFrame { |
593 BasicBlock* block; | 593 BasicBlock* block; |
594 size_t index; | 594 size_t index; |
595 }; | 595 }; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 // mutating any existing order so that the result is still valid. | 665 // mutating any existing order so that the result is still valid. |
666 void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) { | 666 void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) { |
667 // RPO should not have been serialized for this schedule yet. | 667 // RPO should not have been serialized for this schedule yet. |
668 CHECK_EQ(kBlockUnvisited1, schedule_->start()->ao_number()); | 668 CHECK_EQ(kBlockUnvisited1, schedule_->start()->ao_number()); |
669 CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number()); | 669 CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number()); |
670 CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size())); | 670 CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size())); |
671 | 671 |
672 // Find correct insertion point within existing order. | 672 // Find correct insertion point within existing order. |
673 BlockList* insert_before = order_->FindForBlock(entry); | 673 BlockList* insert_before = order_->FindForBlock(entry); |
674 BlockList* insert_after = insert_before ? insert_before->next : NULL; | 674 BlockList* insert_after = insert_before ? insert_before->next : NULL; |
| 675 BlockList* order = insert_after; |
675 | 676 |
676 // Perform an iterative RPO traversal using an explicit stack, | 677 // Perform an iterative RPO traversal using an explicit stack, |
677 // recording backedges that form cycles. O(|B|). | 678 // recording backedges that form cycles. O(|B|). |
678 ZoneList<std::pair<BasicBlock*, size_t> > backedges(1, zone_); | 679 ZoneList<std::pair<BasicBlock*, size_t> > backedges(1, zone_); |
679 SpecialRPOStackFrame* stack = zone_->NewArray<SpecialRPOStackFrame>( | 680 SpecialRPOStackFrame* stack = zone_->NewArray<SpecialRPOStackFrame>( |
680 static_cast<int>(schedule_->BasicBlockCount())); | 681 static_cast<int>(schedule_->BasicBlockCount())); |
681 int stack_depth = Push(stack, 0, entry, kBlockUnvisited1); | 682 int stack_depth = Push(stack, 0, entry, kBlockUnvisited1); |
682 int num_loops = 0; | 683 int num_loops = 0; |
683 | 684 |
684 while (stack_depth > 0) { | 685 while (stack_depth > 0) { |
(...skipping 14 matching lines...) Expand all Loading... |
699 // Assign a new loop number to the header if it doesn't have one. | 700 // Assign a new loop number to the header if it doesn't have one. |
700 SetLoopNumber(succ, num_loops++); | 701 SetLoopNumber(succ, num_loops++); |
701 } | 702 } |
702 } else { | 703 } else { |
703 // Push the successor onto the stack. | 704 // Push the successor onto the stack. |
704 DCHECK(succ->rpo_number() == kBlockUnvisited1); | 705 DCHECK(succ->rpo_number() == kBlockUnvisited1); |
705 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1); | 706 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1); |
706 } | 707 } |
707 } else { | 708 } else { |
708 // Finished with all successors; pop the stack and add the block. | 709 // Finished with all successors; pop the stack and add the block. |
709 insert_after = insert_after->Add(zone_, frame->block); | 710 order = order->Add(zone_, frame->block); |
710 frame->block->set_rpo_number(kBlockVisited1); | 711 frame->block->set_rpo_number(kBlockVisited1); |
711 stack_depth--; | 712 stack_depth--; |
712 } | 713 } |
713 } | 714 } |
714 | 715 |
715 // Insert the result into any existing order. | |
716 if (insert_before == NULL) { | |
717 order_ = insert_after; | |
718 } else { | |
719 // There already is a list element for the entry block in the list, hence | |
720 // we skip the first element of the sub-list to compensate duplication. | |
721 DCHECK_EQ(insert_before->block, insert_after->block); | |
722 insert_before->next = insert_after->next; | |
723 } | |
724 | |
725 // If no loops were encountered, then the order we computed was correct. | 716 // If no loops were encountered, then the order we computed was correct. |
726 if (num_loops != 0) { | 717 if (num_loops != 0) { |
727 // Otherwise, compute the loop information from the backedges in order | 718 // Otherwise, compute the loop information from the backedges in order |
728 // to perform a traversal that groups loop bodies together. | 719 // to perform a traversal that groups loop bodies together. |
729 ComputeLoopInfo(stack, num_loops, &backedges); | 720 ComputeLoopInfo(stack, num_loops, &backedges); |
730 | 721 |
731 // Initialize the "loop stack". Note the entry could be a loop header. | 722 // Initialize the "loop stack". Note the entry could be a loop header. |
732 LoopInfo* loop = | 723 LoopInfo* loop = |
733 HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : NULL; | 724 HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : NULL; |
734 order_ = NULL; | 725 order = NULL; |
735 | 726 |
736 // Perform an iterative post-order traversal, visiting loop bodies before | 727 // Perform an iterative post-order traversal, visiting loop bodies before |
737 // edges that lead out of loops. Visits each block once, but linking loop | 728 // edges that lead out of loops. Visits each block once, but linking loop |
738 // sections together is linear in the loop size, so overall is | 729 // sections together is linear in the loop size, so overall is |
739 // O(|B| + max(loop_depth) * max(|loop|)) | 730 // O(|B| + max(loop_depth) * max(|loop|)) |
740 stack_depth = Push(stack, 0, entry, kBlockUnvisited2); | 731 stack_depth = Push(stack, 0, entry, kBlockUnvisited2); |
741 while (stack_depth > 0) { | 732 while (stack_depth > 0) { |
742 SpecialRPOStackFrame* frame = stack + (stack_depth - 1); | 733 SpecialRPOStackFrame* frame = stack + (stack_depth - 1); |
743 BasicBlock* block = frame->block; | 734 BasicBlock* block = frame->block; |
744 BasicBlock* succ = NULL; | 735 BasicBlock* succ = NULL; |
745 | 736 |
746 if (frame->index < block->SuccessorCount()) { | 737 if (frame->index < block->SuccessorCount()) { |
747 // Process the next normal successor. | 738 // Process the next normal successor. |
748 succ = block->SuccessorAt(frame->index++); | 739 succ = block->SuccessorAt(frame->index++); |
749 } else if (HasLoopNumber(block)) { | 740 } else if (HasLoopNumber(block)) { |
750 // Process additional outgoing edges from the loop header. | 741 // Process additional outgoing edges from the loop header. |
751 if (block->rpo_number() == kBlockOnStack) { | 742 if (block->rpo_number() == kBlockOnStack) { |
752 // Finish the loop body the first time the header is left on the | 743 // Finish the loop body the first time the header is left on the |
753 // stack. | 744 // stack. |
754 DCHECK(loop != NULL && loop->header == block); | 745 DCHECK(loop != NULL && loop->header == block); |
755 loop->start = order_->Add(zone_, block); | 746 loop->start = order->Add(zone_, block); |
756 order_ = loop->end; | 747 order = loop->end; |
757 block->set_rpo_number(kBlockVisited2); | 748 block->set_rpo_number(kBlockVisited2); |
758 // Pop the loop stack and continue visiting outgoing edges within | 749 // Pop the loop stack and continue visiting outgoing edges within |
759 // the context of the outer loop, if any. | 750 // the context of the outer loop, if any. |
760 loop = loop->prev; | 751 loop = loop->prev; |
761 // We leave the loop header on the stack; the rest of this iteration | 752 // We leave the loop header on the stack; the rest of this iteration |
762 // and later iterations will go through its outgoing edges list. | 753 // and later iterations will go through its outgoing edges list. |
763 } | 754 } |
764 | 755 |
765 // Use the next outgoing edge if there are any. | 756 // Use the next outgoing edge if there are any. |
766 int outgoing_index = | 757 int outgoing_index = |
(...skipping 16 matching lines...) Expand all Loading... |
783 // The successor is not in the current loop or any nested loop. | 774 // The successor is not in the current loop or any nested loop. |
784 // Add it to the outgoing edges of this loop and visit it later. | 775 // Add it to the outgoing edges of this loop and visit it later. |
785 loop->AddOutgoing(zone_, succ); | 776 loop->AddOutgoing(zone_, succ); |
786 } else { | 777 } else { |
787 // Push the successor onto the stack. | 778 // Push the successor onto the stack. |
788 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2); | 779 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2); |
789 if (HasLoopNumber(succ)) { | 780 if (HasLoopNumber(succ)) { |
790 // Push the inner loop onto the loop stack. | 781 // Push the inner loop onto the loop stack. |
791 DCHECK(GetLoopNumber(succ) < num_loops); | 782 DCHECK(GetLoopNumber(succ) < num_loops); |
792 LoopInfo* next = &loops_[GetLoopNumber(succ)]; | 783 LoopInfo* next = &loops_[GetLoopNumber(succ)]; |
793 next->end = order_; | 784 next->end = order; |
794 next->prev = loop; | 785 next->prev = loop; |
795 loop = next; | 786 loop = next; |
796 } | 787 } |
797 } | 788 } |
798 } else { | 789 } else { |
799 // Finished with all successors of the current block. | 790 // Finished with all successors of the current block. |
800 if (HasLoopNumber(block)) { | 791 if (HasLoopNumber(block)) { |
801 // If we are going to pop a loop header, then add its entire body. | 792 // If we are going to pop a loop header, then add its entire body. |
802 LoopInfo* info = &loops_[GetLoopNumber(block)]; | 793 LoopInfo* info = &loops_[GetLoopNumber(block)]; |
803 for (BlockList* l = info->start; true; l = l->next) { | 794 for (BlockList* l = info->start; true; l = l->next) { |
804 if (l->next == info->end) { | 795 if (l->next == info->end) { |
805 l->next = order_; | 796 l->next = order; |
806 info->end = order_; | 797 info->end = order; |
807 break; | 798 break; |
808 } | 799 } |
809 } | 800 } |
810 order_ = info->start; | 801 order = info->start; |
811 } else { | 802 } else { |
812 // Pop a single node off the stack and add it to the order. | 803 // Pop a single node off the stack and add it to the order. |
813 order_ = order_->Add(zone_, block); | 804 order = order->Add(zone_, block); |
814 block->set_rpo_number(kBlockVisited2); | 805 block->set_rpo_number(kBlockVisited2); |
815 } | 806 } |
816 stack_depth--; | 807 stack_depth--; |
817 } | 808 } |
818 } | 809 } |
819 } | 810 } |
820 | 811 |
| 812 // Insert result into existing order. |
| 813 if (insert_before == NULL) { |
| 814 order_ = order; |
| 815 } else { |
| 816 // There already is a list element for the entry block in the list, hence |
| 817 // we skip the first element of the sub-list to compensate duplication. |
| 818 DCHECK_EQ(insert_before->block, order->block); |
| 819 insert_before->next = order->next; |
| 820 } |
| 821 |
821 // Compute the correct loop headers and set the correct loop ends. | 822 // Compute the correct loop headers and set the correct loop ends. |
822 LoopInfo* current_loop = NULL; | 823 LoopInfo* current_loop = NULL; |
823 BasicBlock* current_header = NULL; | 824 BasicBlock* current_header = entry->loop_header(); |
824 int loop_depth = 0; | 825 int32_t loop_depth = entry->loop_depth(); |
825 for (BlockList* l = order_; l != NULL; l = l->next) { | 826 if (entry->IsLoopHeader()) --loop_depth; // Entry might be a loop header. |
| 827 for (BlockList* l = order; l != insert_after; l = l->next) { |
826 BasicBlock* current = l->block; | 828 BasicBlock* current = l->block; |
827 | 829 |
| 830 // Reset BasicBlock::rpo_number again. |
| 831 current->set_rpo_number(kBlockUnvisited1); |
| 832 |
828 // Finish the previous loop(s) if we just exited them. | 833 // Finish the previous loop(s) if we just exited them. |
829 while (current_header != NULL && current == current_header->loop_end()) { | 834 while (current_header != NULL && current == current_header->loop_end()) { |
830 DCHECK(current_header->IsLoopHeader()); | 835 DCHECK(current_header->IsLoopHeader()); |
831 DCHECK(current_loop != NULL); | 836 DCHECK(current_loop != NULL); |
832 current_loop = current_loop->prev; | 837 current_loop = current_loop->prev; |
833 current_header = current_loop == NULL ? NULL : current_loop->header; | 838 current_header = current_loop == NULL ? NULL : current_loop->header; |
834 --loop_depth; | 839 --loop_depth; |
835 } | 840 } |
836 current->set_loop_header(current_header); | 841 current->set_loop_header(current_header); |
837 | 842 |
838 // Push a new loop onto the stack if this loop is a loop header. | 843 // Push a new loop onto the stack if this loop is a loop header. |
839 if (HasLoopNumber(current)) { | 844 if (HasLoopNumber(current)) { |
840 loop_depth++; | 845 ++loop_depth; |
841 current_loop = &loops_[GetLoopNumber(current)]; | 846 current_loop = &loops_[GetLoopNumber(current)]; |
842 BlockList* end = current_loop->end; | 847 BlockList* end = current_loop->end; |
843 current->set_loop_end(end == NULL ? BeyondEndSentinel() : end->block); | 848 current->set_loop_end(end == NULL ? BeyondEndSentinel() : end->block); |
844 current_header = current_loop->header; | 849 current_header = current_loop->header; |
845 Trace("B%d is a loop header, increment loop depth to %d\n", | 850 Trace("B%d is a loop header, increment loop depth to %d\n", |
846 current->id().ToInt(), loop_depth); | 851 current->id().ToInt(), loop_depth); |
847 } | 852 } |
848 | 853 |
849 current->set_loop_depth(loop_depth); | 854 current->set_loop_depth(loop_depth); |
850 | 855 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 int links = 0; | 970 int links = 0; |
966 BlockList* l = loop->start; | 971 BlockList* l = loop->start; |
967 DCHECK(l != NULL && l->block == header); | 972 DCHECK(l != NULL && l->block == header); |
968 bool end_found; | 973 bool end_found; |
969 while (true) { | 974 while (true) { |
970 if (l == NULL || l == loop->end) { | 975 if (l == NULL || l == loop->end) { |
971 end_found = (loop->end == l); | 976 end_found = (loop->end == l); |
972 break; | 977 break; |
973 } | 978 } |
974 // The list should be in same order as the final result. | 979 // The list should be in same order as the final result. |
975 DCHECK(l->block->rpo_number() == links + loop->header->rpo_number()); | 980 DCHECK(l->block->rpo_number() == links + header->rpo_number()); |
976 links++; | 981 links++; |
977 l = l->next; | 982 l = l->next; |
978 DCHECK(links < static_cast<int>(2 * order->size())); // cycle? | 983 DCHECK(links < static_cast<int>(2 * order->size())); // cycle? |
979 } | 984 } |
980 DCHECK(links > 0); | 985 DCHECK(links > 0); |
981 DCHECK(links == end->rpo_number() - header->rpo_number()); | 986 DCHECK(links == end->rpo_number() - header->rpo_number()); |
982 DCHECK(end_found); | 987 DCHECK(end_found); |
983 | 988 |
| 989 // Check loop depth of the header. |
| 990 int loop_depth = 0; |
| 991 for (LoopInfo* outer = loop; outer != NULL; outer = outer->prev) { |
| 992 loop_depth++; |
| 993 } |
| 994 DCHECK_EQ(loop_depth, header->loop_depth()); |
| 995 |
984 // Check the contiguousness of loops. | 996 // Check the contiguousness of loops. |
985 int count = 0; | 997 int count = 0; |
986 for (int j = 0; j < static_cast<int>(order->size()); j++) { | 998 for (int j = 0; j < static_cast<int>(order->size()); j++) { |
987 BasicBlock* block = order->at(j); | 999 BasicBlock* block = order->at(j); |
988 DCHECK(block->rpo_number() == j); | 1000 DCHECK(block->rpo_number() == j); |
989 if (j < header->rpo_number() || j >= end->rpo_number()) { | 1001 if (j < header->rpo_number() || j >= end->rpo_number()) { |
990 DCHECK(!header->LoopContains(block)); | 1002 DCHECK(!header->LoopContains(block)); |
991 } else { | 1003 } else { |
992 DCHECK(header->LoopContains(block)); | 1004 DCHECK(header->LoopContains(block)); |
| 1005 DCHECK_GE(block->loop_depth(), loop_depth); |
993 count++; | 1006 count++; |
994 } | 1007 } |
995 } | 1008 } |
996 DCHECK(links == count); | 1009 DCHECK(links == count); |
997 } | 1010 } |
998 } | 1011 } |
999 #endif // DEBUG | 1012 #endif // DEBUG |
1000 | 1013 |
1001 Zone* zone_; | 1014 Zone* zone_; |
1002 Schedule* schedule_; | 1015 Schedule* schedule_; |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1421 if (FLAG_trace_turbo_scheduler) { | 1434 if (FLAG_trace_turbo_scheduler) { |
1422 OFStream os(stdout); | 1435 OFStream os(stdout); |
1423 os << "Schedule before control flow fusion:\n" << *schedule_; | 1436 os << "Schedule before control flow fusion:\n" << *schedule_; |
1424 } | 1437 } |
1425 | 1438 |
1426 // Iterate on phase 1: Build control-flow graph. | 1439 // Iterate on phase 1: Build control-flow graph. |
1427 CFGBuilder cfg_builder(zone_, this); | 1440 CFGBuilder cfg_builder(zone_, this); |
1428 cfg_builder.Run(block, node); | 1441 cfg_builder.Run(block, node); |
1429 | 1442 |
1430 // Iterate on phase 2: Compute special RPO and dominator tree. | 1443 // Iterate on phase 2: Compute special RPO and dominator tree. |
| 1444 special_rpo_->UpdateSpecialRPO(block, schedule_->block(node)); |
1431 // TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that. | 1445 // TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that. |
1432 for (BasicBlock* block : schedule_->all_blocks_) { | 1446 for (BasicBlock* block : schedule_->all_blocks_) { |
1433 block->set_rpo_number(-1); | |
1434 block->set_dominator_depth(-1); | 1447 block->set_dominator_depth(-1); |
1435 block->set_dominator(NULL); | 1448 block->set_dominator(NULL); |
1436 } | 1449 } |
1437 special_rpo_->UpdateSpecialRPO(block, schedule_->block(node)); | |
1438 GenerateImmediateDominatorTree(); | 1450 GenerateImmediateDominatorTree(); |
1439 | 1451 |
1440 // Move previously planned nodes. | 1452 // Move previously planned nodes. |
1441 // TODO(mstarzinger): Improve that by supporting bulk moves. | 1453 // TODO(mstarzinger): Improve that by supporting bulk moves. |
1442 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); | 1454 scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_)); |
1443 MovePlannedNodes(block, schedule_->block(node)); | 1455 MovePlannedNodes(block, schedule_->block(node)); |
1444 | 1456 |
1445 if (FLAG_trace_turbo_scheduler) { | 1457 if (FLAG_trace_turbo_scheduler) { |
1446 OFStream os(stdout); | 1458 OFStream os(stdout); |
1447 os << "Schedule after control flow fusion:\n" << *schedule_; | 1459 os << "Schedule after control flow fusion:\n" << *schedule_; |
1448 } | 1460 } |
1449 } | 1461 } |
1450 | 1462 |
1451 | 1463 |
1452 void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) { | 1464 void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) { |
1453 Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(), | 1465 Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(), |
1454 to->id().ToInt()); | 1466 to->id().ToInt()); |
1455 NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]); | 1467 NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]); |
1456 for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) { | 1468 for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) { |
1457 schedule_->SetBlockForNode(to, *i); | 1469 schedule_->SetBlockForNode(to, *i); |
1458 scheduled_nodes_[to->id().ToSize()].push_back(*i); | 1470 scheduled_nodes_[to->id().ToSize()].push_back(*i); |
1459 } | 1471 } |
1460 nodes->clear(); | 1472 nodes->clear(); |
1461 } | 1473 } |
1462 | 1474 |
1463 } // namespace compiler | 1475 } // namespace compiler |
1464 } // namespace internal | 1476 } // namespace internal |
1465 } // namespace v8 | 1477 } // namespace v8 |
OLD | NEW |