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 11029002: Revert r13022 (revert inlining of methods with control flow), Review URL: https://codereview.chromi… (Closed) Base URL: http://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_builder.h » ('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/assert.h" 7 #include "vm/assert.h"
8 #include "vm/bit_vector.h" 8 #include "vm/bit_vector.h"
9 #include "vm/flow_graph_builder.h" 9 #include "vm/flow_graph_builder.h"
10 #include "vm/intermediate_language.h" 10 #include "vm/intermediate_language.h"
11 #include "vm/longjump.h" 11 #include "vm/longjump.h"
12 #include "vm/growable_array.h" 12 #include "vm/growable_array.h"
13 13
14 namespace dart { 14 namespace dart {
15 15
16 DECLARE_FLAG(bool, trace_optimization); 16 DECLARE_FLAG(bool, trace_optimization);
17 17
18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, 18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder,
19 GraphEntryInstr* graph_entry) 19 GraphEntryInstr* graph_entry,
20 intptr_t max_block_id)
20 : parent_(), 21 : parent_(),
21 assigned_vars_(), 22 assigned_vars_(),
22 current_ssa_temp_index_(0), 23 current_ssa_temp_index_(0),
24 max_block_id_(max_block_id),
23 parsed_function_(builder.parsed_function()), 25 parsed_function_(builder.parsed_function()),
24 num_copied_params_(builder.num_copied_params()), 26 num_copied_params_(builder.num_copied_params()),
25 num_non_copied_params_(builder.num_non_copied_params()), 27 num_non_copied_params_(builder.num_non_copied_params()),
26 num_stack_locals_(builder.num_stack_locals()), 28 num_stack_locals_(builder.num_stack_locals()),
27 graph_entry_(graph_entry), 29 graph_entry_(graph_entry),
28 preorder_(), 30 preorder_(),
29 postorder_(), 31 postorder_(),
30 reverse_postorder_(), 32 reverse_postorder_(),
31 exits_(NULL) { 33 exits_(NULL) {
32 DiscoverBlocks(); 34 DiscoverBlocks();
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 } 526 }
525 } 527 }
526 } 528 }
527 529
528 // 2. Process normal instructions. 530 // 2. Process normal instructions.
529 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { 531 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
530 Instruction* current = it.Current(); 532 Instruction* current = it.Current();
531 // Attach current environment to the instruction. First, each instruction 533 // Attach current environment to the instruction. First, each instruction
532 // gets a full copy of the environment. Later we optimize this by 534 // gets a full copy of the environment. Later we optimize this by
533 // eliminating unnecessary environments. 535 // eliminating unnecessary environments.
536 // TODO(zerny): Avoid creating unnecessary environments. Note that some
537 // optimizations need deoptimization info for non-deoptable instructions,
538 // eg, LICM on GOTOs.
534 current->set_env(Environment::From(*env, 539 current->set_env(Environment::From(*env,
535 num_non_copied_params_, 540 num_non_copied_params_,
536 parsed_function_.function())); 541 parsed_function_.function()));
537 if (current->CanDeoptimize()) { 542 if (current->CanDeoptimize()) {
538 current->env()->set_deopt_id(current->deopt_id()); 543 current->env()->set_deopt_id(current->deopt_id());
539 } 544 }
540 545
541 // 2a. Handle uses: 546 // 2a. Handle uses:
542 // Update expression stack environment for each use. 547 // Update expression stack environment for each use.
543 // For each use of a LoadLocal or StoreLocal: Replace it with the value 548 // For each use of a LoadLocal or StoreLocal: Replace it with the value
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
720 const char* function_name = parsed_function_.function().ToCString(); 725 const char* function_name = parsed_function_.function().ToCString();
721 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 726 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
722 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 727 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
723 OS::SNPrint(chars, len, kFormat, function_name, reason); 728 OS::SNPrint(chars, len, kFormat, function_name, reason);
724 const Error& error = Error::Handle( 729 const Error& error = Error::Handle(
725 LanguageError::New(String::Handle(String::New(chars)))); 730 LanguageError::New(String::Handle(String::New(chars))));
726 Isolate::Current()->long_jump_base()->Jump(1, error); 731 Isolate::Current()->long_jump_base()->Jump(1, error);
727 } 732 }
728 733
729 734
730 // Helper to get the block-entry of an instruction. 735 // Helper to reorder phis after splitting a block. The last instruction(s) of
731 static BlockEntryInstr* GetBlockEntry(Instruction* instr) { 736 // the split block will now have a larger block id than any previously known
732 while (!instr->IsBlockEntry()) instr = instr->previous(); 737 // blocks. If the last instruction jumps to a join, we must reorder phi inputs
733 return instr->AsBlockEntry(); 738 // according to the block order, ie, we move this predecessor to the end.
739 static void ReorderPhis(BlockEntryInstr* block) {
740 GotoInstr* jump = block->last_instruction()->AsGoto();
741 if (jump == NULL) return;
742 JoinEntryInstr* join = jump->successor();
743 intptr_t pred_index = join->IndexOfPredecessor(block);
744 intptr_t pred_count = join->PredecessorCount();
745 ASSERT(pred_index >= 0);
746 ASSERT(pred_index < pred_count);
747 // If the predecessor index is the last index there is nothing to update.
748 if ((join->phis() == NULL) || (pred_index + 1 == pred_count)) return;
749 // Otherwise, move the predecessor use to the end in each phi.
750 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
751 PhiInstr* phi = (*join->phis())[i];
752 if (phi == NULL) continue;
753 ASSERT(pred_count == phi->InputCount());
754 // Save the predecessor use.
755 Value* pred_use = phi->InputAt(pred_index);
756 // Move each of the following uses back by one.
757 ASSERT(pred_index < pred_count - 1); // Will move at least one index.
758 for (intptr_t i = pred_index; i < pred_count - 1; ++i) {
759 Value* use = phi->InputAt(i + 1);
760 phi->SetInputAt(i, use);
761 use->set_use_index(i);
762 }
763 // Write the predecessor use at the end.
764 phi->SetInputAt(pred_count - 1, pred_use);
765 pred_use->set_use_index(pred_count - 1);
766 }
734 } 767 }
735 768
736 769
737 // Helper to link two instructions in the graph. 770 // Helper to link two instructions in the graph.
738 static void Link(Instruction* prev, Instruction* next) { 771 static void Link(Instruction* prev, Instruction* next) {
739 ASSERT(prev != next); 772 ASSERT(prev != next);
740 prev->set_next(next); 773 prev->set_next(next);
741 next->set_previous(prev); 774 next->set_previous(prev);
742 } 775 }
743 776
744 777
778 // Helper to sort a list of blocks.
779 static int LowestBlockIdFirst(BlockEntryInstr* const* a,
780 BlockEntryInstr* const* b) {
781 return (*a)->block_id() - (*b)->block_id();
782 }
783
784
745 // Inline a flow graph at a call site. 785 // Inline a flow graph at a call site.
746 // 786 //
747 // Assumes the callee graph was computed by BuildGraph with an inlining context 787 // Assumes the callee graph was computed by BuildGraph with an inlining context
748 // and transformed to SSA with ComputeSSA with a correct virtual register 788 // and transformed to SSA with ComputeSSA with a correct virtual register
749 // number, and that the use lists have been correctly computed. 789 // number, and that the use lists have been correctly computed.
750 // 790 //
751 // After inlining the caller graph will correctly have adjusted the pre/post 791 // After inlining the caller graph will correctly have adjusted the pre/post
752 // orders, the dominator tree and the use lists. 792 // orders, the dominator tree and the use lists.
753 void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) { 793 void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) {
794 ASSERT(call->previous() != NULL);
795 ASSERT(call->next() != NULL);
754 ASSERT(callee_graph->exits() != NULL); 796 ASSERT(callee_graph->exits() != NULL);
755 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); 797 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
798 ASSERT(callee_graph->max_block_id() > max_block_id());
756 ASSERT(callee_graph->max_virtual_register_number() > 799 ASSERT(callee_graph->max_virtual_register_number() >
757 max_virtual_register_number()); 800 max_virtual_register_number());
758 801
759 // TODO(zerny): Implement support for callee graphs with control flow. 802 // Adjust the max block id to the max block id of the callee graph.
760 ASSERT(callee_graph->preorder().length() == 2); 803 max_block_id_ = callee_graph->max_block_id();
761 804
762 // Adjust the SSA temp index by the callee graph's index. 805 // Adjust the SSA temp index by the callee graph's index.
763 current_ssa_temp_index_ = callee_graph->max_virtual_register_number(); 806 current_ssa_temp_index_ = callee_graph->max_virtual_register_number();
764 807
765 BlockEntryInstr* caller_entry = GetBlockEntry(call); 808 BlockEntryInstr* caller_entry = call->GetBlock();
766 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); 809 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
767 ZoneGrowableArray<ReturnInstr*>* callee_exits = callee_graph->exits(); 810 ZoneGrowableArray<ReturnInstr*>* callee_exits = callee_graph->exits();
768 811
769 // 0. Attach the outer environment on each instruction in the callee graph. 812 // Attach the outer environment on each instruction in the callee graph.
770 for (ForwardInstructionIterator it(callee_entry); !it.Done(); it.Advance()) { 813 for (BlockIterator block_it = callee_graph->postorder_iterator();
771 Instruction* instr = it.Current(); 814 !block_it.Done();
772 if (instr->CanDeoptimize()) call->env()->DeepCopyToOuter(instr); 815 block_it.Advance()) {
816 for (ForwardInstructionIterator it(block_it.Current());
817 !it.Done();
818 it.Advance()) {
819 Instruction* instr = it.Current();
820 // TODO(zerny): Avoid creating unnecessary environments. Note that some
821 // optimizations need deoptimization info for non-deoptable instructions,
822 // eg, LICM on GOTOs.
823 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr);
824 }
773 } 825 }
774 826
775 // 1. Insert the callee graph into the caller graph. 827 // Insert the callee graph into the caller graph.
776 if (callee_exits->is_empty()) { 828 if (callee_exits->is_empty()) {
777 // If no normal exits exist, inline and truncate the block after inlining. 829 // TODO(zerny): Add support for non-local exits, such as throw.
778 Link(call->previous(), callee_entry->next()); 830 UNREACHABLE();
779 caller_entry->set_last_instruction(callee_entry->last_instruction());
780 } else if (callee_exits->length() == 1) { 831 } else if (callee_exits->length() == 1) {
781 ReturnInstr* exit = (*callee_exits)[0]; 832 ReturnInstr* exit = (*callee_exits)[0];
782 // TODO(zerny): Support one exit graph containing control flow. 833 ASSERT(exit->previous() != NULL);
783 ASSERT(callee_entry == GetBlockEntry(exit));
784 // For just one exit, replace the uses and remove the call from the graph. 834 // For just one exit, replace the uses and remove the call from the graph.
785 call->ReplaceUsesWith(exit->value()->definition()); 835 call->ReplaceUsesWith(exit->value()->definition());
786 Link(call->previous(), callee_entry->next()); 836 Link(call->previous(), callee_entry->next());
787 Link(exit->previous(), call->next()); 837 Link(exit->previous(), call->next());
838 // In case of control flow, locally update the dominator tree.
839 if (callee_graph->preorder().length() > 2) {
840 // The caller block is split and the new block id is that of the exit
841 // block. If the caller block had outgoing edges, reorder the phis so they
842 // are still ordered by block id.
843 ReorderPhis(caller_entry);
844 // The callee return is now the immediate dominator of blocks whose
845 // immediate dominator was the caller entry.
846 BlockEntryInstr* exit_block = exit->GetBlock();
847 ASSERT(exit_block->dominated_blocks().is_empty());
848 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) {
849 BlockEntryInstr* block = caller_entry->dominated_blocks()[i];
850 block->set_dominator(exit_block);
851 exit_block->AddDominatedBlock(block);
852 }
853 // The caller entry is now the immediate dominator of blocks whose
854 // immediate dominator was the callee entry.
855 caller_entry->ClearDominatedBlocks();
856 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
857 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
858 block->set_dominator(caller_entry);
859 caller_entry->AddDominatedBlock(block);
860 }
861 // Recompute the block orders.
862 DiscoverBlocks();
863 }
788 } else { 864 } else {
789 // TODO(zerny): Support multiple exits. 865 // Sort the list of exits by block id.
790 UNREACHABLE(); 866 GrowableArray<BlockEntryInstr*> exits(callee_exits->length());
867 for (intptr_t i = 0; i < callee_exits->length(); ++i) {
868 exits.Add((*callee_exits)[i]->GetBlock());
869 }
870 exits.Sort(LowestBlockIdFirst);
871 // Create a join of the returns.
872 JoinEntryInstr* join =
873 new JoinEntryInstr(++max_block_id_, CatchClauseNode::kInvalidTryIndex);
874 for (intptr_t i = 0; i < exits.length(); ++i) {
875 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn();
876 ASSERT(exit_instr != NULL);
877 exit_instr->previous()->Goto(join);
878 // Directly add the predecessors of the join in ascending block id order.
879 join->predecessors_.Add(exits[i]);
880 }
881 // If the call has uses, create a phi of the returns.
882 if ((call->input_use_list() != NULL) ||
883 (call->env_use_list() != NULL)) {
884 // Environment count: length before call - argument count (+ return)
885 intptr_t env_count = call->env()->Length() - call->ArgumentCount();
886 // Add a phi of the return values.
887 join->InsertPhi(env_count, env_count + 1);
888 PhiInstr* phi = join->phis()->Last();
889 phi->set_ssa_temp_index(alloc_ssa_temp_index());
890 phi->mark_alive();
891 for (intptr_t i = 0; i < exits.length(); ++i) {
892 ReturnInstr* exit_instr = exits[i]->last_instruction()->AsReturn();
893 ASSERT(exit_instr != NULL);
894 Value* use = exit_instr->value();
895 phi->SetInputAt(i, use);
896 use->set_instruction(phi);
897 use->set_use_index(i);
898 }
899 // Replace uses of the call with the phi.
900 call->ReplaceUsesWith(phi);
901 }
902 // Remove the call from the graph.
903 Link(call->previous(), callee_entry->next());
904 Link(join, call->next());
905 // The caller block is split and the new block id is that of the join
906 // block. If the caller block had outgoing edges, reorder the phis so they
907 // are still ordered by block id.
908 ReorderPhis(caller_entry);
909 // Adjust pre/post orders and update the dominator tree.
910 DiscoverBlocks();
911 // TODO(zerny): Compute the dominator frontier locally.
912 GrowableArray<BitVector*> dominance_frontier;
913 ComputeDominators(&dominance_frontier);
791 } 914 }
792
793 // TODO(zerny): Adjust pre/post orders.
794 // TODO(zerny): Update dominator tree.
795 } 915 }
796 916
797 917
918 intptr_t FlowGraph::InstructionCount() const {
919 intptr_t size = 0;
920 // Iterate each block, skipping the graph entry.
921 for (intptr_t i = 1; i < preorder_.length(); ++i) {
922 for (ForwardInstructionIterator it(preorder_[i]);
923 !it.Done();
924 it.Advance()) {
925 ++size;
926 }
927 }
928 return size;
929 }
930
931
798 } // namespace dart 932 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_builder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698