| 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_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 2811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2822 if (store_vm_field != NULL) { | 2822 if (store_vm_field != NULL) { |
| 2823 ASSERT(store_vm_field->offset_in_bytes() != 0); | 2823 ASSERT(store_vm_field->offset_in_bytes() != 0); |
| 2824 *offset_in_words = store_vm_field->offset_in_bytes() / kWordSize; | 2824 *offset_in_words = store_vm_field->offset_in_bytes() / kWordSize; |
| 2825 return true; | 2825 return true; |
| 2826 } | 2826 } |
| 2827 | 2827 |
| 2828 return false; | 2828 return false; |
| 2829 } | 2829 } |
| 2830 | 2830 |
| 2831 | 2831 |
| 2832 static Definition* GetStoredValue(Instruction* instr) { |
| 2833 if (instr->IsStoreIndexed()) { |
| 2834 return instr->AsStoreIndexed()->value()->definition(); |
| 2835 } |
| 2836 |
| 2837 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField(); |
| 2838 if (store_instance_field != NULL) { |
| 2839 return store_instance_field->value()->definition(); |
| 2840 } |
| 2841 |
| 2842 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField(); |
| 2843 if (store_vm_field != NULL) { |
| 2844 return store_vm_field->value()->definition(); |
| 2845 } |
| 2846 |
| 2847 UNREACHABLE(); // Should only be called for supported store instructions. |
| 2848 return NULL; |
| 2849 } |
| 2850 |
| 2851 |
| 2852 // KeyValueTrait used for numbering of loads. Allows to lookup loads |
| 2853 // corresponding to stores. |
| 2854 class LoadKeyValueTrait { |
| 2855 public: |
| 2856 typedef Definition* Value; |
| 2857 typedef Definition* Key; |
| 2858 typedef Definition* Pair; |
| 2859 |
| 2860 static Key KeyOf(Pair kv) { |
| 2861 return kv; |
| 2862 } |
| 2863 |
| 2864 static Value ValueOf(Pair kv) { |
| 2865 return kv; |
| 2866 } |
| 2867 |
| 2868 static inline intptr_t Hashcode(Key key) { |
| 2869 intptr_t object = 0; |
| 2870 intptr_t location = 0; |
| 2871 |
| 2872 if (key->IsLoadIndexed()) { |
| 2873 LoadIndexedInstr* load_indexed = key->AsLoadIndexed(); |
| 2874 object = load_indexed->array()->definition()->ssa_temp_index(); |
| 2875 location = load_indexed->index()->definition()->ssa_temp_index(); |
| 2876 } else if (key->IsStoreIndexed()) { |
| 2877 StoreIndexedInstr* store_indexed = key->AsStoreIndexed(); |
| 2878 object = store_indexed->array()->definition()->ssa_temp_index(); |
| 2879 location = store_indexed->index()->definition()->ssa_temp_index(); |
| 2880 } else if (key->IsLoadField()) { |
| 2881 LoadFieldInstr* load_field = key->AsLoadField(); |
| 2882 object = load_field->value()->definition()->ssa_temp_index(); |
| 2883 location = load_field->offset_in_bytes(); |
| 2884 } else if (key->IsStoreInstanceField()) { |
| 2885 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); |
| 2886 object = store_field->instance()->definition()->ssa_temp_index(); |
| 2887 location = store_field->field().Offset(); |
| 2888 } else if (key->IsStoreVMField()) { |
| 2889 StoreVMFieldInstr* store_field = key->AsStoreVMField(); |
| 2890 object = store_field->dest()->definition()->ssa_temp_index(); |
| 2891 location = store_field->offset_in_bytes(); |
| 2892 } |
| 2893 |
| 2894 return object * 31 + location; |
| 2895 } |
| 2896 |
| 2897 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 2898 if (kv->Equals(key)) return true; |
| 2899 |
| 2900 if (kv->IsLoadIndexed()) { |
| 2901 if (key->IsStoreIndexed()) { |
| 2902 LoadIndexedInstr* load_indexed = kv->AsLoadIndexed(); |
| 2903 StoreIndexedInstr* store_indexed = key->AsStoreIndexed(); |
| 2904 return load_indexed->array()->Equals(store_indexed->array()) && |
| 2905 load_indexed->index()->Equals(store_indexed->index()); |
| 2906 } |
| 2907 return false; |
| 2908 } |
| 2909 |
| 2910 ASSERT(kv->IsLoadField()); |
| 2911 LoadFieldInstr* load_field = kv->AsLoadField(); |
| 2912 if (key->IsStoreVMField()) { |
| 2913 StoreVMFieldInstr* store_field = key->AsStoreVMField(); |
| 2914 return load_field->value()->Equals(store_field->dest()) && |
| 2915 (load_field->offset_in_bytes() == store_field->offset_in_bytes()); |
| 2916 } else if (key->IsStoreInstanceField()) { |
| 2917 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); |
| 2918 return load_field->value()->Equals(store_field->instance()) && |
| 2919 (load_field->offset_in_bytes() == store_field->field().Offset()); |
| 2920 } |
| 2921 |
| 2922 return false; |
| 2923 } |
| 2924 }; |
| 2925 |
| 2926 |
| 2832 static intptr_t NumberLoadExpressions( | 2927 static intptr_t NumberLoadExpressions( |
| 2833 FlowGraph* graph, | 2928 FlowGraph* graph, |
| 2929 DirectChainedHashMap<LoadKeyValueTrait>* map, |
| 2834 GrowableArray<BitVector*>* kill_by_offs) { | 2930 GrowableArray<BitVector*>* kill_by_offs) { |
| 2835 DirectChainedHashMap<PointerKeyValueTrait<Definition> > map; | |
| 2836 intptr_t expr_id = 0; | 2931 intptr_t expr_id = 0; |
| 2837 | 2932 |
| 2838 // Loads representing different expression ids will be collected and | 2933 // Loads representing different expression ids will be collected and |
| 2839 // used to build per offset kill sets. | 2934 // used to build per offset kill sets. |
| 2840 GrowableArray<Definition*> loads(10); | 2935 GrowableArray<Definition*> loads(10); |
| 2841 | 2936 |
| 2842 for (BlockIterator it = graph->reverse_postorder_iterator(); | 2937 for (BlockIterator it = graph->reverse_postorder_iterator(); |
| 2843 !it.Done(); | 2938 !it.Done(); |
| 2844 it.Advance()) { | 2939 it.Advance()) { |
| 2845 BlockEntryInstr* block = it.Current(); | 2940 BlockEntryInstr* block = it.Current(); |
| 2846 for (ForwardInstructionIterator instr_it(block); | 2941 for (ForwardInstructionIterator instr_it(block); |
| 2847 !instr_it.Done(); | 2942 !instr_it.Done(); |
| 2848 instr_it.Advance()) { | 2943 instr_it.Advance()) { |
| 2849 Definition* defn = instr_it.Current()->AsDefinition(); | 2944 Definition* defn = instr_it.Current()->AsDefinition(); |
| 2850 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 2945 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
| 2851 continue; | 2946 continue; |
| 2852 } | 2947 } |
| 2853 Definition* result = map.Lookup(defn); | 2948 Definition* result = map->Lookup(defn); |
| 2854 if (result == NULL) { | 2949 if (result == NULL) { |
| 2855 map.Insert(defn); | 2950 map->Insert(defn); |
| 2856 defn->set_expr_id(expr_id++); | 2951 defn->set_expr_id(expr_id++); |
| 2857 loads.Add(defn); | 2952 loads.Add(defn); |
| 2858 } else { | 2953 } else { |
| 2859 defn->set_expr_id(result->expr_id()); | 2954 defn->set_expr_id(result->expr_id()); |
| 2860 } | 2955 } |
| 2861 } | 2956 } |
| 2862 } | 2957 } |
| 2863 | 2958 |
| 2864 // Build per offset kill sets. Any store interferes only with loads from | 2959 // Build per offset kill sets. Any store interferes only with loads from |
| 2865 // the same offset. | 2960 // the same offset. |
| 2866 for (intptr_t i = 0; i < loads.length(); i++) { | 2961 for (intptr_t i = 0; i < loads.length(); i++) { |
| 2867 Definition* defn = loads[i]; | 2962 Definition* defn = loads[i]; |
| 2868 | 2963 |
| 2869 const intptr_t offset_in_words = ComputeLoadOffsetInWords(defn); | 2964 const intptr_t offset_in_words = ComputeLoadOffsetInWords(defn); |
| 2870 while (kill_by_offs->length() <= offset_in_words) { | 2965 while (kill_by_offs->length() <= offset_in_words) { |
| 2871 kill_by_offs->Add(NULL); | 2966 kill_by_offs->Add(NULL); |
| 2872 } | 2967 } |
| 2873 if ((*kill_by_offs)[offset_in_words] == NULL) { | 2968 if ((*kill_by_offs)[offset_in_words] == NULL) { |
| 2874 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id); | 2969 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id); |
| 2875 } | 2970 } |
| 2876 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id()); | 2971 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id()); |
| 2877 } | 2972 } |
| 2878 | 2973 |
| 2879 | |
| 2880 return expr_id; | 2974 return expr_id; |
| 2881 } | 2975 } |
| 2882 | 2976 |
| 2883 | 2977 |
| 2884 class LoadOptimizer : public ValueObject { | 2978 class LoadOptimizer : public ValueObject { |
| 2885 public: | 2979 public: |
| 2886 LoadOptimizer(FlowGraph* graph, | 2980 LoadOptimizer(FlowGraph* graph, |
| 2887 intptr_t max_expr_id, | 2981 intptr_t max_expr_id, |
| 2982 DirectChainedHashMap<LoadKeyValueTrait>* map, |
| 2888 const GrowableArray<BitVector*>& kill_by_offset) | 2983 const GrowableArray<BitVector*>& kill_by_offset) |
| 2889 : graph_(graph), | 2984 : graph_(graph), |
| 2985 map_(map), |
| 2890 max_expr_id_(max_expr_id), | 2986 max_expr_id_(max_expr_id), |
| 2891 kill_by_offset_(kill_by_offset), | 2987 kill_by_offset_(kill_by_offset), |
| 2892 in_(graph_->preorder().length()), | 2988 in_(graph_->preorder().length()), |
| 2893 out_(graph_->preorder().length()), | 2989 out_(graph_->preorder().length()), |
| 2894 gen_(graph_->preorder().length()), | 2990 gen_(graph_->preorder().length()), |
| 2895 kill_(graph_->preorder().length()), | 2991 kill_(graph_->preorder().length()), |
| 2896 exposed_values_(graph_->preorder().length()), | 2992 exposed_values_(graph_->preorder().length()), |
| 2897 out_values_(graph_->preorder().length()), | 2993 out_values_(graph_->preorder().length()), |
| 2898 phis_(5), | 2994 phis_(5), |
| 2899 worklist_(5), | 2995 worklist_(5), |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2945 intptr_t offset_in_words = 0; | 3041 intptr_t offset_in_words = 0; |
| 2946 if (IsInterferingStore(instr, &offset_in_words)) { | 3042 if (IsInterferingStore(instr, &offset_in_words)) { |
| 2947 // Interfering stores kill only loads from the same offset. | 3043 // Interfering stores kill only loads from the same offset. |
| 2948 if ((offset_in_words < kill_by_offset_.length()) && | 3044 if ((offset_in_words < kill_by_offset_.length()) && |
| 2949 (kill_by_offset_[offset_in_words] != NULL)) { | 3045 (kill_by_offset_[offset_in_words] != NULL)) { |
| 2950 kill->AddAll(kill_by_offset_[offset_in_words]); | 3046 kill->AddAll(kill_by_offset_[offset_in_words]); |
| 2951 // There is no need to clear out_values when clearing GEN set | 3047 // There is no need to clear out_values when clearing GEN set |
| 2952 // because only those values that are in the GEN set | 3048 // because only those values that are in the GEN set |
| 2953 // will ever be used. | 3049 // will ever be used. |
| 2954 gen->RemoveAll(kill_by_offset_[offset_in_words]); | 3050 gen->RemoveAll(kill_by_offset_[offset_in_words]); |
| 3051 |
| 3052 Definition* load = map_->Lookup(instr->AsDefinition()); |
| 3053 if (load != NULL) { |
| 3054 // Store has a corresponding numbered load. Try forwarding |
| 3055 // stored value to it. |
| 3056 gen->Add(load->expr_id()); |
| 3057 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 3058 (*out_values)[load->expr_id()] = GetStoredValue(instr); |
| 3059 } |
| 2955 } | 3060 } |
| 2956 ASSERT(instr->IsDefinition() && | 3061 ASSERT(instr->IsDefinition() && |
| 2957 !IsLoadEliminationCandidate(instr->AsDefinition())); | 3062 !IsLoadEliminationCandidate(instr->AsDefinition())); |
| 2958 continue; | 3063 continue; |
| 2959 } | 3064 } |
| 2960 | 3065 |
| 2961 // Other instructions with side effects kill all loads. | 3066 // Other instructions with side effects kill all loads. |
| 2962 if (instr->HasSideEffect()) { | 3067 if (instr->HasSideEffect()) { |
| 2963 kill->SetAll(); | 3068 kill->SetAll(); |
| 2964 // There is no need to clear out_values when clearing GEN set | 3069 // There is no need to clear out_values when clearing GEN set |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3267 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { | 3372 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { |
| 3268 ZoneGrowableArray<Definition*>* out = | 3373 ZoneGrowableArray<Definition*>* out = |
| 3269 new ZoneGrowableArray<Definition*>(max_expr_id_); | 3374 new ZoneGrowableArray<Definition*>(max_expr_id_); |
| 3270 for (intptr_t i = 0; i < max_expr_id_; i++) { | 3375 for (intptr_t i = 0; i < max_expr_id_; i++) { |
| 3271 out->Add(NULL); | 3376 out->Add(NULL); |
| 3272 } | 3377 } |
| 3273 return out; | 3378 return out; |
| 3274 } | 3379 } |
| 3275 | 3380 |
| 3276 FlowGraph* graph_; | 3381 FlowGraph* graph_; |
| 3382 DirectChainedHashMap<LoadKeyValueTrait>* map_; |
| 3277 const intptr_t max_expr_id_; | 3383 const intptr_t max_expr_id_; |
| 3278 | 3384 |
| 3279 // Mapping between field offsets in words and expression ids of loads from | 3385 // Mapping between field offsets in words and expression ids of loads from |
| 3280 // that offset. | 3386 // that offset. |
| 3281 const GrowableArray<BitVector*>& kill_by_offset_; | 3387 const GrowableArray<BitVector*>& kill_by_offset_; |
| 3282 | 3388 |
| 3283 // Per block sets of expression ids for loads that are: incoming (available | 3389 // Per block sets of expression ids for loads that are: incoming (available |
| 3284 // on the entry), outgoing (available on the exit), generated and killed. | 3390 // on the entry), outgoing (available on the exit), generated and killed. |
| 3285 GrowableArray<BitVector*> in_; | 3391 GrowableArray<BitVector*> in_; |
| 3286 GrowableArray<BitVector*> out_; | 3392 GrowableArray<BitVector*> out_; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3304 BitVector* in_worklist_; | 3410 BitVector* in_worklist_; |
| 3305 | 3411 |
| 3306 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); | 3412 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); |
| 3307 }; | 3413 }; |
| 3308 | 3414 |
| 3309 | 3415 |
| 3310 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { | 3416 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
| 3311 bool changed = false; | 3417 bool changed = false; |
| 3312 if (FLAG_load_cse) { | 3418 if (FLAG_load_cse) { |
| 3313 GrowableArray<BitVector*> kill_by_offs(10); | 3419 GrowableArray<BitVector*> kill_by_offs(10); |
| 3314 const intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs); | 3420 DirectChainedHashMap<LoadKeyValueTrait> map; |
| 3421 const intptr_t max_expr_id = |
| 3422 NumberLoadExpressions(graph, &map, &kill_by_offs); |
| 3315 if (max_expr_id > 0) { | 3423 if (max_expr_id > 0) { |
| 3316 LoadOptimizer load_optimizer(graph, max_expr_id, kill_by_offs); | 3424 LoadOptimizer load_optimizer(graph, max_expr_id, &map, kill_by_offs); |
| 3317 load_optimizer.Optimize(); | 3425 load_optimizer.Optimize(); |
| 3318 } | 3426 } |
| 3319 } | 3427 } |
| 3320 | 3428 |
| 3321 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; | 3429 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; |
| 3322 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; | 3430 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; |
| 3323 | 3431 |
| 3324 return changed; | 3432 return changed; |
| 3325 } | 3433 } |
| 3326 | 3434 |
| (...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4161 | 4269 |
| 4162 if (FLAG_trace_constant_propagation) { | 4270 if (FLAG_trace_constant_propagation) { |
| 4163 OS::Print("\n==== After constant propagation ====\n"); | 4271 OS::Print("\n==== After constant propagation ====\n"); |
| 4164 FlowGraphPrinter printer(*graph_); | 4272 FlowGraphPrinter printer(*graph_); |
| 4165 printer.PrintBlocks(); | 4273 printer.PrintBlocks(); |
| 4166 } | 4274 } |
| 4167 } | 4275 } |
| 4168 | 4276 |
| 4169 | 4277 |
| 4170 } // namespace dart | 4278 } // namespace dart |
| OLD | NEW |