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

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

Issue 11856010: Change the inlining context from an enum to a class. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 11 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
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),
34 invalid_dominator_tree_(true) { 33 invalid_dominator_tree_(true) {
35 DiscoverBlocks(); 34 DiscoverBlocks();
36 } 35 }
37 36
38 37
39 ConstantInstr* FlowGraph::AddConstantToInitialDefinitions( 38 ConstantInstr* FlowGraph::AddConstantToInitialDefinitions(
40 const Object& object) { 39 const Object& object) {
41 // Check if the constant is already in the pool. 40 // Check if the constant is already in the pool.
42 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) { 41 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) {
43 ConstantInstr* constant = 42 ConstantInstr* constant =
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 ValidateUseListsInInstruction(it.Current()); 201 ValidateUseListsInInstruction(it.Current());
203 } 202 }
204 } 203 }
205 return true; // Return true so we can ASSERT validation. 204 return true; // Return true so we can ASSERT validation.
206 } 205 }
207 #endif // DEBUG 206 #endif // DEBUG
208 207
209 208
210 static void ClearUseLists(Definition* defn) { 209 static void ClearUseLists(Definition* defn) {
211 ASSERT(defn != NULL); 210 ASSERT(defn != NULL);
212 ASSERT(defn->input_use_list() == NULL); 211 ASSERT(!defn->HasUses());
213 ASSERT(defn->env_use_list() == NULL);
214 defn->set_input_use_list(NULL); 212 defn->set_input_use_list(NULL);
215 defn->set_env_use_list(NULL); 213 defn->set_env_use_list(NULL);
216 } 214 }
217 215
218 216
219 static void RecordInputUses(Instruction* instr) { 217 static void RecordInputUses(Instruction* instr) {
220 ASSERT(instr != NULL); 218 ASSERT(instr != NULL);
221 for (intptr_t i = 0; i < instr->InputCount(); ++i) { 219 for (intptr_t i = 0; i < instr->InputCount(); ++i) {
222 Value* use = instr->InputAt(i); 220 Value* use = instr->InputAt(i);
223 ASSERT(use->instruction() == NULL); 221 ASSERT(use->instruction() == NULL);
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 use->set_use_index(use_idx); 818 use->set_use_index(use_idx);
821 } 819 }
822 // Write the predecessor use. 820 // Write the predecessor use.
823 phi->SetInputAt(new_index, pred_use); 821 phi->SetInputAt(new_index, pred_use);
824 pred_use->set_use_index(new_index); 822 pred_use->set_use_index(new_index);
825 } 823 }
826 } 824 }
827 } 825 }
828 826
829 827
830 // Helper to sort a list of blocks.
831 static int LowestBlockIdFirst(BlockEntryInstr* const* a,
832 BlockEntryInstr* const* b) {
833 return (*a)->block_id() - (*b)->block_id();
834 }
835
836
837 // Inline a flow graph at a call site. 828 // Inline a flow graph at a call site.
838 // 829 //
839 // Assumes the callee graph was computed by BuildGraph with an inlining context 830 // Assumes the callee graph was computed by BuildGraph with an inlining context
840 // and transformed to SSA with ComputeSSA with a correct virtual register 831 // and transformed to SSA with ComputeSSA with a correct virtual register
841 // number, and that the use lists have been correctly computed. 832 // number, and that the use lists have been correctly computed.
842 // 833 //
843 // After inlining the caller graph will correctly have adjusted the pre/post 834 // After inlining the caller graph will correctly have adjusted the pre/post
844 // orders, the dominator tree and the use lists. 835 // orders, the dominator tree and the use lists.
845 void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) { 836 void FlowGraph::InlineCall(Definition* call,
837 FlowGraph* callee_graph,
838 ValueInliningContext* inlining_context) {
846 ASSERT(call->previous() != NULL); 839 ASSERT(call->previous() != NULL);
847 ASSERT(call->next() != NULL); 840 ASSERT(call->next() != NULL);
848 ASSERT(callee_graph->exits() != NULL);
849 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); 841 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
850 ASSERT(callee_graph->max_block_id() > max_block_id()); 842 ASSERT(callee_graph->max_block_id() > max_block_id());
851 ASSERT(callee_graph->max_virtual_register_number() > 843 ASSERT(callee_graph->max_virtual_register_number() >
852 max_virtual_register_number()); 844 max_virtual_register_number());
853 845
854 // Adjust the max block id to the max block id of the callee graph. 846 // Adjust the max block id to the max block id of the callee graph.
855 max_block_id_ = callee_graph->max_block_id(); 847 max_block_id_ = callee_graph->max_block_id();
856 848
857 // Adjust the SSA temp index by the callee graph's index. 849 // Adjust the SSA temp index by the callee graph's index.
858 current_ssa_temp_index_ = callee_graph->max_virtual_register_number(); 850 current_ssa_temp_index_ = callee_graph->max_virtual_register_number();
859 851
860 BlockEntryInstr* caller_entry = call->GetBlock(); 852 BlockEntryInstr* caller_entry = call->GetBlock();
861 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); 853 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
862 ZoneGrowableArray<ReturnInstr*>* callee_exits = callee_graph->exits();
863 854
864 // Attach the outer environment on each instruction in the callee graph. 855 // Attach the outer environment on each instruction in the callee graph.
865 for (BlockIterator block_it = callee_graph->postorder_iterator(); 856 for (BlockIterator block_it = callee_graph->postorder_iterator();
866 !block_it.Done(); 857 !block_it.Done();
867 block_it.Advance()) { 858 block_it.Advance()) {
868 for (ForwardInstructionIterator it(block_it.Current()); 859 for (ForwardInstructionIterator it(block_it.Current());
869 !it.Done(); 860 !it.Done();
870 it.Advance()) { 861 it.Advance()) {
871 Instruction* instr = it.Current(); 862 Instruction* instr = it.Current();
872 // TODO(zerny): Avoid creating unnecessary environments. Note that some 863 // TODO(zerny): Avoid creating unnecessary environments. Note that some
873 // optimizations need deoptimization info for non-deoptable instructions, 864 // optimizations need deoptimization info for non-deoptable instructions,
874 // eg, LICM on GOTOs. 865 // eg, LICM on GOTOs.
875 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr); 866 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr);
876 } 867 }
877 } 868 }
878 869
879 // Insert the callee graph into the caller graph. 870 // Insert the callee graph into the caller graph. First sort the list of
880 if (callee_exits->is_empty()) { 871 // exits by block id (recording block entries as a side effect).
872 inlining_context->SortExits();
873 if (inlining_context->NumExits() == 0) {
881 // TODO(zerny): Add support for non-local exits, such as throw. 874 // TODO(zerny): Add support for non-local exits, such as throw.
882 UNREACHABLE(); 875 UNREACHABLE();
883 } else if (callee_exits->length() == 1) { 876 } else if (inlining_context->NumExits() == 1) {
884 ReturnInstr* exit = (*callee_exits)[0];
885 ASSERT(exit->previous() != NULL);
886 // For just one exit, replace the uses and remove the call from the graph. 877 // For just one exit, replace the uses and remove the call from the graph.
887 call->ReplaceUsesWith(exit->value()->definition()); 878 call->ReplaceUsesWith(inlining_context->ValueAt(0)->definition());
888 call->previous()->LinkTo(callee_entry->next()); 879 call->previous()->LinkTo(callee_entry->next());
889 exit->previous()->LinkTo(call->next()); 880 inlining_context->LastInstructionAt(0)->LinkTo(call->next());
890 // In case of control flow, locally update the predecessors, phis and 881 // In case of control flow, locally update the predecessors, phis and
891 // dominator tree. 882 // dominator tree.
892 // TODO(zerny): should we leave the dominator tree since we recompute it 883 // TODO(zerny): should we leave the dominator tree since we recompute it
893 // after a full inlining pass? 884 // after a full inlining pass?
894 if (callee_graph->preorder().length() > 2) { 885 if (callee_graph->preorder().length() > 2) {
895 BlockEntryInstr* exit_block = exit->GetBlock(); 886 BlockEntryInstr* exit_block = inlining_context->ExitBlockAt(0);
896 // Pictorially, the graph structure is: 887 // Pictorially, the graph structure is:
897 // 888 //
898 // Bc : caller_entry Bi : callee_entry 889 // Bc : caller_entry Bi : callee_entry
899 // before_call inlined_head 890 // before_call inlined_head
900 // call ... other blocks ... 891 // call ... other blocks ...
901 // after_call Be : exit_block 892 // after_call Be : exit_block
902 // inlined_foot 893 // inlined_foot
903 // And becomes: 894 // And becomes:
904 // 895 //
905 // Bc : caller_entry 896 // Bc : caller_entry
(...skipping 19 matching lines...) Expand all
925 // The caller entry is now the immediate dominator of blocks whose 916 // The caller entry is now the immediate dominator of blocks whose
926 // immediate dominator was the callee entry. 917 // immediate dominator was the callee entry.
927 caller_entry->ClearDominatedBlocks(); 918 caller_entry->ClearDominatedBlocks();
928 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { 919 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
929 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; 920 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
930 block->set_dominator(caller_entry); 921 block->set_dominator(caller_entry);
931 caller_entry->AddDominatedBlock(block); 922 caller_entry->AddDominatedBlock(block);
932 } 923 }
933 } 924 }
934 } else { 925 } else {
935 // Sort the list of exits by block id.
936 GrowableArray<BlockEntryInstr*> exits(callee_exits->length());
937 for (intptr_t i = 0; i < callee_exits->length(); ++i) {
938 exits.Add((*callee_exits)[i]->GetBlock());
939 }
940 exits.Sort(LowestBlockIdFirst);
941 // Create a join of the returns. 926 // Create a join of the returns.
942 JoinEntryInstr* join = 927 JoinEntryInstr* join =
943 new JoinEntryInstr(++max_block_id_, 928 new JoinEntryInstr(++max_block_id_,
944 CatchClauseNode::kInvalidTryIndex, 929 CatchClauseNode::kInvalidTryIndex,
945 caller_entry->loop_depth()); 930 caller_entry->loop_depth());
946 for (intptr_t i = 0; i < exits.length(); ++i) { 931 intptr_t count = inlining_context->NumExits();
947 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn(); 932 for (intptr_t i = 0; i < count; ++i) {
948 ASSERT(exit_instr != NULL); 933 inlining_context->LastInstructionAt(i)->Goto(join);
949 exit_instr->previous()->Goto(join);
950 // Directly add the predecessors of the join in ascending block id order. 934 // Directly add the predecessors of the join in ascending block id order.
951 join->predecessors_.Add(exits[i]); 935 join->predecessors_.Add(inlining_context->ExitBlockAt(i));
952 } 936 }
953 // If the call has uses, create a phi of the returns. 937 // If the call has uses, create a phi of the returns.
954 if ((call->input_use_list() != NULL) || 938 if (call->HasUses()) {
955 (call->env_use_list() != NULL)) {
956 // Environment count: length before call - argument count (+ return) 939 // Environment count: length before call - argument count (+ return)
957 intptr_t env_count = call->env()->Length() - call->ArgumentCount(); 940 intptr_t env_count = call->env()->Length() - call->ArgumentCount();
958 // Add a phi of the return values. 941 // Add a phi of the return values.
959 join->InsertPhi(env_count, env_count + 1); 942 join->InsertPhi(env_count, env_count + 1);
960 PhiInstr* phi = join->phis()->Last(); 943 PhiInstr* phi = join->phis()->Last();
961 phi->set_ssa_temp_index(alloc_ssa_temp_index()); 944 phi->set_ssa_temp_index(alloc_ssa_temp_index());
962 phi->mark_alive(); 945 phi->mark_alive();
963 for (intptr_t i = 0; i < exits.length(); ++i) { 946 for (intptr_t i = 0; i < count; ++i) {
964 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn(); 947 Value* value = inlining_context->ValueAt(i);
965 ASSERT(exit_instr != NULL); 948 phi->SetInputAt(i, value);
966 Value* use = exit_instr->value(); 949 value->set_instruction(phi);
967 phi->SetInputAt(i, use); 950 value->set_use_index(i);
968 use->set_instruction(phi);
969 use->set_use_index(i);
970 } 951 }
971 // Replace uses of the call with the phi. 952 // Replace uses of the call with the phi.
972 call->ReplaceUsesWith(phi); 953 call->ReplaceUsesWith(phi);
973 } 954 }
974 // Remove the call from the graph. 955 // Remove the call from the graph.
975 call->previous()->LinkTo(callee_entry->next()); 956 call->previous()->LinkTo(callee_entry->next());
976 join->LinkTo(call->next()); 957 join->LinkTo(call->next());
977 // Replace the blocks after splitting (see comment in the len=1 case above). 958 // Replace the blocks after splitting (see comment in the len=1 case above).
978 ReplacePredecessor(caller_entry, join); 959 ReplacePredecessor(caller_entry, join);
979 ReplacePredecessor(callee_entry, caller_entry); 960 ReplacePredecessor(callee_entry, caller_entry);
980 // Update the last instruction pointers on each exit (ie, to the new goto). 961 // Update the last instruction pointers on each exit block to the new goto.
981 for (intptr_t i = 0; i < exits.length(); ++i) { 962 for (intptr_t i = 0; i < count; ++i) {
982 exits[i]->set_last_instruction( 963 inlining_context->ExitBlockAt(i)->set_last_instruction(
983 exits[i]->last_instruction()->previous()->next()); 964 inlining_context->LastInstructionAt(i)->next());
984 } 965 }
985 // Mark that the dominator tree is invalid. 966 // Mark that the dominator tree is invalid.
986 // TODO(zerny): Compute the dominator frontier locally. 967 // TODO(zerny): Compute the dominator frontier locally.
987 invalid_dominator_tree_ = true; 968 invalid_dominator_tree_ = true;
988 } 969 }
989 } 970 }
990 971
991 972
992 void FlowGraph::RepairGraphAfterInlining() { 973 void FlowGraph::RepairGraphAfterInlining() {
993 DiscoverBlocks(); 974 DiscoverBlocks();
(...skipping 12 matching lines...) Expand all
1006 !it.Done(); 987 !it.Done();
1007 it.Advance()) { 988 it.Advance()) {
1008 ++size; 989 ++size;
1009 } 990 }
1010 } 991 }
1011 return size; 992 return size;
1012 } 993 }
1013 994
1014 995
1015 } // namespace dart 996 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698