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

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: 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 401 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 const char* function_name = parsed_function_.function().ToCString(); 720 const char* function_name = parsed_function_.function().ToCString();
719 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 721 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
720 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 722 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
721 OS::SNPrint(chars, len, kFormat, function_name, reason); 723 OS::SNPrint(chars, len, kFormat, function_name, reason);
722 const Error& error = Error::Handle( 724 const Error& error = Error::Handle(
723 LanguageError::New(String::Handle(String::New(chars)))); 725 LanguageError::New(String::Handle(String::New(chars))));
724 Isolate::Current()->long_jump_base()->Jump(1, error); 726 Isolate::Current()->long_jump_base()->Jump(1, error);
725 } 727 }
726 728
727 729
728 // Helper to reorder phis after splitting a block. The last instruction(s) of 730 // Helper to reorder predecessors and phis after splitting a block. For each
Kevin Millikin (Google) 2012/10/22 09:10:37 Comment needs some updating---it's no longer calle
zerny-google 2012/10/22 13:21:31 Done.
729 // the split block will now have a larger block id than any previously known 731 // successor of 'old_block', the predecessors will be reordered to preserve
730 // blocks. If the last instruction jumps to a join, we must reorder phi inputs 732 // block order sorting. If the successor is a join, also the phi inputs will be
731 // according to the block order, ie, we move this predecessor to the end. 733 // updated.
732 static void ReorderPhis(BlockEntryInstr* block) { 734 // Prerequisite: the last-instruction pointers must not have been updated yet.
733 GotoInstr* jump = block->last_instruction()->AsGoto(); 735 void FlowGraph::ReorderPredecessors(BlockEntryInstr* old_block,
Kevin Millikin (Google) 2012/10/22 09:10:37 I find the naming and emphasis (on reordering) a b
zerny-google 2012/10/22 13:21:31 I renamed it to ReplaceBlock, but that is not enti
736 BlockEntryInstr* new_block) {
737 // If the last instruction is a branch, update the predecessor of the targets.
738 BranchInstr* branch = old_block->last_instruction()->AsBranch();
Kevin Millikin (Google) 2012/10/22 09:10:37 It doesn't make a huge difference, but this code c
zerny-google 2012/10/22 13:21:31 Done.
739 if (branch != NULL) {
740 for (intptr_t i = 0; i < branch->SuccessorCount(); ++i) {
741 TargetEntryInstr* target = branch->SuccessorAt(i)->AsTargetEntry();
742 ASSERT(target != NULL);
743 target->predecessor_ = new_block;
744 }
745 return;
746 }
747 // If the last instruction is a jump, update the join's predecessors and phis.
748 GotoInstr* jump = old_block->last_instruction()->AsGoto();
734 if (jump == NULL) return; 749 if (jump == NULL) return;
750 // Find the old predecessor index
735 JoinEntryInstr* join = jump->successor(); 751 JoinEntryInstr* join = jump->successor();
736 intptr_t pred_index = join->IndexOfPredecessor(block); 752 intptr_t pred_index = join->IndexOfPredecessor(old_block);
737 intptr_t pred_count = join->PredecessorCount(); 753 intptr_t pred_count = join->PredecessorCount();
738 ASSERT(pred_index >= 0); 754 ASSERT(pred_index >= 0);
739 ASSERT(pred_index < pred_count); 755 ASSERT(pred_index < pred_count);
740 // If the predecessor index is the last index there is nothing to update. 756 // Find the new predecessor index
Kevin Millikin (Google) 2012/10/22 09:10:37 It seems like we could do the search and move in t
zerny-google 2012/10/22 13:21:31 Done.
741 if ((join->phis() == NULL) || (pred_index + 1 == pred_count)) return; 757 intptr_t new_block_id = new_block->block_id();
742 // Otherwise, move the predecessor use to the end in each phi. 758 intptr_t new_pred_index = -1;
Kevin Millikin (Google) 2012/10/22 09:10:37 Is it simpler to understand this if you shift the
zerny-google 2012/10/22 13:21:31 No longer an issue with the new "find predecessor
759 while (new_pred_index < pred_count - 1) {
760 ++new_pred_index;
761 if (join->predecessors_[new_pred_index]->block_id() > new_block_id) break;
762 }
763 // Reorder the predecessors of the join.
764 intptr_t step = (new_pred_index > pred_index) ? 1 : -1;
765 intptr_t i = pred_index;
766 while (i != new_pred_index) {
zerny-google 2012/10/12 11:52:05 I'll rewrite this to a for loop again (still using
767 join->predecessors_[i] = join->predecessors_[i + step];
768 i += step;
769 }
770 join->predecessors_[new_pred_index] = new_block;
771 // If the new and old predecessor index match there is nothing to update.
772 if ((join->phis() == NULL) || (pred_index == new_pred_index)) return;
Kevin Millikin (Google) 2012/10/22 09:10:37 Can't you can skip the reordering of the predecess
zerny-google 2012/10/22 13:21:31 No, we still need to write the new_block at the ne
773 // Otherwise, reorder the predecessor uses in each phi.
743 for (intptr_t i = 0; i < join->phis()->length(); ++i) { 774 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
744 PhiInstr* phi = (*join->phis())[i]; 775 PhiInstr* phi = (*join->phis())[i];
745 if (phi == NULL) continue; 776 if (phi == NULL) continue;
746 ASSERT(pred_count == phi->InputCount()); 777 ASSERT(pred_count == phi->InputCount());
747 // Save the predecessor use. 778 // Save the predecessor use.
748 Value* pred_use = phi->InputAt(pred_index); 779 Value* pred_use = phi->InputAt(pred_index);
749 // Move each of the following uses back by one. 780 // Move uses between old and new.
750 ASSERT(pred_index < pred_count - 1); // Will move at least one index. 781 intptr_t use_idx = pred_index;
751 for (intptr_t i = pred_index; i < pred_count - 1; ++i) { 782 while (use_idx != new_pred_index) {
zerny-google 2012/10/12 11:52:05 I'll rewrite this to a for loop again (still using
752 Value* use = phi->InputAt(i + 1); 783 Value* use = phi->InputAt(use_idx + step);
753 phi->SetInputAt(i, use); 784 phi->SetInputAt(use_idx, use);
754 use->set_use_index(i); 785 use->set_use_index(use_idx);
786 use_idx += step;
755 } 787 }
756 // Write the predecessor use at the end. 788 // Write the predecessor use.
757 phi->SetInputAt(pred_count - 1, pred_use); 789 phi->SetInputAt(new_pred_index, pred_use);
758 pred_use->set_use_index(pred_count - 1); 790 pred_use->set_use_index(new_pred_index);
759 } 791 }
760 } 792 }
761 793
762 794
763 // Helper to sort a list of blocks. 795 // Helper to sort a list of blocks.
764 static int LowestBlockIdFirst(BlockEntryInstr* const* a, 796 static int LowestBlockIdFirst(BlockEntryInstr* const* a,
765 BlockEntryInstr* const* b) { 797 BlockEntryInstr* const* b) {
766 return (*a)->block_id() - (*b)->block_id(); 798 return (*a)->block_id() - (*b)->block_id();
767 } 799 }
768 800
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
813 if (callee_exits->is_empty()) { 845 if (callee_exits->is_empty()) {
814 // TODO(zerny): Add support for non-local exits, such as throw. 846 // TODO(zerny): Add support for non-local exits, such as throw.
815 UNREACHABLE(); 847 UNREACHABLE();
816 } else if (callee_exits->length() == 1) { 848 } else if (callee_exits->length() == 1) {
817 ReturnInstr* exit = (*callee_exits)[0]; 849 ReturnInstr* exit = (*callee_exits)[0];
818 ASSERT(exit->previous() != NULL); 850 ASSERT(exit->previous() != NULL);
819 // For just one exit, replace the uses and remove the call from the graph. 851 // For just one exit, replace the uses and remove the call from the graph.
820 call->ReplaceUsesWith(exit->value()->definition()); 852 call->ReplaceUsesWith(exit->value()->definition());
821 call->previous()->LinkTo(callee_entry->next()); 853 call->previous()->LinkTo(callee_entry->next());
822 exit->previous()->LinkTo(call->next()); 854 exit->previous()->LinkTo(call->next());
823 // In case of control flow, locally update the dominator tree. 855 // In case of control flow, locally update the predecessors, phis and
856 // dominator tree.
857 // TODO(zerny): should we leave the dominator tree since we recompute it
858 // after a full inlining pass.
824 if (callee_graph->preorder().length() > 2) { 859 if (callee_graph->preorder().length() > 2) {
825 // The caller block is split and the new block id is that of the exit 860 BlockEntryInstr* exit_block = exit->GetBlock();
826 // block. If the caller block had outgoing edges, reorder the phis so they 861 // The caller block is split and the predecessors might need reordering.
Kevin Millikin (Google) 2012/10/22 09:10:37 'the predecessors' is unclear. "The caller block
zerny-google 2012/10/22 13:21:31 Done.
827 // are still ordered by block id. 862 // The caller entry becomes the block of the callee entry block.
Kevin Millikin (Google) 2012/10/22 09:10:37 I don't think I understand this comment at all :)
zerny-google 2012/10/22 13:21:31 Done.
828 ReorderPhis(caller_entry); 863 ReorderPredecessors(callee_entry, caller_entry);
864 // The callee exit block becomes the block of the caller entry block.
865 ReorderPredecessors(caller_entry, exit_block);
829 // The callee return is now the immediate dominator of blocks whose 866 // The callee return is now the immediate dominator of blocks whose
830 // immediate dominator was the caller entry. 867 // immediate dominator was the caller entry.
831 BlockEntryInstr* exit_block = exit->GetBlock();
832 ASSERT(exit_block->dominated_blocks().is_empty()); 868 ASSERT(exit_block->dominated_blocks().is_empty());
833 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) { 869 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) {
834 BlockEntryInstr* block = caller_entry->dominated_blocks()[i]; 870 BlockEntryInstr* block = caller_entry->dominated_blocks()[i];
835 block->set_dominator(exit_block); 871 block->set_dominator(exit_block);
836 exit_block->AddDominatedBlock(block); 872 exit_block->AddDominatedBlock(block);
837 } 873 }
838 // The caller entry is now the immediate dominator of blocks whose 874 // The caller entry is now the immediate dominator of blocks whose
839 // immediate dominator was the callee entry. 875 // immediate dominator was the callee entry.
840 caller_entry->ClearDominatedBlocks(); 876 caller_entry->ClearDominatedBlocks();
841 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { 877 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
842 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; 878 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
843 block->set_dominator(caller_entry); 879 block->set_dominator(caller_entry);
844 caller_entry->AddDominatedBlock(block); 880 caller_entry->AddDominatedBlock(block);
845 } 881 }
846 // Recompute the block orders. 882 // Update the last-instruction pointers.
847 DiscoverBlocks(); 883 exit_block->set_last_instruction(caller_entry->last_instruction());
Kevin Millikin (Google) 2012/10/22 09:10:37 It seems like this could also be moved into Reorde
zerny-google 2012/10/22 13:21:31 Done.
884 caller_entry->set_last_instruction(callee_entry->last_instruction());
848 } 885 }
849 } else { 886 } else {
850 // Sort the list of exits by block id. 887 // Sort the list of exits by block id.
851 GrowableArray<BlockEntryInstr*> exits(callee_exits->length()); 888 GrowableArray<BlockEntryInstr*> exits(callee_exits->length());
852 for (intptr_t i = 0; i < callee_exits->length(); ++i) { 889 for (intptr_t i = 0; i < callee_exits->length(); ++i) {
853 exits.Add((*callee_exits)[i]->GetBlock()); 890 exits.Add((*callee_exits)[i]->GetBlock());
854 } 891 }
855 exits.Sort(LowestBlockIdFirst); 892 exits.Sort(LowestBlockIdFirst);
856 // Create a join of the returns. 893 // Create a join of the returns.
857 JoinEntryInstr* join = 894 JoinEntryInstr* join =
(...skipping 19 matching lines...) Expand all
877 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn(); 914 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn();
878 ASSERT(exit_instr != NULL); 915 ASSERT(exit_instr != NULL);
879 Value* use = exit_instr->value(); 916 Value* use = exit_instr->value();
880 phi->SetInputAt(i, use); 917 phi->SetInputAt(i, use);
881 use->set_instruction(phi); 918 use->set_instruction(phi);
882 use->set_use_index(i); 919 use->set_use_index(i);
883 } 920 }
884 // Replace uses of the call with the phi. 921 // Replace uses of the call with the phi.
885 call->ReplaceUsesWith(phi); 922 call->ReplaceUsesWith(phi);
886 } 923 }
887 // Remove the call from the graph. 924 // Remove the call from the graph.
888 call->previous()->LinkTo(callee_entry->next()); 925 call->previous()->LinkTo(callee_entry->next());
889 join->LinkTo(call->next()); 926 join->LinkTo(call->next());
890 // The caller block is split and the new block id is that of the join 927 // The caller block is split and the predecessors might need reordering.
891 // block. If the caller block had outgoing edges, reorder the phis so they 928 // The caller entry becomes the block of the callee entry block.
892 // are still ordered by block id. 929 ReorderPredecessors(callee_entry, caller_entry);
893 ReorderPhis(caller_entry); 930 // The join block becomes the block of the caller entry block.
894 // Adjust pre/post orders and update the dominator tree. 931 ReorderPredecessors(caller_entry, join);
895 DiscoverBlocks(); 932 // Update the last instruction pointers.
933 join->set_last_instruction(caller_entry->last_instruction());
934 caller_entry->set_last_instruction(callee_entry->last_instruction());
935 for (intptr_t i = 0; i < exits.length(); ++i) {
936 exits[i]->set_last_instruction(
937 exits[i]->last_instruction()->previous()->next());
938 }
939 // Mark that the dominator tree is invalid.
896 // TODO(zerny): Compute the dominator frontier locally. 940 // TODO(zerny): Compute the dominator frontier locally.
941 invalid_dominator_tree_ = true;
942 }
943 }
944
945
946 void FlowGraph::RepairGraphAfterInlining() {
947 DiscoverBlocks();
948 if (invalid_dominator_tree_) {
897 GrowableArray<BitVector*> dominance_frontier; 949 GrowableArray<BitVector*> dominance_frontier;
898 ComputeDominators(&dominance_frontier); 950 ComputeDominators(&dominance_frontier);
899 } 951 }
900 } 952 }
901 953
902 954
903 intptr_t FlowGraph::InstructionCount() const { 955 intptr_t FlowGraph::InstructionCount() const {
904 intptr_t size = 0; 956 intptr_t size = 0;
905 // Iterate each block, skipping the graph entry. 957 // Iterate each block, skipping the graph entry.
906 for (intptr_t i = 1; i < preorder_.length(); ++i) { 958 for (intptr_t i = 1; i < preorder_.length(); ++i) {
907 for (ForwardInstructionIterator it(preorder_[i]); 959 for (ForwardInstructionIterator it(preorder_[i]);
908 !it.Done(); 960 !it.Done();
909 it.Advance()) { 961 it.Advance()) {
910 ++size; 962 ++size;
911 } 963 }
912 } 964 }
913 return size; 965 return size;
914 } 966 }
915 967
916 968
917 } // namespace dart 969 } // 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