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

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

Issue 11953076: Move code around in preparation for better inlining. (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 740 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 const char* function_name = parsed_function_.function().ToCString(); 751 const char* function_name = parsed_function_.function().ToCString();
752 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 752 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
753 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 753 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
754 OS::SNPrint(chars, len, kFormat, function_name, reason); 754 OS::SNPrint(chars, len, kFormat, function_name, reason);
755 const Error& error = Error::Handle( 755 const Error& error = Error::Handle(
756 LanguageError::New(String::Handle(String::New(chars)))); 756 LanguageError::New(String::Handle(String::New(chars))));
757 Isolate::Current()->long_jump_base()->Jump(1, error); 757 Isolate::Current()->long_jump_base()->Jump(1, error);
758 } 758 }
759 759
760 760
761 // Helper to replace a predecessor block. For each successor of 'old_block', the
762 // predecessors will be reordered to preserve block-order sorting of the
763 // predecessors as well as the phis if the successor is a join.
764 void FlowGraph::ReplacePredecessor(BlockEntryInstr* old_block,
765 BlockEntryInstr* new_block) {
766 // Set the last instruction of the new block to that of the old block.
767 Instruction* last = old_block->last_instruction();
768 new_block->set_last_instruction(last);
769 // For each successor, update the predecessors.
770 for (intptr_t sidx = 0; sidx < last->SuccessorCount(); ++sidx) {
771 // If the successor is a target, update its predecessor.
772 TargetEntryInstr* target = last->SuccessorAt(sidx)->AsTargetEntry();
773 if (target != NULL) {
774 target->predecessor_ = new_block;
775 continue;
776 }
777 // If the successor is a join, update each predecessor and the phis.
778 JoinEntryInstr* join = last->SuccessorAt(sidx)->AsJoinEntry();
779 ASSERT(join != NULL);
780 // Find the old predecessor index.
781 intptr_t old_index = join->IndexOfPredecessor(old_block);
782 intptr_t pred_count = join->PredecessorCount();
783 ASSERT(old_index >= 0);
784 ASSERT(old_index < pred_count);
785 // Find the new predecessor index while reordering the predecessors.
786 intptr_t new_id = new_block->block_id();
787 intptr_t new_index = old_index;
788 if (old_block->block_id() < new_id) {
789 // Search upwards, bubbling down intermediate predecessors.
790 for (; new_index < pred_count - 1; ++new_index) {
791 if (join->predecessors_[new_index + 1]->block_id() > new_id) break;
792 join->predecessors_[new_index] = join->predecessors_[new_index + 1];
793 }
794 } else {
795 // Search downwards, bubbling up intermediate predecessors.
796 for (; new_index > 0; --new_index) {
797 if (join->predecessors_[new_index - 1]->block_id() < new_id) break;
798 join->predecessors_[new_index] = join->predecessors_[new_index - 1];
799 }
800 }
801 join->predecessors_[new_index] = new_block;
802 // If the new and old predecessor index match there is nothing to update.
803 if ((join->phis() == NULL) || (old_index == new_index)) return;
804 // Otherwise, reorder the predecessor uses in each phi.
805 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
806 PhiInstr* phi = (*join->phis())[i];
807 if (phi == NULL) continue;
808 ASSERT(pred_count == phi->InputCount());
809 // Save the predecessor use.
810 Value* pred_use = phi->InputAt(old_index);
811 // Move uses between old and new.
812 intptr_t step = (old_index < new_index) ? 1 : -1;
813 for (intptr_t use_idx = old_index;
814 use_idx != new_index;
815 use_idx += step) {
816 Value* use = phi->InputAt(use_idx + step);
817 phi->SetInputAt(use_idx, use);
818 use->set_use_index(use_idx);
819 }
820 // Write the predecessor use.
821 phi->SetInputAt(new_index, pred_use);
822 pred_use->set_use_index(new_index);
823 }
824 }
825 }
826
827
828 // Inline a flow graph at a call site.
829 //
830 // Assumes the callee graph was computed by BuildGraph with an inlining context
831 // and transformed to SSA with ComputeSSA with a correct virtual register
832 // number, and that the use lists have been correctly computed.
833 //
834 // After inlining the caller graph will correctly have adjusted the pre/post
835 // orders, the dominator tree and the use lists.
836 void FlowGraph::InlineCall(Definition* call,
837 FlowGraph* callee_graph,
838 ValueInliningContext* inlining_context) {
839 ASSERT(call->previous() != NULL);
840 ASSERT(call->next() != NULL);
841 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
842 ASSERT(callee_graph->max_block_id() > max_block_id());
843 ASSERT(callee_graph->max_virtual_register_number() >
844 max_virtual_register_number());
845
846 // Adjust the max block id to the max block id of the callee graph.
847 max_block_id_ = callee_graph->max_block_id();
848
849 // Adjust the SSA temp index by the callee graph's index.
850 current_ssa_temp_index_ = callee_graph->max_virtual_register_number();
851
852 BlockEntryInstr* caller_entry = call->GetBlock();
853 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
854
855 // Attach the outer environment on each instruction in the callee graph.
856 for (BlockIterator block_it = callee_graph->postorder_iterator();
857 !block_it.Done();
858 block_it.Advance()) {
859 for (ForwardInstructionIterator it(block_it.Current());
860 !it.Done();
861 it.Advance()) {
862 Instruction* instr = it.Current();
863 // TODO(zerny): Avoid creating unnecessary environments. Note that some
864 // optimizations need deoptimization info for non-deoptable instructions,
865 // eg, LICM on GOTOs.
866 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr);
867 }
868 }
869
870 // Insert the callee graph into the caller graph. First sort the list of
871 // exits by block id (recording block entries as a side effect).
872 inlining_context->SortExits();
873 if (inlining_context->NumExits() == 0) {
874 // TODO(zerny): Add support for non-local exits, such as throw.
875 UNREACHABLE();
876 } else if (inlining_context->NumExits() == 1) {
877 // For just one exit, replace the uses and remove the call from the graph.
878 call->ReplaceUsesWith(inlining_context->ValueAt(0)->definition());
879 call->previous()->LinkTo(callee_entry->next());
880 inlining_context->LastInstructionAt(0)->LinkTo(call->next());
881 // In case of control flow, locally update the predecessors, phis and
882 // dominator tree.
883 // TODO(zerny): should we leave the dominator tree since we recompute it
884 // after a full inlining pass?
885 if (callee_graph->preorder().length() > 2) {
886 BlockEntryInstr* exit_block = inlining_context->ExitBlockAt(0);
887 // Pictorially, the graph structure is:
888 //
889 // Bc : caller_entry Bi : callee_entry
890 // before_call inlined_head
891 // call ... other blocks ...
892 // after_call Be : exit_block
893 // inlined_foot
894 // And becomes:
895 //
896 // Bc : caller_entry
897 // before_call
898 // inlined_head
899 // ... other blocks ...
900 // Be : exit_block
901 // inlined_foot
902 // after_call
903 //
904 // For 'after_call', caller entry (Bc) is replaced by callee exit (Be).
905 ReplacePredecessor(caller_entry, exit_block);
906 // For 'inlined_head', callee entry (Bi) is replaced by caller entry (Bc).
907 ReplacePredecessor(callee_entry, caller_entry);
908 // The callee exit is now the immediate dominator of blocks whose
909 // immediate dominator was the caller entry.
910 ASSERT(exit_block->dominated_blocks().is_empty());
911 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) {
912 BlockEntryInstr* block = caller_entry->dominated_blocks()[i];
913 block->set_dominator(exit_block);
914 exit_block->AddDominatedBlock(block);
915 }
916 // The caller entry is now the immediate dominator of blocks whose
917 // immediate dominator was the callee entry.
918 caller_entry->ClearDominatedBlocks();
919 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
920 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
921 block->set_dominator(caller_entry);
922 caller_entry->AddDominatedBlock(block);
923 }
924 }
925 } else {
926 // Create a join of the returns.
927 JoinEntryInstr* join =
928 new JoinEntryInstr(++max_block_id_, CatchClauseNode::kInvalidTryIndex);
929 intptr_t count = inlining_context->NumExits();
930 for (intptr_t i = 0; i < count; ++i) {
931 inlining_context->LastInstructionAt(i)->Goto(join);
932 // Directly add the predecessors of the join in ascending block id order.
933 join->predecessors_.Add(inlining_context->ExitBlockAt(i));
934 }
935 // If the call has uses, create a phi of the returns.
936 if (call->HasUses()) {
937 // Environment count: length before call - argument count (+ return)
938 intptr_t env_count = call->env()->Length() - call->ArgumentCount();
939 // Add a phi of the return values.
940 join->InsertPhi(env_count, env_count + 1);
941 PhiInstr* phi = join->phis()->Last();
942 phi->set_ssa_temp_index(alloc_ssa_temp_index());
943 phi->mark_alive();
944 for (intptr_t i = 0; i < count; ++i) {
945 Value* value = inlining_context->ValueAt(i);
946 phi->SetInputAt(i, value);
947 value->set_instruction(phi);
948 value->set_use_index(i);
949 }
950 // Replace uses of the call with the phi.
951 call->ReplaceUsesWith(phi);
952 }
953 // Remove the call from the graph.
954 call->previous()->LinkTo(callee_entry->next());
955 join->LinkTo(call->next());
956 // Replace the blocks after splitting (see comment in the len=1 case above).
957 ReplacePredecessor(caller_entry, join);
958 ReplacePredecessor(callee_entry, caller_entry);
959 // Update the last instruction pointers on each exit block to the new goto.
960 for (intptr_t i = 0; i < count; ++i) {
961 inlining_context->ExitBlockAt(i)->set_last_instruction(
962 inlining_context->LastInstructionAt(i)->next());
963 }
964 // Mark that the dominator tree is invalid.
965 // TODO(zerny): Compute the dominator frontier locally.
966 invalid_dominator_tree_ = true;
967 }
968 }
969
970
971 void FlowGraph::RepairGraphAfterInlining() { 761 void FlowGraph::RepairGraphAfterInlining() {
972 DiscoverBlocks(); 762 DiscoverBlocks();
973 if (invalid_dominator_tree_) { 763 if (invalid_dominator_tree_) {
974 GrowableArray<BitVector*> dominance_frontier; 764 GrowableArray<BitVector*> dominance_frontier;
975 ComputeDominators(&dominance_frontier); 765 ComputeDominators(&dominance_frontier);
976 } 766 }
977 } 767 }
978 768
979 769
980 intptr_t FlowGraph::InstructionCount() const { 770 intptr_t FlowGraph::InstructionCount() const {
981 intptr_t size = 0; 771 intptr_t size = 0;
982 // Iterate each block, skipping the graph entry. 772 // Iterate each block, skipping the graph entry.
983 for (intptr_t i = 1; i < preorder_.length(); ++i) { 773 for (intptr_t i = 1; i < preorder_.length(); ++i) {
984 for (ForwardInstructionIterator it(preorder_[i]); 774 for (ForwardInstructionIterator it(preorder_[i]);
985 !it.Done(); 775 !it.Done();
986 it.Advance()) { 776 it.Advance()) {
987 ++size; 777 ++size;
988 } 778 }
989 } 779 }
990 return size; 780 return size;
991 } 781 }
992 782
993 783
994 } // namespace dart 784 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698