Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: runtime/vm/flow_graph.cc

Issue 11092102: Avoid rediscovering blocks on each call to FlowGraph::InlineCall. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: comments Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698