Chromium Code Reviews| 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 2758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2769 | 2769 |
| 2770 static bool IsLoadEliminationCandidate(Definition* def) { | 2770 static bool IsLoadEliminationCandidate(Definition* def) { |
| 2771 // Immutable loads (not affected by side effects) are handled | 2771 // Immutable loads (not affected by side effects) are handled |
| 2772 // in the DominatorBasedCSE pass. | 2772 // in the DominatorBasedCSE pass. |
| 2773 // TODO(fschneider): Extend to other load instructions. | 2773 // TODO(fschneider): Extend to other load instructions. |
| 2774 return (def->IsLoadField() && def->AffectedBySideEffect()) | 2774 return (def->IsLoadField() && def->AffectedBySideEffect()) |
| 2775 || def->IsLoadIndexed(); | 2775 || def->IsLoadIndexed(); |
| 2776 } | 2776 } |
| 2777 | 2777 |
| 2778 | 2778 |
| 2779 static intptr_t NumberLoadExpressions(FlowGraph* graph) { | 2779 static intptr_t ComputeLoadOffsetInWords(Definition* defn) { |
| 2780 if (defn->IsLoadIndexed()) { | |
| 2781 // We are assuming that LoadField is never used to load the first word. | |
| 2782 return 0; | |
| 2783 } | |
| 2784 | |
| 2785 LoadFieldInstr* load_field = defn->AsLoadField(); | |
| 2786 if (load_field != NULL) { | |
| 2787 const intptr_t idx = load_field->offset_in_bytes() / kWordSize; | |
| 2788 ASSERT(idx > 0); | |
| 2789 return idx; | |
| 2790 } | |
| 2791 | |
| 2792 UNREACHABLE(); | |
| 2793 return 0; | |
| 2794 } | |
| 2795 | |
| 2796 | |
| 2797 static bool IsInterferingStore(Instruction* instr, | |
| 2798 intptr_t* offset_in_words) { | |
| 2799 if (instr->IsStoreIndexed()) { | |
| 2800 // We are assuming that LoadField is never used to load the first word. | |
| 2801 *offset_in_words = 0; | |
| 2802 return true; | |
| 2803 } | |
| 2804 | |
| 2805 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField(); | |
| 2806 if (store_instance_field != NULL) { | |
| 2807 ASSERT(store_instance_field->field().Offset() != 0); | |
| 2808 *offset_in_words = store_instance_field->field().Offset() / kWordSize; | |
| 2809 return true; | |
| 2810 } | |
| 2811 | |
| 2812 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField(); | |
| 2813 if (store_vm_field != NULL) { | |
| 2814 ASSERT(store_vm_field->offset_in_bytes() != 0); | |
| 2815 *offset_in_words = store_vm_field->offset_in_bytes() / kWordSize; | |
| 2816 return true; | |
| 2817 } | |
| 2818 | |
| 2819 return false; | |
| 2820 } | |
| 2821 | |
| 2822 | |
| 2823 static intptr_t NumberLoadExpressions( | |
| 2824 FlowGraph* graph, | |
| 2825 GrowableArray<BitVector*>* kill_by_offs) { | |
| 2780 DirectChainedHashMap<PointerKeyValueTrait<Definition> > map; | 2826 DirectChainedHashMap<PointerKeyValueTrait<Definition> > map; |
| 2781 intptr_t expr_id = 0; | 2827 intptr_t expr_id = 0; |
| 2828 | |
| 2829 // Loads representing different expression ids will be collected and | |
| 2830 // used to build per offset kill sets. | |
| 2831 GrowableArray<Definition*> loads(10); | |
| 2832 | |
| 2782 for (BlockIterator it = graph->reverse_postorder_iterator(); | 2833 for (BlockIterator it = graph->reverse_postorder_iterator(); |
| 2783 !it.Done(); | 2834 !it.Done(); |
| 2784 it.Advance()) { | 2835 it.Advance()) { |
| 2785 BlockEntryInstr* block = it.Current(); | 2836 BlockEntryInstr* block = it.Current(); |
| 2786 for (ForwardInstructionIterator instr_it(block); | 2837 for (ForwardInstructionIterator instr_it(block); |
| 2787 !instr_it.Done(); | 2838 !instr_it.Done(); |
| 2788 instr_it.Advance()) { | 2839 instr_it.Advance()) { |
| 2789 Definition* defn = instr_it.Current()->AsDefinition(); | 2840 Definition* defn = instr_it.Current()->AsDefinition(); |
| 2790 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 2841 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
| 2791 continue; | 2842 continue; |
| 2792 } | 2843 } |
| 2793 Definition* result = map.Lookup(defn); | 2844 Definition* result = map.Lookup(defn); |
| 2794 if (result == NULL) { | 2845 if (result == NULL) { |
| 2795 map.Insert(defn); | 2846 map.Insert(defn); |
| 2796 defn->set_expr_id(expr_id++); | 2847 defn->set_expr_id(expr_id++); |
| 2848 loads.Add(defn); | |
| 2797 } else { | 2849 } else { |
| 2798 defn->set_expr_id(result->expr_id()); | 2850 defn->set_expr_id(result->expr_id()); |
| 2799 } | 2851 } |
| 2800 } | 2852 } |
| 2801 } | 2853 } |
| 2854 | |
| 2855 // Build per offset kill sets. Any store interferes only with loads from | |
| 2856 // the same offset. | |
| 2857 for (intptr_t i = 0; i < loads.length(); i++) { | |
| 2858 Definition* defn = loads[i]; | |
| 2859 | |
| 2860 const intptr_t offset_in_words = ComputeLoadOffsetInWords(defn); | |
| 2861 while (kill_by_offs->length() <= offset_in_words) { | |
| 2862 kill_by_offs->Add(NULL); | |
| 2863 } | |
| 2864 if ((*kill_by_offs)[offset_in_words] == NULL) { | |
| 2865 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id); | |
| 2866 } | |
| 2867 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id()); | |
| 2868 } | |
| 2869 | |
| 2870 | |
| 2802 return expr_id; | 2871 return expr_id; |
| 2803 } | 2872 } |
| 2804 | 2873 |
| 2805 | 2874 |
| 2806 static void ComputeAvailableLoads( | 2875 static void ComputeAvailableLoads( |
| 2807 FlowGraph* graph, | 2876 FlowGraph* graph, |
| 2808 intptr_t max_expr_id, | 2877 intptr_t max_expr_id, |
| 2809 const GrowableArray<BitVector*>& avail_in) { | 2878 const GrowableArray<BitVector*>& avail_in, |
| 2879 const GrowableArray<BitVector*>& kill_by_offs) { | |
| 2810 // Initialize gen-, kill-, out-sets. | 2880 // Initialize gen-, kill-, out-sets. |
| 2811 intptr_t num_blocks = graph->preorder().length(); | 2881 intptr_t num_blocks = graph->preorder().length(); |
| 2812 GrowableArray<BitVector*> avail_out(num_blocks); | 2882 GrowableArray<BitVector*> avail_out(num_blocks); |
| 2813 GrowableArray<BitVector*> avail_gen(num_blocks); | 2883 GrowableArray<BitVector*> avail_gen(num_blocks); |
| 2814 GrowableArray<BitVector*> avail_kill(num_blocks); | 2884 GrowableArray<BitVector*> avail_kill(num_blocks); |
| 2815 for (intptr_t i = 0; i < num_blocks; i++) { | 2885 for (intptr_t i = 0; i < num_blocks; i++) { |
| 2816 avail_out.Add(new BitVector(max_expr_id)); | 2886 avail_out.Add(new BitVector(max_expr_id)); |
| 2817 avail_gen.Add(new BitVector(max_expr_id)); | 2887 avail_gen.Add(new BitVector(max_expr_id)); |
| 2818 avail_kill.Add(new BitVector(max_expr_id)); | 2888 avail_kill.Add(new BitVector(max_expr_id)); |
| 2819 } | 2889 } |
| 2820 | 2890 |
| 2821 for (BlockIterator block_it = graph->reverse_postorder_iterator(); | 2891 for (BlockIterator block_it = graph->reverse_postorder_iterator(); |
| 2822 !block_it.Done(); | 2892 !block_it.Done(); |
| 2823 block_it.Advance()) { | 2893 block_it.Advance()) { |
| 2824 BlockEntryInstr* block = block_it.Current(); | 2894 BlockEntryInstr* block = block_it.Current(); |
| 2825 intptr_t preorder_number = block->preorder_number(); | 2895 intptr_t preorder_number = block->preorder_number(); |
| 2826 for (BackwardInstructionIterator instr_it(block); | 2896 for (BackwardInstructionIterator instr_it(block); |
| 2827 !instr_it.Done(); | 2897 !instr_it.Done(); |
| 2828 instr_it.Advance()) { | 2898 instr_it.Advance()) { |
| 2829 Instruction* instr = instr_it.Current(); | 2899 Instruction* instr = instr_it.Current(); |
| 2830 if (instr->HasSideEffect()) { | 2900 |
| 2901 intptr_t offset_in_words = 0; | |
| 2902 if (IsInterferingStore(instr, &offset_in_words)) { | |
| 2903 if ((offset_in_words < kill_by_offs.length()) && | |
| 2904 (kill_by_offs[offset_in_words] != NULL)) { | |
| 2905 avail_kill[preorder_number]->AddAll(kill_by_offs[offset_in_words]); | |
| 2906 } | |
| 2907 } else if (instr->HasSideEffect()) { | |
| 2831 avail_kill[preorder_number]->SetAll(); | 2908 avail_kill[preorder_number]->SetAll(); |
| 2832 break; | 2909 break; |
| 2833 } | 2910 } |
| 2834 Definition* defn = instr_it.Current()->AsDefinition(); | 2911 Definition* defn = instr_it.Current()->AsDefinition(); |
| 2835 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 2912 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
| 2836 continue; | 2913 continue; |
| 2837 } | 2914 } |
| 2838 avail_gen[preorder_number]->Add(defn->expr_id()); | 2915 |
| 2916 const intptr_t expr_id = defn->expr_id(); | |
| 2917 if (!avail_kill[preorder_number]->Contains(expr_id)) { | |
| 2918 avail_gen[preorder_number]->Add(expr_id); | |
| 2919 } | |
| 2839 } | 2920 } |
| 2840 avail_out[preorder_number]->CopyFrom(avail_gen[preorder_number]); | 2921 avail_out[preorder_number]->CopyFrom(avail_gen[preorder_number]); |
| 2841 } | 2922 } |
| 2842 | 2923 |
| 2843 BitVector* temp = new BitVector(avail_in[0]->length()); | 2924 BitVector* temp = new BitVector(avail_in[0]->length()); |
| 2844 | 2925 |
| 2845 bool changed = true; | 2926 bool changed = true; |
| 2846 while (changed) { | 2927 while (changed) { |
| 2847 changed = false; | 2928 changed = false; |
| 2848 | 2929 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2880 if (block_out->KillAndAdd(block_kill, block_gen)) changed = true; | 2961 if (block_out->KillAndAdd(block_kill, block_gen)) changed = true; |
| 2881 } | 2962 } |
| 2882 } | 2963 } |
| 2883 } | 2964 } |
| 2884 } | 2965 } |
| 2885 | 2966 |
| 2886 | 2967 |
| 2887 static bool OptimizeLoads( | 2968 static bool OptimizeLoads( |
| 2888 BlockEntryInstr* block, | 2969 BlockEntryInstr* block, |
| 2889 GrowableArray<Definition*>* definitions, | 2970 GrowableArray<Definition*>* definitions, |
| 2890 const GrowableArray<BitVector*>& avail_in) { | 2971 const GrowableArray<BitVector*>& avail_in, |
| 2972 const GrowableArray<BitVector*>& kill_by_offs) { | |
| 2891 // TODO(fschneider): Factor out code shared with the existing CSE pass. | 2973 // TODO(fschneider): Factor out code shared with the existing CSE pass. |
| 2892 | 2974 |
| 2893 // Delete loads that are killed (not available) at the entry. | 2975 // Delete loads that are killed (not available) at the entry. |
| 2894 intptr_t pre_num = block->preorder_number(); | 2976 intptr_t pre_num = block->preorder_number(); |
| 2895 ASSERT(avail_in[pre_num]->length() == definitions->length()); | 2977 ASSERT(avail_in[pre_num]->length() == definitions->length()); |
| 2896 for (intptr_t i = 0; i < avail_in[pre_num]->length(); i++) { | 2978 for (intptr_t i = 0; i < avail_in[pre_num]->length(); i++) { |
| 2897 if (!avail_in[pre_num]->Contains(i)) { | 2979 if (!avail_in[pre_num]->Contains(i)) { |
| 2898 (*definitions)[i] = NULL; | 2980 (*definitions)[i] = NULL; |
| 2899 } | 2981 } |
| 2900 } | 2982 } |
| 2901 | 2983 |
| 2902 bool changed = false; | 2984 bool changed = false; |
| 2903 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2985 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 2904 Instruction* instr = it.Current(); | 2986 Instruction* instr = it.Current(); |
| 2905 if (instr->HasSideEffect()) { | 2987 |
| 2988 intptr_t offset_in_words = 0; | |
| 2989 if (IsInterferingStore(instr, &offset_in_words)) { | |
| 2990 if ((offset_in_words < kill_by_offs.length()) && | |
| 2991 (kill_by_offs[offset_in_words] != NULL)) { | |
| 2992 for (BitVector::Iterator it(kill_by_offs[offset_in_words]); | |
| 2993 !it.Done(); | |
| 2994 it.Advance()) { | |
| 2995 (*definitions)[it.Current()] = NULL; | |
| 2996 } | |
| 2997 } | |
|
Florian Schneider
2012/11/29 13:42:48
Maybe continue already here since IsInterferingSto
| |
| 2998 } else if (instr->HasSideEffect()) { | |
| 2906 // Handle local side effects by clearing current definitions. | 2999 // Handle local side effects by clearing current definitions. |
| 2907 for (intptr_t i = 0; i < definitions->length(); i++) { | 3000 for (intptr_t i = 0; i < definitions->length(); i++) { |
| 2908 (*definitions)[i] = NULL; | 3001 (*definitions)[i] = NULL; |
| 2909 } | 3002 } |
| 2910 continue; | 3003 continue; |
| 2911 } | 3004 } |
| 2912 Definition* defn = instr->AsDefinition(); | 3005 Definition* defn = instr->AsDefinition(); |
| 2913 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 3006 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
| 2914 continue; | 3007 continue; |
| 2915 } | 3008 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2930 } | 3023 } |
| 2931 } | 3024 } |
| 2932 | 3025 |
| 2933 // Process children in the dominator tree recursively. | 3026 // Process children in the dominator tree recursively. |
| 2934 intptr_t num_children = block->dominated_blocks().length(); | 3027 intptr_t num_children = block->dominated_blocks().length(); |
| 2935 for (intptr_t i = 0; i < num_children; ++i) { | 3028 for (intptr_t i = 0; i < num_children; ++i) { |
| 2936 BlockEntryInstr* child = block->dominated_blocks()[i]; | 3029 BlockEntryInstr* child = block->dominated_blocks()[i]; |
| 2937 if (i < num_children - 1) { | 3030 if (i < num_children - 1) { |
| 2938 GrowableArray<Definition*> child_defs(definitions->length()); | 3031 GrowableArray<Definition*> child_defs(definitions->length()); |
| 2939 child_defs.AddArray(*definitions); | 3032 child_defs.AddArray(*definitions); |
| 2940 changed = OptimizeLoads(child, &child_defs, avail_in) || changed; | 3033 changed = OptimizeLoads(child, &child_defs, avail_in, kill_by_offs) || |
| 3034 changed; | |
| 2941 } else { | 3035 } else { |
| 2942 changed = OptimizeLoads(child, definitions, avail_in) || changed; | 3036 changed = OptimizeLoads(child, definitions, avail_in, kill_by_offs) || |
| 3037 changed; | |
| 2943 } | 3038 } |
| 2944 } | 3039 } |
| 2945 return changed; | 3040 return changed; |
| 2946 } | 3041 } |
| 2947 | 3042 |
| 2948 | 3043 |
| 2949 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { | 3044 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
| 2950 bool changed = false; | 3045 bool changed = false; |
| 2951 if (FLAG_load_cse) { | 3046 if (FLAG_load_cse) { |
| 2952 intptr_t max_expr_id = NumberLoadExpressions(graph); | 3047 GrowableArray<BitVector*> kill_by_offs(10); |
| 3048 intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs); | |
| 2953 if (max_expr_id > 0) { | 3049 if (max_expr_id > 0) { |
| 2954 intptr_t num_blocks = graph->preorder().length(); | 3050 intptr_t num_blocks = graph->preorder().length(); |
| 2955 GrowableArray<BitVector*> avail_in(num_blocks); | 3051 GrowableArray<BitVector*> avail_in(num_blocks); |
| 2956 for (intptr_t i = 0; i < num_blocks; i++) { | 3052 for (intptr_t i = 0; i < num_blocks; i++) { |
| 2957 avail_in.Add(new BitVector(max_expr_id)); | 3053 avail_in.Add(new BitVector(max_expr_id)); |
| 2958 } | 3054 } |
| 2959 | 3055 |
| 2960 ComputeAvailableLoads(graph, max_expr_id, avail_in); | 3056 ComputeAvailableLoads(graph, max_expr_id, avail_in, kill_by_offs); |
| 2961 | 3057 |
| 2962 GrowableArray<Definition*> definitions(max_expr_id); | 3058 GrowableArray<Definition*> definitions(max_expr_id); |
| 2963 for (intptr_t j = 0; j < max_expr_id ; j++) { | 3059 for (intptr_t j = 0; j < max_expr_id ; j++) { |
| 2964 definitions.Add(NULL); | 3060 definitions.Add(NULL); |
| 2965 } | 3061 } |
| 2966 changed = OptimizeLoads(graph->graph_entry(), &definitions, avail_in); | 3062 changed = OptimizeLoads( |
| 3063 graph->graph_entry(), &definitions, avail_in, kill_by_offs); | |
| 2967 } | 3064 } |
| 2968 } | 3065 } |
| 2969 | 3066 |
| 2970 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; | 3067 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; |
| 2971 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; | 3068 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; |
| 2972 | 3069 |
| 2973 return changed; | 3070 return changed; |
| 2974 } | 3071 } |
| 2975 | 3072 |
| 2976 | 3073 |
| (...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3801 | 3898 |
| 3802 if (FLAG_trace_constant_propagation) { | 3899 if (FLAG_trace_constant_propagation) { |
| 3803 OS::Print("\n==== After constant propagation ====\n"); | 3900 OS::Print("\n==== After constant propagation ====\n"); |
| 3804 FlowGraphPrinter printer(*graph_); | 3901 FlowGraphPrinter printer(*graph_); |
| 3805 printer.PrintBlocks(); | 3902 printer.PrintBlocks(); |
| 3806 } | 3903 } |
| 3807 } | 3904 } |
| 3808 | 3905 |
| 3809 | 3906 |
| 3810 } // namespace dart | 3907 } // namespace dart |
| OLD | NEW |