| 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" |
| 11 #include "src/compiler/node-properties-inl.h" | 11 #include "src/compiler/node-properties-inl.h" |
| 12 #include "src/data-flow.h" | 12 #include "src/data-flow.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 namespace compiler { | 16 namespace compiler { |
| 17 | 17 |
| 18 Scheduler::Scheduler(Zone* zone) | |
| 19 : zone_(zone), | |
| 20 graph_(NULL), | |
| 21 schedule_(NULL), | |
| 22 branches_(NodeVector::allocator_type(zone)), | |
| 23 calls_(NodeVector::allocator_type(zone)), | |
| 24 deopts_(NodeVector::allocator_type(zone)), | |
| 25 returns_(NodeVector::allocator_type(zone)), | |
| 26 loops_and_merges_(NodeVector::allocator_type(zone)), | |
| 27 node_block_placement_(BasicBlockVector::allocator_type(zone)), | |
| 28 unscheduled_uses_(IntVector::allocator_type(zone)), | |
| 29 scheduled_nodes_(NodeVectorVector::allocator_type(zone)), | |
| 30 schedule_root_nodes_(NodeVector::allocator_type(zone)), | |
| 31 schedule_early_rpo_index_(IntVector::allocator_type(zone)) {} | |
| 32 | |
| 33 | |
| 34 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) | 18 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) |
| 35 : zone_(zone), | 19 : zone_(zone), |
| 36 graph_(graph), | 20 graph_(graph), |
| 37 schedule_(schedule), | 21 schedule_(schedule), |
| 38 branches_(NodeVector::allocator_type(zone)), | 22 branches_(NodeVector::allocator_type(zone)), |
| 39 calls_(NodeVector::allocator_type(zone)), | 23 calls_(NodeVector::allocator_type(zone)), |
| 40 deopts_(NodeVector::allocator_type(zone)), | 24 deopts_(NodeVector::allocator_type(zone)), |
| 41 returns_(NodeVector::allocator_type(zone)), | 25 returns_(NodeVector::allocator_type(zone)), |
| 42 loops_and_merges_(NodeVector::allocator_type(zone)), | 26 loops_and_merges_(NodeVector::allocator_type(zone)), |
| 43 node_block_placement_(BasicBlockVector::allocator_type(zone)), | 27 node_block_placement_(BasicBlockVector::allocator_type(zone)), |
| 44 unscheduled_uses_(IntVector::allocator_type(zone)), | 28 unscheduled_uses_(IntVector::allocator_type(zone)), |
| 45 scheduled_nodes_(NodeVectorVector::allocator_type(zone)), | 29 scheduled_nodes_(NodeVectorVector::allocator_type(zone)), |
| 46 schedule_root_nodes_(NodeVector::allocator_type(zone)), | 30 schedule_root_nodes_(NodeVector::allocator_type(zone)), |
| 47 schedule_early_rpo_index_(IntVector::allocator_type(zone)) {} | 31 schedule_early_rpo_index_(IntVector::allocator_type(zone)) {} |
| 48 | 32 |
| 49 | 33 |
| 50 Schedule* Scheduler::NewSchedule(Graph* graph) { | 34 Schedule* Scheduler::ComputeSchedule(Graph* graph) { |
| 51 graph_ = graph; | 35 Zone tmp_zone(graph->zone()->isolate()); |
| 52 schedule_ = new (zone_) Schedule(zone_); | 36 Schedule* schedule = new (graph->zone()) Schedule(graph->zone()); |
| 37 Scheduler scheduler(&tmp_zone, graph, schedule); |
| 53 | 38 |
| 54 schedule_->AddNode(schedule_->end(), graph_->end()); | 39 schedule->AddNode(schedule->end(), graph->end()); |
| 55 | 40 |
| 56 PrepareAuxiliaryNodeData(); | 41 scheduler.PrepareAuxiliaryNodeData(); |
| 42 scheduler.CreateBlocks(); |
| 43 scheduler.WireBlocks(); |
| 44 scheduler.PrepareAuxiliaryBlockData(); |
| 57 | 45 |
| 58 // Create basic blocks for each block and merge node in the graph. | 46 Scheduler::ComputeSpecialRPO(schedule); |
| 59 CreateBlocks(); | 47 scheduler.GenerateImmediateDominatorTree(); |
| 60 | 48 |
| 61 // Wire the basic blocks together. | 49 scheduler.PrepareUses(); |
| 62 WireBlocks(); | 50 scheduler.ScheduleEarly(); |
| 51 scheduler.ScheduleLate(); |
| 63 | 52 |
| 64 PrepareAuxiliaryBlockData(); | 53 return schedule; |
| 65 | |
| 66 ComputeSpecialRPO(); | |
| 67 GenerateImmediateDominatorTree(); | |
| 68 | |
| 69 PrepareUses(); | |
| 70 ScheduleEarly(); | |
| 71 ScheduleLate(); | |
| 72 | |
| 73 return schedule_; | |
| 74 } | 54 } |
| 75 | 55 |
| 76 | 56 |
| 77 class CreateBlockVisitor : public NullNodeVisitor { | 57 class CreateBlockVisitor : public NullNodeVisitor { |
| 78 public: | 58 public: |
| 79 explicit CreateBlockVisitor(Scheduler* scheduler) : scheduler_(scheduler) {} | 59 explicit CreateBlockVisitor(Scheduler* scheduler) : scheduler_(scheduler) {} |
| 80 | 60 |
| 81 GenericGraphVisit::Control Post(Node* node) { | 61 GenericGraphVisit::Control Post(Node* node) { |
| 82 Schedule* schedule = scheduler_->schedule_; | 62 Schedule* schedule = scheduler_->schedule_; |
| 83 switch (node->opcode()) { | 63 switch (node->opcode()) { |
| (...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 // a RPO of the graph where loop bodies are contiguous. Properties: | 839 // a RPO of the graph where loop bodies are contiguous. Properties: |
| 860 // 1. If block A is a predecessor of B, then A appears before B in the order, | 840 // 1. If block A is a predecessor of B, then A appears before B in the order, |
| 861 // unless B is a loop header and A is in the loop headed at B | 841 // unless B is a loop header and A is in the loop headed at B |
| 862 // (i.e. A -> B is a backedge). | 842 // (i.e. A -> B is a backedge). |
| 863 // => If block A dominates block B, then A appears before B in the order. | 843 // => If block A dominates block B, then A appears before B in the order. |
| 864 // => If block A is a loop header, A appears before all blocks in the loop | 844 // => If block A is a loop header, A appears before all blocks in the loop |
| 865 // headed at A. | 845 // headed at A. |
| 866 // 2. All loops are contiguous in the order (i.e. no intervening blocks that | 846 // 2. All loops are contiguous in the order (i.e. no intervening blocks that |
| 867 // do not belong to the loop.) | 847 // do not belong to the loop.) |
| 868 // Note a simple RPO traversal satisfies (1) but not (3). | 848 // Note a simple RPO traversal satisfies (1) but not (3). |
| 869 BasicBlockVector* Scheduler::ComputeSpecialRPO() { | 849 BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) { |
| 850 Zone tmp_zone(schedule->zone()->isolate()); |
| 851 Zone* zone = &tmp_zone; |
| 870 if (FLAG_trace_turbo_scheduler) { | 852 if (FLAG_trace_turbo_scheduler) { |
| 871 PrintF("------------- COMPUTING SPECIAL RPO ---------------\n"); | 853 PrintF("------------- COMPUTING SPECIAL RPO ---------------\n"); |
| 872 } | 854 } |
| 873 // RPO should not have been computed for this schedule yet. | 855 // RPO should not have been computed for this schedule yet. |
| 874 CHECK_EQ(kBlockUnvisited1, schedule_->entry()->rpo_number_); | 856 CHECK_EQ(kBlockUnvisited1, schedule->entry()->rpo_number_); |
| 875 CHECK_EQ(0, static_cast<int>(schedule_->rpo_order_.size())); | 857 CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size())); |
| 876 | 858 |
| 877 // Perform an iterative RPO traversal using an explicit stack, | 859 // Perform an iterative RPO traversal using an explicit stack, |
| 878 // recording backedges that form cycles. O(|B|). | 860 // recording backedges that form cycles. O(|B|). |
| 879 ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone_); | 861 ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone); |
| 880 SpecialRPOStackFrame* stack = | 862 SpecialRPOStackFrame* stack = |
| 881 zone_->NewArray<SpecialRPOStackFrame>(schedule_->BasicBlockCount()); | 863 zone->NewArray<SpecialRPOStackFrame>(schedule->BasicBlockCount()); |
| 882 BasicBlock* entry = schedule_->entry(); | 864 BasicBlock* entry = schedule->entry(); |
| 883 BlockList* order = NULL; | 865 BlockList* order = NULL; |
| 884 int stack_depth = Push(stack, 0, entry, kBlockUnvisited1); | 866 int stack_depth = Push(stack, 0, entry, kBlockUnvisited1); |
| 885 int num_loops = 0; | 867 int num_loops = 0; |
| 886 | 868 |
| 887 while (stack_depth > 0) { | 869 while (stack_depth > 0) { |
| 888 int current = stack_depth - 1; | 870 int current = stack_depth - 1; |
| 889 SpecialRPOStackFrame* frame = stack + current; | 871 SpecialRPOStackFrame* frame = stack + current; |
| 890 | 872 |
| 891 if (frame->index < frame->block->SuccessorCount()) { | 873 if (frame->index < frame->block->SuccessorCount()) { |
| 892 // Process the next successor. | 874 // Process the next successor. |
| 893 BasicBlock* succ = frame->block->SuccessorAt(frame->index++); | 875 BasicBlock* succ = frame->block->SuccessorAt(frame->index++); |
| 894 if (succ->rpo_number_ == kBlockVisited1) continue; | 876 if (succ->rpo_number_ == kBlockVisited1) continue; |
| 895 if (succ->rpo_number_ == kBlockOnStack) { | 877 if (succ->rpo_number_ == kBlockOnStack) { |
| 896 // The successor is on the stack, so this is a backedge (cycle). | 878 // The successor is on the stack, so this is a backedge (cycle). |
| 897 backedges.Add( | 879 backedges.Add( |
| 898 std::pair<BasicBlock*, int>(frame->block, frame->index - 1), zone_); | 880 std::pair<BasicBlock*, int>(frame->block, frame->index - 1), zone); |
| 899 if (succ->loop_end_ < 0) { | 881 if (succ->loop_end_ < 0) { |
| 900 // Assign a new loop number to the header if it doesn't have one. | 882 // Assign a new loop number to the header if it doesn't have one. |
| 901 succ->loop_end_ = num_loops++; | 883 succ->loop_end_ = num_loops++; |
| 902 } | 884 } |
| 903 } else { | 885 } else { |
| 904 // Push the successor onto the stack. | 886 // Push the successor onto the stack. |
| 905 DCHECK(succ->rpo_number_ == kBlockUnvisited1); | 887 DCHECK(succ->rpo_number_ == kBlockUnvisited1); |
| 906 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1); | 888 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1); |
| 907 } | 889 } |
| 908 } else { | 890 } else { |
| 909 // Finished with all successors; pop the stack and add the block. | 891 // Finished with all successors; pop the stack and add the block. |
| 910 order = order->Add(zone_, frame->block); | 892 order = order->Add(zone, frame->block); |
| 911 frame->block->rpo_number_ = kBlockVisited1; | 893 frame->block->rpo_number_ = kBlockVisited1; |
| 912 stack_depth--; | 894 stack_depth--; |
| 913 } | 895 } |
| 914 } | 896 } |
| 915 | 897 |
| 916 // If no loops were encountered, then the order we computed was correct. | 898 // If no loops were encountered, then the order we computed was correct. |
| 917 LoopInfo* loops = NULL; | 899 LoopInfo* loops = NULL; |
| 918 if (num_loops != 0) { | 900 if (num_loops != 0) { |
| 919 // Otherwise, compute the loop information from the backedges in order | 901 // Otherwise, compute the loop information from the backedges in order |
| 920 // to perform a traversal that groups loop bodies together. | 902 // to perform a traversal that groups loop bodies together. |
| 921 loops = ComputeLoopInfo(zone_, stack, num_loops, | 903 loops = ComputeLoopInfo(zone, stack, num_loops, schedule->BasicBlockCount(), |
| 922 schedule_->BasicBlockCount(), &backedges); | 904 &backedges); |
| 923 | 905 |
| 924 // Initialize the "loop stack". Note the entry could be a loop header. | 906 // Initialize the "loop stack". Note the entry could be a loop header. |
| 925 LoopInfo* loop = entry->IsLoopHeader() ? &loops[entry->loop_end_] : NULL; | 907 LoopInfo* loop = entry->IsLoopHeader() ? &loops[entry->loop_end_] : NULL; |
| 926 order = NULL; | 908 order = NULL; |
| 927 | 909 |
| 928 // Perform an iterative post-order traversal, visiting loop bodies before | 910 // Perform an iterative post-order traversal, visiting loop bodies before |
| 929 // edges that lead out of loops. Visits each block once, but linking loop | 911 // edges that lead out of loops. Visits each block once, but linking loop |
| 930 // sections together is linear in the loop size, so overall is | 912 // sections together is linear in the loop size, so overall is |
| 931 // O(|B| + max(loop_depth) * max(|loop|)) | 913 // O(|B| + max(loop_depth) * max(|loop|)) |
| 932 stack_depth = Push(stack, 0, entry, kBlockUnvisited2); | 914 stack_depth = Push(stack, 0, entry, kBlockUnvisited2); |
| 933 while (stack_depth > 0) { | 915 while (stack_depth > 0) { |
| 934 SpecialRPOStackFrame* frame = stack + (stack_depth - 1); | 916 SpecialRPOStackFrame* frame = stack + (stack_depth - 1); |
| 935 BasicBlock* block = frame->block; | 917 BasicBlock* block = frame->block; |
| 936 BasicBlock* succ = NULL; | 918 BasicBlock* succ = NULL; |
| 937 | 919 |
| 938 if (frame->index < block->SuccessorCount()) { | 920 if (frame->index < block->SuccessorCount()) { |
| 939 // Process the next normal successor. | 921 // Process the next normal successor. |
| 940 succ = block->SuccessorAt(frame->index++); | 922 succ = block->SuccessorAt(frame->index++); |
| 941 } else if (block->IsLoopHeader()) { | 923 } else if (block->IsLoopHeader()) { |
| 942 // Process additional outgoing edges from the loop header. | 924 // Process additional outgoing edges from the loop header. |
| 943 if (block->rpo_number_ == kBlockOnStack) { | 925 if (block->rpo_number_ == kBlockOnStack) { |
| 944 // Finish the loop body the first time the header is left on the | 926 // Finish the loop body the first time the header is left on the |
| 945 // stack. | 927 // stack. |
| 946 DCHECK(loop != NULL && loop->header == block); | 928 DCHECK(loop != NULL && loop->header == block); |
| 947 loop->start = order->Add(zone_, block); | 929 loop->start = order->Add(zone, block); |
| 948 order = loop->end; | 930 order = loop->end; |
| 949 block->rpo_number_ = kBlockVisited2; | 931 block->rpo_number_ = kBlockVisited2; |
| 950 // Pop the loop stack and continue visiting outgoing edges within the | 932 // Pop the loop stack and continue visiting outgoing edges within the |
| 951 // the context of the outer loop, if any. | 933 // the context of the outer loop, if any. |
| 952 loop = loop->prev; | 934 loop = loop->prev; |
| 953 // We leave the loop header on the stack; the rest of this iteration | 935 // We leave the loop header on the stack; the rest of this iteration |
| 954 // and later iterations will go through its outgoing edges list. | 936 // and later iterations will go through its outgoing edges list. |
| 955 } | 937 } |
| 956 | 938 |
| 957 // Use the next outgoing edge if there are any. | 939 // Use the next outgoing edge if there are any. |
| 958 int outgoing_index = frame->index - block->SuccessorCount(); | 940 int outgoing_index = frame->index - block->SuccessorCount(); |
| 959 LoopInfo* info = &loops[block->loop_end_]; | 941 LoopInfo* info = &loops[block->loop_end_]; |
| 960 DCHECK(loop != info); | 942 DCHECK(loop != info); |
| 961 if (info->outgoing != NULL && | 943 if (info->outgoing != NULL && |
| 962 outgoing_index < info->outgoing->length()) { | 944 outgoing_index < info->outgoing->length()) { |
| 963 succ = info->outgoing->at(outgoing_index); | 945 succ = info->outgoing->at(outgoing_index); |
| 964 frame->index++; | 946 frame->index++; |
| 965 } | 947 } |
| 966 } | 948 } |
| 967 | 949 |
| 968 if (succ != NULL) { | 950 if (succ != NULL) { |
| 969 // Process the next successor. | 951 // Process the next successor. |
| 970 if (succ->rpo_number_ == kBlockOnStack) continue; | 952 if (succ->rpo_number_ == kBlockOnStack) continue; |
| 971 if (succ->rpo_number_ == kBlockVisited2) continue; | 953 if (succ->rpo_number_ == kBlockVisited2) continue; |
| 972 DCHECK(succ->rpo_number_ == kBlockUnvisited2); | 954 DCHECK(succ->rpo_number_ == kBlockUnvisited2); |
| 973 if (loop != NULL && !loop->members->Contains(succ->id())) { | 955 if (loop != NULL && !loop->members->Contains(succ->id())) { |
| 974 // The successor is not in the current loop or any nested loop. | 956 // The successor is not in the current loop or any nested loop. |
| 975 // Add it to the outgoing edges of this loop and visit it later. | 957 // Add it to the outgoing edges of this loop and visit it later. |
| 976 loop->AddOutgoing(zone_, succ); | 958 loop->AddOutgoing(zone, succ); |
| 977 } else { | 959 } else { |
| 978 // Push the successor onto the stack. | 960 // Push the successor onto the stack. |
| 979 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2); | 961 stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2); |
| 980 if (succ->IsLoopHeader()) { | 962 if (succ->IsLoopHeader()) { |
| 981 // Push the inner loop onto the loop stack. | 963 // Push the inner loop onto the loop stack. |
| 982 DCHECK(succ->loop_end_ >= 0 && succ->loop_end_ < num_loops); | 964 DCHECK(succ->loop_end_ >= 0 && succ->loop_end_ < num_loops); |
| 983 LoopInfo* next = &loops[succ->loop_end_]; | 965 LoopInfo* next = &loops[succ->loop_end_]; |
| 984 next->end = order; | 966 next->end = order; |
| 985 next->prev = loop; | 967 next->prev = loop; |
| 986 loop = next; | 968 loop = next; |
| 987 } | 969 } |
| 988 } | 970 } |
| 989 } else { | 971 } else { |
| 990 // Finished with all successors of the current block. | 972 // Finished with all successors of the current block. |
| 991 if (block->IsLoopHeader()) { | 973 if (block->IsLoopHeader()) { |
| 992 // If we are going to pop a loop header, then add its entire body. | 974 // If we are going to pop a loop header, then add its entire body. |
| 993 LoopInfo* info = &loops[block->loop_end_]; | 975 LoopInfo* info = &loops[block->loop_end_]; |
| 994 for (BlockList* l = info->start; true; l = l->next) { | 976 for (BlockList* l = info->start; true; l = l->next) { |
| 995 if (l->next == info->end) { | 977 if (l->next == info->end) { |
| 996 l->next = order; | 978 l->next = order; |
| 997 info->end = order; | 979 info->end = order; |
| 998 break; | 980 break; |
| 999 } | 981 } |
| 1000 } | 982 } |
| 1001 order = info->start; | 983 order = info->start; |
| 1002 } else { | 984 } else { |
| 1003 // Pop a single node off the stack and add it to the order. | 985 // Pop a single node off the stack and add it to the order. |
| 1004 order = order->Add(zone_, block); | 986 order = order->Add(zone, block); |
| 1005 block->rpo_number_ = kBlockVisited2; | 987 block->rpo_number_ = kBlockVisited2; |
| 1006 } | 988 } |
| 1007 stack_depth--; | 989 stack_depth--; |
| 1008 } | 990 } |
| 1009 } | 991 } |
| 1010 } | 992 } |
| 1011 | 993 |
| 1012 // Construct the final order from the list. | 994 // Construct the final order from the list. |
| 1013 BasicBlockVector* final_order = &schedule_->rpo_order_; | 995 BasicBlockVector* final_order = &schedule->rpo_order_; |
| 1014 order->Serialize(final_order); | 996 order->Serialize(final_order); |
| 1015 | 997 |
| 1016 // Compute the correct loop header for every block and set the correct loop | 998 // Compute the correct loop header for every block and set the correct loop |
| 1017 // ends. | 999 // ends. |
| 1018 LoopInfo* current_loop = NULL; | 1000 LoopInfo* current_loop = NULL; |
| 1019 BasicBlock* current_header = NULL; | 1001 BasicBlock* current_header = NULL; |
| 1020 int loop_depth = 0; | 1002 int loop_depth = 0; |
| 1021 for (BasicBlockVectorIter i = final_order->begin(); i != final_order->end(); | 1003 for (BasicBlockVectorIter i = final_order->begin(); i != final_order->end(); |
| 1022 ++i) { | 1004 ++i) { |
| 1023 BasicBlock* current = *i; | 1005 BasicBlock* current = *i; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 | 1040 |
| 1059 #if DEBUG | 1041 #if DEBUG |
| 1060 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); | 1042 if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order); |
| 1061 VerifySpecialRPO(num_loops, loops, final_order); | 1043 VerifySpecialRPO(num_loops, loops, final_order); |
| 1062 #endif | 1044 #endif |
| 1063 return final_order; | 1045 return final_order; |
| 1064 } | 1046 } |
| 1065 } | 1047 } |
| 1066 } | 1048 } |
| 1067 } // namespace v8::internal::compiler | 1049 } // namespace v8::internal::compiler |
| OLD | NEW |