OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph.h" | 5 #include "vm/flow_graph.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 current_ssa_temp_index_(0), | 23 current_ssa_temp_index_(0), |
24 max_block_id_(max_block_id), | 24 max_block_id_(max_block_id), |
25 parsed_function_(builder.parsed_function()), | 25 parsed_function_(builder.parsed_function()), |
26 num_copied_params_(builder.num_copied_params()), | 26 num_copied_params_(builder.num_copied_params()), |
27 num_non_copied_params_(builder.num_non_copied_params()), | 27 num_non_copied_params_(builder.num_non_copied_params()), |
28 num_stack_locals_(builder.num_stack_locals()), | 28 num_stack_locals_(builder.num_stack_locals()), |
29 graph_entry_(graph_entry), | 29 graph_entry_(graph_entry), |
30 preorder_(), | 30 preorder_(), |
31 postorder_(), | 31 postorder_(), |
32 reverse_postorder_(), | 32 reverse_postorder_(), |
33 exits_(NULL) { | 33 exits_(NULL), |
| 34 invalid_dominator_tree_(true) { |
34 DiscoverBlocks(); | 35 DiscoverBlocks(); |
35 } | 36 } |
36 | 37 |
37 | 38 |
38 void FlowGraph::DiscoverBlocks() { | 39 void FlowGraph::DiscoverBlocks() { |
39 // Initialize state. | 40 // Initialize state. |
40 preorder_.Clear(); | 41 preorder_.Clear(); |
41 postorder_.Clear(); | 42 postorder_.Clear(); |
42 reverse_postorder_.Clear(); | 43 reverse_postorder_.Clear(); |
43 parent_.Clear(); | 44 parent_.Clear(); |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 | 298 |
298 // Compute immediate dominators and the dominance frontier for each basic | 299 // Compute immediate dominators and the dominance frontier for each basic |
299 // block. As a side effect of the algorithm, sets the immediate dominator | 300 // block. As a side effect of the algorithm, sets the immediate dominator |
300 // of each basic block. | 301 // of each basic block. |
301 // | 302 // |
302 // dominance_frontier: an output parameter encoding the dominance frontier. | 303 // dominance_frontier: an output parameter encoding the dominance frontier. |
303 // The array maps the preorder block number of a block to the set of | 304 // The array maps the preorder block number of a block to the set of |
304 // (preorder block numbers of) blocks in the dominance frontier. | 305 // (preorder block numbers of) blocks in the dominance frontier. |
305 void FlowGraph::ComputeDominators( | 306 void FlowGraph::ComputeDominators( |
306 GrowableArray<BitVector*>* dominance_frontier) { | 307 GrowableArray<BitVector*>* dominance_frontier) { |
| 308 invalid_dominator_tree_ = false; |
307 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass | 309 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass |
308 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) | 310 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) |
309 // that eliminates a pass by using nearest-common ancestor (NCA) to | 311 // that eliminates a pass by using nearest-common ancestor (NCA) to |
310 // compute immediate dominators from semidominators. It also removes a | 312 // compute immediate dominators from semidominators. It also removes a |
311 // level of indirection in the link-eval forest data structure. | 313 // level of indirection in the link-eval forest data structure. |
312 // | 314 // |
313 // The algorithm is described in Georgiadis, Tarjan, and Werneck's | 315 // The algorithm is described in Georgiadis, Tarjan, and Werneck's |
314 // "Finding Dominators in Practice". | 316 // "Finding Dominators in Practice". |
315 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . | 317 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . |
316 | 318 |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 const char* function_name = parsed_function_.function().ToCString(); | 719 const char* function_name = parsed_function_.function().ToCString(); |
718 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 720 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
719 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 721 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
720 OS::SNPrint(chars, len, kFormat, function_name, reason); | 722 OS::SNPrint(chars, len, kFormat, function_name, reason); |
721 const Error& error = Error::Handle( | 723 const Error& error = Error::Handle( |
722 LanguageError::New(String::Handle(String::New(chars)))); | 724 LanguageError::New(String::Handle(String::New(chars)))); |
723 Isolate::Current()->long_jump_base()->Jump(1, error); | 725 Isolate::Current()->long_jump_base()->Jump(1, error); |
724 } | 726 } |
725 | 727 |
726 | 728 |
727 // Helper to reorder phis after splitting a block. The last instruction(s) of | 729 // Helper to replace a predecessor block. For each successor of 'old_block', the |
728 // the split block will now have a larger block id than any previously known | 730 // predecessors will be reordered to preserve block-order sorting of the |
729 // blocks. If the last instruction jumps to a join, we must reorder phi inputs | 731 // predecessors as well as the phis if the successor is a join. |
730 // according to the block order, ie, we move this predecessor to the end. | 732 void FlowGraph::ReplacePredecessor(BlockEntryInstr* old_block, |
731 static void ReorderPhis(BlockEntryInstr* block) { | 733 BlockEntryInstr* new_block) { |
732 GotoInstr* jump = block->last_instruction()->AsGoto(); | 734 // Set the last instruction of the new block to that of the old block. |
733 if (jump == NULL) return; | 735 Instruction* last = old_block->last_instruction(); |
734 JoinEntryInstr* join = jump->successor(); | 736 new_block->set_last_instruction(last); |
735 intptr_t pred_index = join->IndexOfPredecessor(block); | 737 // For each successor, update the predecessors. |
736 intptr_t pred_count = join->PredecessorCount(); | 738 for (intptr_t sidx = 0; sidx < last->SuccessorCount(); ++sidx) { |
737 ASSERT(pred_index >= 0); | 739 // If the successor is a target, update its predecessor. |
738 ASSERT(pred_index < pred_count); | 740 TargetEntryInstr* target = last->SuccessorAt(sidx)->AsTargetEntry(); |
739 // If the predecessor index is the last index there is nothing to update. | 741 if (target != NULL) { |
740 if ((join->phis() == NULL) || (pred_index + 1 == pred_count)) return; | 742 target->predecessor_ = new_block; |
741 // Otherwise, move the predecessor use to the end in each phi. | 743 continue; |
742 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
743 PhiInstr* phi = (*join->phis())[i]; | |
744 if (phi == NULL) continue; | |
745 ASSERT(pred_count == phi->InputCount()); | |
746 // Save the predecessor use. | |
747 Value* pred_use = phi->InputAt(pred_index); | |
748 // Move each of the following uses back by one. | |
749 ASSERT(pred_index < pred_count - 1); // Will move at least one index. | |
750 for (intptr_t i = pred_index; i < pred_count - 1; ++i) { | |
751 Value* use = phi->InputAt(i + 1); | |
752 phi->SetInputAt(i, use); | |
753 use->set_use_index(i); | |
754 } | 744 } |
755 // Write the predecessor use at the end. | 745 // If the successor is a join, update each predecessor and the phis. |
756 phi->SetInputAt(pred_count - 1, pred_use); | 746 JoinEntryInstr* join = last->SuccessorAt(sidx)->AsJoinEntry(); |
757 pred_use->set_use_index(pred_count - 1); | 747 ASSERT(join != NULL); |
| 748 // Find the old predecessor index. |
| 749 intptr_t old_index = join->IndexOfPredecessor(old_block); |
| 750 intptr_t pred_count = join->PredecessorCount(); |
| 751 ASSERT(old_index >= 0); |
| 752 ASSERT(old_index < pred_count); |
| 753 // Find the new predecessor index while reordering the predecessors. |
| 754 intptr_t new_id = new_block->block_id(); |
| 755 intptr_t new_index = old_index; |
| 756 if (old_block->block_id() < new_id) { |
| 757 // Search upwards, bubbling down intermediate predecessors. |
| 758 for (; new_index < pred_count - 1; ++new_index) { |
| 759 if (join->predecessors_[new_index + 1]->block_id() > new_id) break; |
| 760 join->predecessors_[new_index] = join->predecessors_[new_index + 1]; |
| 761 } |
| 762 } else { |
| 763 // Search downwards, bubbling up intermediate predecessors. |
| 764 for (; new_index > 0; --new_index) { |
| 765 if (join->predecessors_[new_index - 1]->block_id() < new_id) break; |
| 766 join->predecessors_[new_index] = join->predecessors_[new_index - 1]; |
| 767 } |
| 768 } |
| 769 join->predecessors_[new_index] = new_block; |
| 770 // If the new and old predecessor index match there is nothing to update. |
| 771 if ((join->phis() == NULL) || (old_index == new_index)) return; |
| 772 // Otherwise, reorder the predecessor uses in each phi. |
| 773 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 774 PhiInstr* phi = (*join->phis())[i]; |
| 775 if (phi == NULL) continue; |
| 776 ASSERT(pred_count == phi->InputCount()); |
| 777 // Save the predecessor use. |
| 778 Value* pred_use = phi->InputAt(old_index); |
| 779 // Move uses between old and new. |
| 780 intptr_t step = (old_index < new_index) ? 1 : -1; |
| 781 for (intptr_t use_idx = old_index; |
| 782 use_idx != new_index; |
| 783 use_idx += step) { |
| 784 Value* use = phi->InputAt(use_idx + step); |
| 785 phi->SetInputAt(use_idx, use); |
| 786 use->set_use_index(use_idx); |
| 787 } |
| 788 // Write the predecessor use. |
| 789 phi->SetInputAt(new_index, pred_use); |
| 790 pred_use->set_use_index(new_index); |
| 791 } |
758 } | 792 } |
759 } | 793 } |
760 | 794 |
761 | 795 |
762 // Helper to sort a list of blocks. | 796 // Helper to sort a list of blocks. |
763 static int LowestBlockIdFirst(BlockEntryInstr* const* a, | 797 static int LowestBlockIdFirst(BlockEntryInstr* const* a, |
764 BlockEntryInstr* const* b) { | 798 BlockEntryInstr* const* b) { |
765 return (*a)->block_id() - (*b)->block_id(); | 799 return (*a)->block_id() - (*b)->block_id(); |
766 } | 800 } |
767 | 801 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 if (callee_exits->is_empty()) { | 846 if (callee_exits->is_empty()) { |
813 // TODO(zerny): Add support for non-local exits, such as throw. | 847 // TODO(zerny): Add support for non-local exits, such as throw. |
814 UNREACHABLE(); | 848 UNREACHABLE(); |
815 } else if (callee_exits->length() == 1) { | 849 } else if (callee_exits->length() == 1) { |
816 ReturnInstr* exit = (*callee_exits)[0]; | 850 ReturnInstr* exit = (*callee_exits)[0]; |
817 ASSERT(exit->previous() != NULL); | 851 ASSERT(exit->previous() != NULL); |
818 // For just one exit, replace the uses and remove the call from the graph. | 852 // For just one exit, replace the uses and remove the call from the graph. |
819 call->ReplaceUsesWith(exit->value()->definition()); | 853 call->ReplaceUsesWith(exit->value()->definition()); |
820 call->previous()->LinkTo(callee_entry->next()); | 854 call->previous()->LinkTo(callee_entry->next()); |
821 exit->previous()->LinkTo(call->next()); | 855 exit->previous()->LinkTo(call->next()); |
822 // In case of control flow, locally update the dominator tree. | 856 // In case of control flow, locally update the predecessors, phis and |
| 857 // dominator tree. |
| 858 // TODO(zerny): should we leave the dominator tree since we recompute it |
| 859 // after a full inlining pass? |
823 if (callee_graph->preorder().length() > 2) { | 860 if (callee_graph->preorder().length() > 2) { |
824 // The caller block is split and the new block id is that of the exit | 861 BlockEntryInstr* exit_block = exit->GetBlock(); |
825 // block. If the caller block had outgoing edges, reorder the phis so they | 862 // Pictorially, the graph structure is: |
826 // are still ordered by block id. | 863 // |
827 ReorderPhis(caller_entry); | 864 // Bc : caller_entry Bi : callee_entry |
828 // The callee return is now the immediate dominator of blocks whose | 865 // before_call inlined_head |
| 866 // call ... other blocks ... |
| 867 // after_call Be : exit_block |
| 868 // inlined_foot |
| 869 // And becomes: |
| 870 // |
| 871 // Bc : caller_entry |
| 872 // before_call |
| 873 // inlined_head |
| 874 // ... other blocks ... |
| 875 // Be : exit_block |
| 876 // inlined_foot |
| 877 // after_call |
| 878 // |
| 879 // For 'after_call', caller entry (Bc) is replaced by callee exit (Be). |
| 880 ReplacePredecessor(caller_entry, exit_block); |
| 881 // For 'inlined_head', callee entry (Bi) is replaced by caller entry (Bc). |
| 882 ReplacePredecessor(callee_entry, caller_entry); |
| 883 // The callee exit is now the immediate dominator of blocks whose |
829 // immediate dominator was the caller entry. | 884 // immediate dominator was the caller entry. |
830 BlockEntryInstr* exit_block = exit->GetBlock(); | |
831 ASSERT(exit_block->dominated_blocks().is_empty()); | 885 ASSERT(exit_block->dominated_blocks().is_empty()); |
832 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) { | 886 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) { |
833 BlockEntryInstr* block = caller_entry->dominated_blocks()[i]; | 887 BlockEntryInstr* block = caller_entry->dominated_blocks()[i]; |
834 block->set_dominator(exit_block); | 888 block->set_dominator(exit_block); |
835 exit_block->AddDominatedBlock(block); | 889 exit_block->AddDominatedBlock(block); |
836 } | 890 } |
837 // The caller entry is now the immediate dominator of blocks whose | 891 // The caller entry is now the immediate dominator of blocks whose |
838 // immediate dominator was the callee entry. | 892 // immediate dominator was the callee entry. |
839 caller_entry->ClearDominatedBlocks(); | 893 caller_entry->ClearDominatedBlocks(); |
840 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { | 894 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { |
841 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; | 895 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; |
842 block->set_dominator(caller_entry); | 896 block->set_dominator(caller_entry); |
843 caller_entry->AddDominatedBlock(block); | 897 caller_entry->AddDominatedBlock(block); |
844 } | 898 } |
845 // Recompute the block orders. | |
846 DiscoverBlocks(); | |
847 } | 899 } |
848 } else { | 900 } else { |
849 // Sort the list of exits by block id. | 901 // Sort the list of exits by block id. |
850 GrowableArray<BlockEntryInstr*> exits(callee_exits->length()); | 902 GrowableArray<BlockEntryInstr*> exits(callee_exits->length()); |
851 for (intptr_t i = 0; i < callee_exits->length(); ++i) { | 903 for (intptr_t i = 0; i < callee_exits->length(); ++i) { |
852 exits.Add((*callee_exits)[i]->GetBlock()); | 904 exits.Add((*callee_exits)[i]->GetBlock()); |
853 } | 905 } |
854 exits.Sort(LowestBlockIdFirst); | 906 exits.Sort(LowestBlockIdFirst); |
855 // Create a join of the returns. | 907 // Create a join of the returns. |
856 JoinEntryInstr* join = | 908 JoinEntryInstr* join = |
(...skipping 19 matching lines...) Expand all Loading... |
876 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn(); | 928 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn(); |
877 ASSERT(exit_instr != NULL); | 929 ASSERT(exit_instr != NULL); |
878 Value* use = exit_instr->value(); | 930 Value* use = exit_instr->value(); |
879 phi->SetInputAt(i, use); | 931 phi->SetInputAt(i, use); |
880 use->set_instruction(phi); | 932 use->set_instruction(phi); |
881 use->set_use_index(i); | 933 use->set_use_index(i); |
882 } | 934 } |
883 // Replace uses of the call with the phi. | 935 // Replace uses of the call with the phi. |
884 call->ReplaceUsesWith(phi); | 936 call->ReplaceUsesWith(phi); |
885 } | 937 } |
886 // Remove the call from the graph. | 938 // Remove the call from the graph. |
887 call->previous()->LinkTo(callee_entry->next()); | 939 call->previous()->LinkTo(callee_entry->next()); |
888 join->LinkTo(call->next()); | 940 join->LinkTo(call->next()); |
889 // The caller block is split and the new block id is that of the join | 941 // Replace the blocks after splitting (see comment in the len=1 case above). |
890 // block. If the caller block had outgoing edges, reorder the phis so they | 942 ReplacePredecessor(caller_entry, join); |
891 // are still ordered by block id. | 943 ReplacePredecessor(callee_entry, caller_entry); |
892 ReorderPhis(caller_entry); | 944 // Update the last instruction pointers on each exit (ie, to the new goto). |
893 // Adjust pre/post orders and update the dominator tree. | 945 for (intptr_t i = 0; i < exits.length(); ++i) { |
894 DiscoverBlocks(); | 946 exits[i]->set_last_instruction( |
| 947 exits[i]->last_instruction()->previous()->next()); |
| 948 } |
| 949 // Mark that the dominator tree is invalid. |
895 // TODO(zerny): Compute the dominator frontier locally. | 950 // TODO(zerny): Compute the dominator frontier locally. |
| 951 invalid_dominator_tree_ = true; |
| 952 } |
| 953 } |
| 954 |
| 955 |
| 956 void FlowGraph::RepairGraphAfterInlining() { |
| 957 DiscoverBlocks(); |
| 958 if (invalid_dominator_tree_) { |
896 GrowableArray<BitVector*> dominance_frontier; | 959 GrowableArray<BitVector*> dominance_frontier; |
897 ComputeDominators(&dominance_frontier); | 960 ComputeDominators(&dominance_frontier); |
898 } | 961 } |
899 } | 962 } |
900 | 963 |
901 | 964 |
902 intptr_t FlowGraph::InstructionCount() const { | 965 intptr_t FlowGraph::InstructionCount() const { |
903 intptr_t size = 0; | 966 intptr_t size = 0; |
904 // Iterate each block, skipping the graph entry. | 967 // Iterate each block, skipping the graph entry. |
905 for (intptr_t i = 1; i < preorder_.length(); ++i) { | 968 for (intptr_t i = 1; i < preorder_.length(); ++i) { |
906 for (ForwardInstructionIterator it(preorder_[i]); | 969 for (ForwardInstructionIterator it(preorder_[i]); |
907 !it.Done(); | 970 !it.Done(); |
908 it.Advance()) { | 971 it.Advance()) { |
909 ++size; | 972 ++size; |
910 } | 973 } |
911 } | 974 } |
912 return size; | 975 return size; |
913 } | 976 } |
914 | 977 |
915 | 978 |
916 } // namespace dart | 979 } // namespace dart |
OLD | NEW |