OLD | NEW |
---|---|
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/growable_array.h" | 10 #include "vm/growable_array.h" |
11 #include "vm/object_store.h" | |
11 #include "vm/report.h" | 12 #include "vm/report.h" |
12 | 13 |
13 namespace dart { | 14 namespace dart { |
14 | 15 |
15 DECLARE_FLAG(bool, reorder_basic_blocks); | 16 DECLARE_FLAG(bool, reorder_basic_blocks); |
16 DECLARE_FLAG(bool, trace_optimization); | 17 DECLARE_FLAG(bool, trace_optimization); |
17 DECLARE_FLAG(bool, verify_compiler); | 18 DECLARE_FLAG(bool, verify_compiler); |
18 | 19 |
19 | 20 |
20 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, | 21 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, |
21 GraphEntryInstr* graph_entry, | 22 GraphEntryInstr* graph_entry, |
22 intptr_t max_block_id) | 23 intptr_t max_block_id) |
23 : isolate_(Isolate::Current()), | 24 : isolate_(Isolate::Current()), |
24 parent_(), | 25 parent_(), |
25 current_ssa_temp_index_(0), | 26 current_ssa_temp_index_(0), |
26 max_block_id_(max_block_id), | 27 max_block_id_(max_block_id), |
27 builder_(builder), | 28 builder_(builder), |
28 parsed_function_(*builder.parsed_function()), | 29 parsed_function_(*builder.parsed_function()), |
29 num_copied_params_(builder.num_copied_params()), | 30 num_copied_params_(builder.num_copied_params()), |
30 num_non_copied_params_(builder.num_non_copied_params()), | 31 num_non_copied_params_(builder.num_non_copied_params()), |
31 num_stack_locals_(builder.num_stack_locals()), | 32 num_stack_locals_(builder.num_stack_locals()), |
32 graph_entry_(graph_entry), | 33 graph_entry_(graph_entry), |
33 preorder_(), | 34 preorder_(), |
34 postorder_(), | 35 postorder_(), |
35 reverse_postorder_(), | 36 reverse_postorder_(), |
36 optimized_block_order_(), | 37 optimized_block_order_(), |
37 constant_null_(NULL), | 38 constant_null_(NULL), |
38 constant_dead_(NULL), | 39 constant_dead_(NULL), |
40 constant_empty_context_(NULL), | |
41 current_context_(NULL), | |
39 block_effects_(NULL), | 42 block_effects_(NULL), |
40 licm_allowed_(true), | 43 licm_allowed_(true), |
41 loop_headers_(NULL), | 44 loop_headers_(NULL), |
42 loop_invariant_loads_(NULL), | 45 loop_invariant_loads_(NULL), |
43 guarded_fields_(builder.guarded_fields()), | 46 guarded_fields_(builder.guarded_fields()), |
44 deferred_prefixes_(builder.deferred_prefixes()), | 47 deferred_prefixes_(builder.deferred_prefixes()), |
45 captured_parameters_( | 48 captured_parameters_( |
46 new(isolate_) BitVector(isolate_, variable_count())) { | 49 new(isolate_) BitVector(isolate_, variable_count())) { |
47 DiscoverBlocks(); | 50 DiscoverBlocks(); |
48 } | 51 } |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 } | 461 } |
459 assigned_vars_.Add(kill); | 462 assigned_vars_.Add(kill); |
460 } | 463 } |
461 | 464 |
462 return assigned_vars_; | 465 return assigned_vars_; |
463 } | 466 } |
464 | 467 |
465 // Returns true if the value set by the given store reaches any load from the | 468 // Returns true if the value set by the given store reaches any load from the |
466 // same local variable. | 469 // same local variable. |
467 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { | 470 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { |
471 if (store->local().index() == flow_graph_->CurrentContextVar()->index()) { | |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
is it possible just to do
store->local().Equals(f
Florian Schneider
2014/10/28 19:04:31
Done.
| |
472 return true; | |
473 } | |
474 | |
468 if (store->is_dead()) { | 475 if (store->is_dead()) { |
469 return false; | 476 return false; |
470 } | 477 } |
471 | |
472 if (store->is_last()) { | 478 if (store->is_last()) { |
473 const intptr_t index = store->local().BitIndexIn(num_non_copied_params_); | 479 const intptr_t index = store->local().BitIndexIn(num_non_copied_params_); |
474 return GetLiveOutSet(block)->Contains(index); | 480 return GetLiveOutSet(block)->Contains(index); |
475 } | 481 } |
476 | 482 |
477 return true; | 483 return true; |
478 } | 484 } |
479 | 485 |
480 // Returns true if the given load is the last for the local and the value | 486 // Returns true if the given load is the last for the local and the value |
481 // of the local will not flow into another one. | 487 // of the local will not flow into another one. |
482 bool IsLastLoad(BlockEntryInstr* block, LoadLocalInstr* load) { | 488 bool IsLastLoad(BlockEntryInstr* block, LoadLocalInstr* load) { |
489 if (load->local().index() == flow_graph_->CurrentContextVar()->index()) { | |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
ditto
Florian Schneider
2014/10/28 19:04:30
Done.
| |
490 return false; | |
491 } | |
483 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); | 492 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); |
484 return load->is_last() && !GetLiveOutSet(block)->Contains(index); | 493 return load->is_last() && !GetLiveOutSet(block)->Contains(index); |
485 } | 494 } |
486 | 495 |
487 private: | 496 private: |
488 virtual void ComputeInitialSets(); | 497 virtual void ComputeInitialSets(); |
489 | 498 |
490 const FlowGraph* flow_graph_; | 499 const FlowGraph* flow_graph_; |
491 const intptr_t num_non_copied_params_; | 500 const intptr_t num_non_copied_params_; |
492 GrowableArray<BitVector*> assigned_vars_; | 501 GrowableArray<BitVector*> assigned_vars_; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 | 724 |
716 // Initialize has_already and work. | 725 // Initialize has_already and work. |
717 for (intptr_t block_index = 0; block_index < block_count; ++block_index) { | 726 for (intptr_t block_index = 0; block_index < block_count; ++block_index) { |
718 has_already.Add(-1); | 727 has_already.Add(-1); |
719 work.Add(-1); | 728 work.Add(-1); |
720 } | 729 } |
721 | 730 |
722 // Insert phis for each variable in turn. | 731 // Insert phis for each variable in turn. |
723 GrowableArray<BlockEntryInstr*> worklist; | 732 GrowableArray<BlockEntryInstr*> worklist; |
724 for (intptr_t var_index = 0; var_index < variable_count(); ++var_index) { | 733 for (intptr_t var_index = 0; var_index < variable_count(); ++var_index) { |
734 bool always_live = var_index == CurrentContextEnvIndex(); | |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
const bool is_always_alive
Florian Schneider
2014/10/28 19:04:30
Done.
| |
725 // Add to the worklist each block containing an assignment. | 735 // Add to the worklist each block containing an assignment. |
726 for (intptr_t block_index = 0; block_index < block_count; ++block_index) { | 736 for (intptr_t block_index = 0; block_index < block_count; ++block_index) { |
727 if (assigned_vars[block_index]->Contains(var_index)) { | 737 if (assigned_vars[block_index]->Contains(var_index)) { |
728 work[block_index] = var_index; | 738 work[block_index] = var_index; |
729 worklist.Add(preorder[block_index]); | 739 worklist.Add(preorder[block_index]); |
730 } | 740 } |
731 } | 741 } |
732 | 742 |
733 while (!worklist.is_empty()) { | 743 while (!worklist.is_empty()) { |
734 BlockEntryInstr* current = worklist.RemoveLast(); | 744 BlockEntryInstr* current = worklist.RemoveLast(); |
735 // Ensure a phi for each block in the dominance frontier of current. | 745 // Ensure a phi for each block in the dominance frontier of current. |
736 for (BitVector::Iterator it(dom_frontier[current->preorder_number()]); | 746 for (BitVector::Iterator it(dom_frontier[current->preorder_number()]); |
737 !it.Done(); | 747 !it.Done(); |
738 it.Advance()) { | 748 it.Advance()) { |
739 int index = it.Current(); | 749 int index = it.Current(); |
740 if (has_already[index] < var_index) { | 750 if (has_already[index] < var_index) { |
741 BlockEntryInstr* block = preorder[index]; | 751 BlockEntryInstr* block = preorder[index]; |
742 ASSERT(block->IsJoinEntry()); | 752 ASSERT(block->IsJoinEntry()); |
743 block->AsJoinEntry()->InsertPhi(var_index, variable_count()); | 753 block->AsJoinEntry()->InsertPhi(var_index, |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
You can also make InsertPhi return the phi it crea
Florian Schneider
2014/10/28 19:04:31
Done.
| |
754 variable_count(), | |
755 always_live); | |
744 has_already[index] = var_index; | 756 has_already[index] = var_index; |
745 if (work[index] < var_index) { | 757 if (work[index] < var_index) { |
746 work[index] = var_index; | 758 work[index] = var_index; |
747 worklist.Add(block); | 759 worklist.Add(block); |
748 } | 760 } |
749 } | 761 } |
750 } | 762 } |
751 } | 763 } |
752 } | 764 } |
753 } | 765 } |
754 | 766 |
755 | 767 |
756 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, | 768 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, |
757 VariableLivenessAnalysis* variable_liveness, | 769 VariableLivenessAnalysis* variable_liveness, |
758 ZoneGrowableArray<Definition*>* inlining_parameters) { | 770 ZoneGrowableArray<Definition*>* inlining_parameters) { |
759 GraphEntryInstr* entry = graph_entry(); | 771 GraphEntryInstr* entry = graph_entry(); |
760 | 772 |
761 // Initial renaming environment. | 773 // Initial renaming environment. |
762 GrowableArray<Definition*> env(variable_count()); | 774 GrowableArray<Definition*> env(variable_count()); |
763 | 775 |
764 // Add global constants to the initial definitions. | 776 // Add global constants to the initial definitions. |
765 constant_null_ = GetConstant(Object::ZoneHandle()); | 777 constant_null_ = GetConstant(Object::ZoneHandle()); |
766 constant_dead_ = GetConstant(Symbols::OptimizedOut()); | 778 constant_dead_ = GetConstant(Symbols::OptimizedOut()); |
779 constant_empty_context_ = GetConstant(Context::Handle( | |
780 isolate()->object_store()->empty_context())); | |
767 | 781 |
768 // Add parameters to the initial definitions and renaming environment. | 782 // Add parameters to the initial definitions and renaming environment. |
769 if (inlining_parameters != NULL) { | 783 if (inlining_parameters != NULL) { |
770 // Use known parameters. | 784 // Use known parameters. |
771 ASSERT(parameter_count() == inlining_parameters->length()); | 785 ASSERT(parameter_count() == inlining_parameters->length()); |
772 for (intptr_t i = 0; i < parameter_count(); ++i) { | 786 for (intptr_t i = 0; i < parameter_count(); ++i) { |
773 Definition* defn = (*inlining_parameters)[i]; | 787 Definition* defn = (*inlining_parameters)[i]; |
774 AllocateSSAIndexes(defn); | 788 AllocateSSAIndexes(defn); |
775 AddToInitialDefinitions(defn); | 789 AddToInitialDefinitions(defn); |
776 env.Add(defn); | 790 env.Add(defn); |
777 } | 791 } |
778 } else { | 792 } else { |
779 // Create new parameters. For functions compiled for OSR, the locals | 793 // Create new parameters. For functions compiled for OSR, the locals |
780 // are unknown and so treated like parameters. | 794 // are unknown and so treated like parameters. |
781 intptr_t count = IsCompiledForOsr() ? variable_count() : parameter_count(); | 795 intptr_t count = IsCompiledForOsr() ? variable_count() : parameter_count(); |
782 for (intptr_t i = 0; i < count; ++i) { | 796 for (intptr_t i = 0; i < count; ++i) { |
783 ParameterInstr* param = new(isolate()) ParameterInstr(i, entry); | 797 ParameterInstr* param = new(isolate()) ParameterInstr(i, entry); |
784 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. | 798 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
785 AddToInitialDefinitions(param); | 799 AddToInitialDefinitions(param); |
786 env.Add(param); | 800 env.Add(param); |
787 } | 801 } |
788 } | 802 } |
789 | 803 |
790 // Initialize all locals with #null in the renaming environment. For OSR, | 804 // Initialize all locals with #null in the renaming environment. For OSR, |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
Comment is out of date.
Florian Schneider
2014/10/28 19:04:31
Done.
| |
791 // the locals have already been handled as parameters. | 805 // the locals have already been handled as parameters. |
792 if (!IsCompiledForOsr()) { | 806 if (!IsCompiledForOsr()) { |
793 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { | 807 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { |
794 env.Add(constant_null()); | 808 if (i == CurrentContextEnvIndex()) { |
809 if (parsed_function().function().IsClosureFunction()) { | |
810 CurrentContextInstr* context = new CurrentContextInstr(); | |
811 context->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. | |
812 AddToInitialDefinitions(context); | |
813 env.Add(context); | |
814 } else { | |
815 env.Add(constant_empty_context()); | |
816 } | |
817 } else { | |
818 env.Add(constant_null()); | |
819 } | |
795 } | 820 } |
796 } | 821 } |
797 | 822 |
798 if (entry->SuccessorCount() > 1) { | 823 if (entry->SuccessorCount() > 1) { |
799 // Functions with try-catch have a fixed area of stack slots reserved | 824 // Functions with try-catch have a fixed area of stack slots reserved |
800 // so that all local variables are stored at a known location when | 825 // so that all local variables are stored at a known location when |
801 // on entry to the catch. | 826 // on entry to the catch. |
802 entry->set_fixed_slot_count(num_stack_locals() + num_copied_params()); | 827 entry->set_fixed_slot_count(num_stack_locals() + num_copied_params()); |
803 } | 828 } |
804 RenameRecursive(entry, &env, live_phis, variable_liveness); | 829 RenameRecursive(entry, &env, live_phis, variable_liveness); |
805 } | 830 } |
806 | 831 |
807 | 832 |
808 void FlowGraph::AttachEnvironment(Instruction* instr, | 833 void FlowGraph::AttachEnvironment(Instruction* instr, |
809 GrowableArray<Definition*>* env) { | 834 GrowableArray<Definition*>* env) { |
810 Environment* deopt_env = | 835 Environment* deopt_env = |
811 Environment::From(isolate(), | 836 Environment::From(isolate(), |
812 *env, | 837 *env, |
813 num_non_copied_params_, | 838 num_non_copied_params_, |
814 &parsed_function_); | 839 &parsed_function_); |
815 // TODO(fschneider): Add predicates CanEagerlyDeoptimize and | |
816 // CanLazilyDeoptimize to instructions to generally deal with instructions | |
817 // that have pushed arguments and input operands. | |
818 // Right now, closure calls are the only instructions that have both. They | |
819 // also don't have an eager deoptimziation point, so the environment attached | |
820 // here is only used for after the call. | |
821 if (instr->IsClosureCall()) { | 840 if (instr->IsClosureCall()) { |
822 deopt_env = deopt_env->DeepCopy(isolate(), | 841 deopt_env = deopt_env->DeepCopy(isolate(), |
823 deopt_env->Length() - instr->InputCount()); | 842 deopt_env->Length() - instr->InputCount()); |
824 } | 843 } |
825 instr->SetEnvironment(deopt_env); | 844 instr->SetEnvironment(deopt_env); |
826 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | 845 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { |
827 Value* use = it.CurrentValue(); | 846 Value* use = it.CurrentValue(); |
828 use->definition()->AddEnvUse(use); | 847 use->definition()->AddEnvUse(use); |
829 } | 848 } |
830 if (instr->CanDeoptimize()) { | 849 if (instr->CanDeoptimize()) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
865 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. | 884 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
866 (*env)[i] = param; | 885 (*env)[i] = param; |
867 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param); | 886 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param); |
868 } | 887 } |
869 } | 888 } |
870 | 889 |
871 // Prune non-live variables at block entry by replacing their environment | 890 // Prune non-live variables at block entry by replacing their environment |
872 // slots with null. | 891 // slots with null. |
873 BitVector* live_in = variable_liveness->GetLiveInSet(block_entry); | 892 BitVector* live_in = variable_liveness->GetLiveInSet(block_entry); |
874 for (intptr_t i = 0; i < variable_count(); i++) { | 893 for (intptr_t i = 0; i < variable_count(); i++) { |
875 if (!live_in->Contains(i)) { | 894 if (!live_in->Contains(i) && (i != CurrentContextEnvIndex())) { |
Vyacheslav Egorov (Google)
2014/10/28 13:44:57
Should not we instead ensure that live_in->Contain
Florian Schneider
2014/10/28 19:04:31
Yes, I can change the VariableLiveness accordingly
| |
876 (*env)[i] = constant_dead(); | 895 (*env)[i] = constant_dead(); |
877 } | 896 } |
878 } | 897 } |
879 | 898 |
880 // Attach environment to the block entry. | 899 // Attach environment to the block entry. |
881 AttachEnvironment(block_entry, env); | 900 AttachEnvironment(block_entry, env); |
882 | 901 |
883 // 2. Process normal instructions. | 902 // 2. Process normal instructions. |
884 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { | 903 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { |
885 Instruction* current = it.Current(); | 904 Instruction* current = it.Current(); |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1308 } | 1327 } |
1309 | 1328 |
1310 | 1329 |
1311 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, | 1330 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, |
1312 BlockEntryInstr* to) const { | 1331 BlockEntryInstr* to) const { |
1313 return available_at_[to->postorder_number()]->Contains( | 1332 return available_at_[to->postorder_number()]->Contains( |
1314 from->postorder_number()); | 1333 from->postorder_number()); |
1315 } | 1334 } |
1316 | 1335 |
1317 } // namespace dart | 1336 } // namespace dart |
OLD | NEW |