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 2863 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2874 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id); | 2874 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id); |
| 2875 } | 2875 } |
| 2876 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id()); | 2876 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id()); |
| 2877 } | 2877 } |
| 2878 | 2878 |
| 2879 | 2879 |
| 2880 return expr_id; | 2880 return expr_id; |
| 2881 } | 2881 } |
| 2882 | 2882 |
| 2883 | 2883 |
| 2884 static void ComputeAvailableLoads( | 2884 class LoadOptimizer : public ValueObject { |
|
srdjan
2012/12/13 18:27:15
This is a long class. Maybe it warrants its own fi
| |
| 2885 FlowGraph* graph, | 2885 public: |
| 2886 intptr_t max_expr_id, | 2886 LoadOptimizer(FlowGraph* graph, |
| 2887 const GrowableArray<BitVector*>& avail_in, | 2887 intptr_t max_expr_id, |
| 2888 const GrowableArray<BitVector*>& kill_by_offs) { | 2888 const GrowableArray<BitVector*>& kill_by_offset) |
| 2889 // Initialize gen-, kill-, out-sets. | 2889 : graph_(graph), |
| 2890 intptr_t num_blocks = graph->preorder().length(); | 2890 max_expr_id_(max_expr_id), |
| 2891 GrowableArray<BitVector*> avail_out(num_blocks); | 2891 kill_by_offset_(kill_by_offset), |
| 2892 GrowableArray<BitVector*> avail_gen(num_blocks); | 2892 in_(graph_->preorder().length()), |
| 2893 GrowableArray<BitVector*> avail_kill(num_blocks); | 2893 out_(graph_->preorder().length()), |
| 2894 for (intptr_t i = 0; i < num_blocks; i++) { | 2894 gen_(graph_->preorder().length()), |
| 2895 avail_out.Add(new BitVector(max_expr_id)); | 2895 kill_(graph_->preorder().length()), |
| 2896 avail_gen.Add(new BitVector(max_expr_id)); | 2896 exposed_values_(graph_->preorder().length()), |
| 2897 avail_kill.Add(new BitVector(max_expr_id)); | 2897 out_values_(graph_->preorder().length()), |
| 2898 } | 2898 phis_(5), |
| 2899 | 2899 worklist_(5), |
| 2900 for (BlockIterator block_it = graph->reverse_postorder_iterator(); | 2900 in_worklist_(NULL) { |
| 2901 !block_it.Done(); | 2901 const intptr_t num_blocks = graph_->preorder().length(); |
| 2902 block_it.Advance()) { | 2902 for (intptr_t i = 0; i < num_blocks; i++) { |
| 2903 BlockEntryInstr* block = block_it.Current(); | 2903 out_.Add(new BitVector(max_expr_id_)); |
| 2904 intptr_t preorder_number = block->preorder_number(); | 2904 gen_.Add(new BitVector(max_expr_id_)); |
| 2905 for (BackwardInstructionIterator instr_it(block); | 2905 kill_.Add(new BitVector(max_expr_id_)); |
| 2906 !instr_it.Done(); | 2906 in_.Add(new BitVector(max_expr_id_)); |
| 2907 instr_it.Advance()) { | 2907 |
| 2908 Instruction* instr = instr_it.Current(); | 2908 exposed_values_.Add(NULL); |
| 2909 | 2909 out_values_.Add(NULL); |
| 2910 intptr_t offset_in_words = 0; | 2910 } |
| 2911 if (IsInterferingStore(instr, &offset_in_words)) { | 2911 } |
| 2912 if ((offset_in_words < kill_by_offs.length()) && | 2912 |
| 2913 (kill_by_offs[offset_in_words] != NULL)) { | 2913 void Optimize() { |
| 2914 avail_kill[preorder_number]->AddAll(kill_by_offs[offset_in_words]); | 2914 ComputeInitialSets(); |
| 2915 } | 2915 ComputeOutValues(); |
| 2916 ASSERT(instr->IsDefinition() && | 2916 ForwardLoads(); |
| 2917 !IsLoadEliminationCandidate(instr->AsDefinition())); | 2917 EmitPhis(); |
| 2918 continue; | 2918 } |
| 2919 } else if (instr->HasSideEffect()) { | 2919 |
| 2920 avail_kill[preorder_number]->SetAll(); | 2920 private: |
| 2921 break; | 2921 // Compute sets of loads generated and killed by each block. |
| 2922 } | 2922 // Additionally compute upwards exposed and generated loads for each block. |
| 2923 Definition* defn = instr->AsDefinition(); | 2923 // Exposed loads are those that can be replaced if a corresponding |
| 2924 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 2924 // reaching load will be found. |
| 2925 continue; | 2925 // Loads that are locally redundant will be replaced as we go through |
| 2926 } | 2926 // instructions. |
| 2927 | 2927 void ComputeInitialSets() { |
| 2928 const intptr_t expr_id = defn->expr_id(); | 2928 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 2929 if (!avail_kill[preorder_number]->Contains(expr_id)) { | |
| 2930 avail_gen[preorder_number]->Add(expr_id); | |
| 2931 } | |
| 2932 } | |
| 2933 avail_out[preorder_number]->CopyFrom(avail_gen[preorder_number]); | |
| 2934 } | |
| 2935 | |
| 2936 BitVector* temp = new BitVector(avail_in[0]->length()); | |
| 2937 | |
| 2938 bool changed = true; | |
| 2939 while (changed) { | |
| 2940 changed = false; | |
| 2941 | |
| 2942 for (BlockIterator block_it = graph->reverse_postorder_iterator(); | |
| 2943 !block_it.Done(); | 2929 !block_it.Done(); |
| 2944 block_it.Advance()) { | 2930 block_it.Advance()) { |
| 2945 BlockEntryInstr* block = block_it.Current(); | 2931 BlockEntryInstr* block = block_it.Current(); |
| 2946 BitVector* block_in = avail_in[block->preorder_number()]; | 2932 const intptr_t preorder_number = block->preorder_number(); |
| 2947 BitVector* block_out = avail_out[block->preorder_number()]; | 2933 |
| 2948 BitVector* block_kill = avail_kill[block->preorder_number()]; | 2934 BitVector* kill = kill_[preorder_number]; |
| 2949 BitVector* block_gen = avail_gen[block->preorder_number()]; | 2935 BitVector* gen = gen_[preorder_number]; |
| 2950 | 2936 |
| 2951 if (FLAG_trace_optimization) { | 2937 ZoneGrowableArray<Definition*>* exposed_values = NULL; |
| 2952 OS::Print("B%"Pd"", block->block_id()); | 2938 ZoneGrowableArray<Definition*>* out_values = NULL; |
| 2953 block_in->Print(); | 2939 |
| 2954 block_out->Print(); | 2940 for (ForwardInstructionIterator instr_it(block); |
| 2955 OS::Print("\n"); | 2941 !instr_it.Done(); |
| 2956 } | 2942 instr_it.Advance()) { |
| 2957 | 2943 Instruction* instr = instr_it.Current(); |
| 2958 // Compute block_in as the intersection of all out(p) where p | 2944 |
| 2959 // is a predecessor of the current block. | 2945 intptr_t offset_in_words = 0; |
| 2960 if (block->IsGraphEntry()) { | 2946 if (IsInterferingStore(instr, &offset_in_words)) { |
| 2961 temp->Clear(); | 2947 // Interfering stores kill only loads from the same offset. |
| 2962 } else { | 2948 if ((offset_in_words < kill_by_offset_.length()) && |
| 2963 temp->SetAll(); | 2949 (kill_by_offset_[offset_in_words] != NULL)) { |
| 2964 ASSERT(block->PredecessorCount() > 0); | 2950 kill->AddAll(kill_by_offset_[offset_in_words]); |
| 2965 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 2951 // There is no need to clear out_values when clearing GEN set |
| 2966 BlockEntryInstr* pred = block->PredecessorAt(i); | 2952 // because only those values that are in the GEN set |
| 2967 BitVector* pred_out = avail_out[pred->preorder_number()]; | 2953 // will ever be used. |
| 2968 temp->Intersect(*pred_out); | 2954 gen->RemoveAll(kill_by_offset_[offset_in_words]); |
| 2969 } | 2955 } |
| 2970 } | 2956 ASSERT(instr->IsDefinition() && |
| 2971 if (!temp->Equals(*block_in)) { | 2957 !IsLoadEliminationCandidate(instr->AsDefinition())); |
| 2972 block_in->CopyFrom(temp); | 2958 continue; |
| 2973 if (block_out->KillAndAdd(block_kill, block_gen)) changed = true; | 2959 } |
| 2974 } | 2960 |
| 2975 } | 2961 // Other instructions with side effects kill all loads. |
| 2976 } | 2962 if (instr->HasSideEffect()) { |
| 2977 } | 2963 kill->SetAll(); |
| 2978 | 2964 // There is no need to clear out_values when clearing GEN set |
| 2979 | 2965 // because only those values that are in the GEN set |
| 2980 static bool OptimizeLoads( | 2966 // will ever be used. |
| 2981 BlockEntryInstr* block, | 2967 gen->Clear(); |
| 2982 GrowableArray<Definition*>* definitions, | 2968 continue; |
| 2983 const GrowableArray<BitVector*>& avail_in, | 2969 } |
| 2984 const GrowableArray<BitVector*>& kill_by_offs) { | 2970 |
| 2985 // TODO(fschneider): Factor out code shared with the existing CSE pass. | 2971 Definition* defn = instr->AsDefinition(); |
| 2986 | 2972 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
| 2987 // Delete loads that are killed (not available) at the entry. | 2973 continue; |
| 2988 intptr_t pre_num = block->preorder_number(); | 2974 } |
| 2989 ASSERT(avail_in[pre_num]->length() == definitions->length()); | 2975 |
| 2990 for (intptr_t i = 0; i < avail_in[pre_num]->length(); i++) { | 2976 const intptr_t expr_id = defn->expr_id(); |
| 2991 if (!avail_in[pre_num]->Contains(i)) { | 2977 if (gen->Contains(expr_id)) { |
| 2992 (*definitions)[i] = NULL; | 2978 // This is a locally redundant load. |
| 2993 } | 2979 ASSERT((out_values != NULL) && ((*out_values)[expr_id] != NULL)); |
| 2994 } | 2980 |
| 2995 | 2981 if (FLAG_trace_optimization) { |
| 2996 bool changed = false; | 2982 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", |
| 2997 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2983 defn->ssa_temp_index(), |
| 2998 Instruction* instr = it.Current(); | 2984 (*out_values)[expr_id]->ssa_temp_index()); |
| 2999 | 2985 } |
| 3000 intptr_t offset_in_words = 0; | 2986 |
| 3001 if (IsInterferingStore(instr, &offset_in_words)) { | 2987 defn->ReplaceUsesWith((*out_values)[expr_id]); |
| 3002 if ((offset_in_words < kill_by_offs.length()) && | 2988 instr_it.RemoveCurrentFromGraph(); |
| 3003 (kill_by_offs[offset_in_words] != NULL)) { | 2989 continue; |
| 3004 for (BitVector::Iterator it(kill_by_offs[offset_in_words]); | 2990 } else if (!kill->Contains(expr_id)) { |
| 3005 !it.Done(); | 2991 // This is an exposed load: it is the first representative of a |
| 3006 it.Advance()) { | 2992 // given expression id and it is not killed on the path from |
| 3007 (*definitions)[it.Current()] = NULL; | 2993 // the block entry. |
| 3008 } | 2994 if (exposed_values == NULL) { |
| 3009 } | 2995 static const intptr_t kMaxExposedValuesInitialSize = 5; |
| 3010 ASSERT(instr->IsDefinition() && | 2996 exposed_values = new ZoneGrowableArray<Definition*>( |
| 3011 !IsLoadEliminationCandidate(instr->AsDefinition())); | 2997 Utils::Minimum(kMaxExposedValuesInitialSize, max_expr_id_)); |
| 3012 continue; | 2998 } |
| 3013 } else if (instr->HasSideEffect()) { | 2999 |
| 3014 // Handle local side effects by clearing current definitions. | 3000 exposed_values->Add(defn); |
| 3015 for (intptr_t i = 0; i < definitions->length(); i++) { | 3001 } |
| 3016 (*definitions)[i] = NULL; | 3002 |
| 3017 } | 3003 gen->Add(expr_id); |
| 3018 continue; | 3004 |
| 3019 } | 3005 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 3020 Definition* defn = instr->AsDefinition(); | 3006 (*out_values)[expr_id] = defn; |
| 3021 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 3007 } |
| 3022 continue; | 3008 |
| 3023 } | 3009 out_[preorder_number]->CopyFrom(gen); |
| 3024 Definition* result = (*definitions)[defn->expr_id()]; | 3010 exposed_values_[preorder_number] = exposed_values; |
| 3025 if (result == NULL) { | 3011 out_values_[preorder_number] = out_values; |
| 3026 (*definitions)[defn->expr_id()] = defn; | 3012 } |
| 3027 continue; | 3013 } |
| 3028 } | 3014 |
| 3029 | 3015 // Compute OUT sets and corresponding out_values mappings by propagating them |
| 3030 // Replace current with lookup result. | 3016 // iteratively until fix point is reached. |
| 3031 defn->ReplaceUsesWith(result); | 3017 // No replacement is done at this point and thus any out_value[expr_id] is |
| 3032 it.RemoveCurrentFromGraph(); | 3018 // changed at most once: from NULL to an actual value. |
| 3033 changed = true; | 3019 // When merging incoming loads we might need to create a phi. |
| 3034 if (FLAG_trace_optimization) { | 3020 // These phis are not inserted at the graph immediately because some of them |
| 3035 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", | 3021 // might become redundant after load forwarding is done. |
| 3036 defn->ssa_temp_index(), | 3022 void ComputeOutValues() { |
| 3037 result->ssa_temp_index()); | 3023 BitVector* temp = new BitVector(max_expr_id_); |
| 3038 } | 3024 |
| 3039 } | 3025 bool changed = true; |
| 3040 | 3026 while (changed) { |
| 3041 // Process children in the dominator tree recursively. | 3027 changed = false; |
| 3042 intptr_t num_children = block->dominated_blocks().length(); | 3028 |
| 3043 for (intptr_t i = 0; i < num_children; ++i) { | 3029 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 3044 BlockEntryInstr* child = block->dominated_blocks()[i]; | 3030 !block_it.Done(); |
| 3045 if (i < num_children - 1) { | 3031 block_it.Advance()) { |
| 3046 GrowableArray<Definition*> child_defs(definitions->length()); | 3032 BlockEntryInstr* block = block_it.Current(); |
| 3047 child_defs.AddArray(*definitions); | 3033 |
| 3048 changed = OptimizeLoads(child, &child_defs, avail_in, kill_by_offs) || | 3034 const intptr_t preorder_number = block->preorder_number(); |
| 3049 changed; | 3035 |
| 3036 BitVector* block_in = in_[preorder_number]; | |
| 3037 BitVector* block_out = out_[preorder_number]; | |
| 3038 BitVector* block_kill = kill_[preorder_number]; | |
| 3039 BitVector* block_gen = gen_[preorder_number]; | |
| 3040 | |
| 3041 if (FLAG_trace_optimization) { | |
| 3042 OS::Print("B%"Pd"", block->block_id()); | |
| 3043 block_in->Print(); | |
| 3044 block_out->Print(); | |
| 3045 block_kill->Print(); | |
| 3046 block_gen->Print(); | |
| 3047 OS::Print("\n"); | |
| 3048 } | |
| 3049 | |
| 3050 ZoneGrowableArray<Definition*>* block_out_values = | |
| 3051 out_values_[preorder_number]; | |
| 3052 | |
| 3053 // Compute block_in as the intersection of all out(p) where p | |
| 3054 // is a predecessor of the current block. | |
| 3055 if (block->IsGraphEntry()) { | |
| 3056 temp->Clear(); | |
| 3057 } else { | |
| 3058 // TODO(vegorov): this can be optimized for the case of a single | |
| 3059 // predecessor. | |
| 3060 // TODO(vegorov): this can be reordered to reduce amount of operations | |
| 3061 // temp->CopyFrom(first_predecessor) | |
| 3062 temp->SetAll(); | |
| 3063 ASSERT(block->PredecessorCount() > 0); | |
| 3064 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | |
| 3065 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 3066 BitVector* pred_out = out_[pred->preorder_number()]; | |
| 3067 temp->Intersect(*pred_out); | |
| 3068 } | |
| 3069 } | |
| 3070 | |
| 3071 if (!temp->Equals(*block_in)) { | |
| 3072 // If IN set has changed propagate the change to OUT set. | |
| 3073 block_in->CopyFrom(temp); | |
| 3074 if (block_out->KillAndAdd(block_kill, block_in)) { | |
| 3075 // If OUT set has changed then we have new values available out of | |
| 3076 // the block. Compute these values creating phi where necessary. | |
| 3077 for (BitVector::Iterator it(block_out); | |
| 3078 !it.Done(); | |
| 3079 it.Advance()) { | |
| 3080 const intptr_t expr_id = it.Current(); | |
| 3081 | |
| 3082 if (block_out_values == NULL) { | |
| 3083 out_values_[preorder_number] = block_out_values = | |
| 3084 CreateBlockOutValues(); | |
| 3085 } | |
| 3086 | |
| 3087 if ((*block_out_values)[expr_id] == NULL) { | |
| 3088 ASSERT(block->PredecessorCount() > 0); | |
| 3089 (*block_out_values)[expr_id] = | |
| 3090 MergeIncomingValues(block, expr_id); | |
| 3091 } | |
| 3092 } | |
| 3093 changed = true; | |
| 3094 } | |
| 3095 } | |
| 3096 | |
| 3097 if (FLAG_trace_optimization) { | |
| 3098 OS::Print("after B%"Pd"", block->block_id()); | |
| 3099 block_in->Print(); | |
| 3100 block_out->Print(); | |
| 3101 block_kill->Print(); | |
| 3102 block_gen->Print(); | |
| 3103 OS::Print("\n"); | |
| 3104 } | |
| 3105 } | |
| 3106 } | |
| 3107 } | |
| 3108 | |
| 3109 // Compute incoming value for the given expression id. | |
| 3110 // Will create a phi if different values are incoming from multiple | |
| 3111 // predecessors. | |
| 3112 Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t expr_id) { | |
| 3113 // First check if the same value is coming in from all predecessors. | |
| 3114 Definition* incoming = NULL; | |
| 3115 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | |
| 3116 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 3117 ZoneGrowableArray<Definition*>* pred_out_values = | |
| 3118 out_values_[pred->preorder_number()]; | |
| 3119 if (incoming == NULL) { | |
| 3120 incoming = (*pred_out_values)[expr_id]; | |
| 3121 } else if (incoming != (*pred_out_values)[expr_id]) { | |
| 3122 incoming = NULL; | |
| 3123 break; | |
| 3124 } | |
| 3125 } | |
| 3126 | |
| 3127 if (incoming != NULL) { | |
| 3128 return incoming; | |
| 3129 } | |
| 3130 | |
| 3131 // Incoming values are different. Phi is required to merge. | |
| 3132 PhiInstr* phi = new PhiInstr( | |
| 3133 block->AsJoinEntry(), block->PredecessorCount()); | |
| 3134 | |
| 3135 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | |
| 3136 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 3137 ZoneGrowableArray<Definition*>* pred_out_values = | |
| 3138 out_values_[pred->preorder_number()]; | |
| 3139 ASSERT((*pred_out_values)[expr_id] != NULL); | |
| 3140 | |
| 3141 // Sets of outgoing values are not linked into use lists so | |
| 3142 // they might contain values that were replaced and removed | |
| 3143 // from the graph by this iteration. | |
| 3144 // To prevent using them we additionally mark definitions themselves | |
| 3145 // as replaced and store a pointer to the replacement. | |
| 3146 Value* input = new Value((*pred_out_values)[expr_id]->Replacement()); | |
| 3147 phi->SetInputAt(i, input); | |
| 3148 | |
| 3149 // TODO(vegorov): add a helper function to handle input insertion. | |
| 3150 input->set_instruction(phi); | |
| 3151 input->set_use_index(i); | |
| 3152 input->AddToInputUseList(); | |
| 3153 } | |
| 3154 | |
| 3155 phi->set_ssa_temp_index(graph_->alloc_ssa_temp_index()); | |
| 3156 phis_.Add(phi); // Postpone phi insertion until after load forwarding. | |
| 3157 | |
| 3158 return phi; | |
| 3159 } | |
| 3160 | |
| 3161 // Iterate over basic blocks and replace exposed loads with incoming | |
| 3162 // values. | |
| 3163 void ForwardLoads() { | |
| 3164 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | |
| 3165 !block_it.Done(); | |
| 3166 block_it.Advance()) { | |
| 3167 BlockEntryInstr* block = block_it.Current(); | |
| 3168 | |
| 3169 ZoneGrowableArray<Definition*>* loads = | |
| 3170 exposed_values_[block->preorder_number()]; | |
| 3171 if (loads == NULL) continue; // No exposed loads. | |
| 3172 | |
| 3173 BitVector* in = in_[block->preorder_number()]; | |
| 3174 | |
| 3175 for (intptr_t i = 0; i < loads->length(); i++) { | |
| 3176 Definition* load = (*loads)[i]; | |
| 3177 if (!in->Contains(load->expr_id())) continue; // No incoming value. | |
| 3178 | |
| 3179 Definition* replacement = MergeIncomingValues(block, load->expr_id()); | |
| 3180 | |
| 3181 // Sets of outgoing values are not linked into use lists so | |
| 3182 // they might contain values that were replace and removed | |
| 3183 // from the graph by this iteration. | |
| 3184 // To prevent using them we additionally mark definitions themselves | |
| 3185 // as replaced and store a pointer to the replacement. | |
| 3186 replacement = replacement->Replacement(); | |
| 3187 | |
| 3188 if (load != replacement) { | |
| 3189 if (FLAG_trace_optimization) { | |
| 3190 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", | |
| 3191 load->ssa_temp_index(), | |
| 3192 replacement->ssa_temp_index()); | |
| 3193 } | |
| 3194 | |
| 3195 load->ReplaceUsesWith(replacement); | |
| 3196 load->RemoveFromGraph(); | |
| 3197 load->SetReplacement(replacement); | |
| 3198 } | |
| 3199 } | |
| 3200 } | |
| 3201 } | |
| 3202 | |
| 3203 // Check if the given phi take the same value on all code paths. | |
| 3204 // Eliminate it as redundant if this is the case. | |
| 3205 // When analyzing phi operands assumes that only generated during | |
| 3206 // this load phase can be redundant. They can be distinguished because | |
| 3207 // they are not marked alive. | |
| 3208 // TODO(vegorov): move this into a separate phase over all phis. | |
| 3209 bool EliminateRedundantPhi(PhiInstr* phi) { | |
| 3210 Definition* value = NULL; // Possible value of this phi. | |
| 3211 | |
| 3212 worklist_.Clear(); | |
| 3213 if (in_worklist_ == NULL) { | |
| 3214 in_worklist_ = new BitVector(graph_->current_ssa_temp_index()); | |
| 3050 } else { | 3215 } else { |
| 3051 changed = OptimizeLoads(child, definitions, avail_in, kill_by_offs) || | 3216 in_worklist_->Clear(); |
| 3052 changed; | 3217 } |
| 3053 } | 3218 |
| 3054 } | 3219 worklist_.Add(phi); |
| 3055 return changed; | 3220 in_worklist_->Add(phi->ssa_temp_index()); |
| 3056 } | 3221 |
| 3222 for (intptr_t i = 0; i < worklist_.length(); i++) { | |
| 3223 PhiInstr* phi = worklist_[i]; | |
| 3224 | |
| 3225 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
| 3226 Definition* input = phi->InputAt(i)->definition(); | |
| 3227 if (input == phi) continue; | |
| 3228 | |
| 3229 PhiInstr* phi_input = input->AsPhi(); | |
| 3230 if ((phi_input != NULL) && !phi_input->is_alive()) { | |
| 3231 if (!in_worklist_->Contains(phi_input->ssa_temp_index())) { | |
| 3232 worklist_.Add(phi_input); | |
| 3233 in_worklist_->Add(phi_input->ssa_temp_index()); | |
| 3234 } | |
| 3235 continue; | |
| 3236 } | |
| 3237 | |
| 3238 if (value == NULL) { | |
| 3239 value = input; | |
| 3240 } else if (value != input) { | |
| 3241 return false; // This phi is not redundant. | |
| 3242 } | |
| 3243 } | |
| 3244 } | |
| 3245 | |
| 3246 // All phis in the worklist are redundant and have the same computed | |
| 3247 // value on all code paths. | |
| 3248 ASSERT(value != NULL); | |
| 3249 for (intptr_t i = 0; i < worklist_.length(); i++) { | |
| 3250 worklist_[i]->ReplaceUsesWith(value); | |
| 3251 } | |
| 3252 | |
| 3253 return true; | |
| 3254 } | |
| 3255 | |
| 3256 // Emit non-redundant phis created during ComputeOutValues and ForwardLoads. | |
| 3257 void EmitPhis() { | |
| 3258 for (intptr_t i = 0; i < phis_.length(); i++) { | |
| 3259 PhiInstr* phi = phis_[i]; | |
| 3260 if ((phi->input_use_list() != NULL) && !EliminateRedundantPhi(phi)) { | |
| 3261 phi->mark_alive(); | |
| 3262 phi->block()->InsertPhi(phi); | |
| 3263 } | |
| 3264 } | |
| 3265 } | |
| 3266 | |
| 3267 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { | |
| 3268 ZoneGrowableArray<Definition*>* out = | |
| 3269 new ZoneGrowableArray<Definition*>(max_expr_id_); | |
| 3270 for (intptr_t i = 0; i < max_expr_id_; i++) { | |
| 3271 out->Add(NULL); | |
| 3272 } | |
| 3273 return out; | |
| 3274 } | |
| 3275 | |
| 3276 FlowGraph* graph_; | |
| 3277 const intptr_t max_expr_id_; | |
| 3278 | |
| 3279 // Mapping between field offsets in words and expression ids of loads from | |
| 3280 // that offset. | |
| 3281 const GrowableArray<BitVector*>& kill_by_offset_; | |
| 3282 | |
| 3283 // Per block sets of expression ids for loads that are: incoming (available | |
| 3284 // on the entry), outgoing (available on the exit), generated and killed. | |
| 3285 GrowableArray<BitVector*> in_; | |
| 3286 GrowableArray<BitVector*> out_; | |
| 3287 GrowableArray<BitVector*> gen_; | |
| 3288 GrowableArray<BitVector*> kill_; | |
| 3289 | |
| 3290 // Per block list of upwards exposed loads. | |
| 3291 GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_; | |
| 3292 | |
| 3293 // Per block mappings between expression ids and outgoing definitions that | |
| 3294 // represent those ids. | |
| 3295 GrowableArray<ZoneGrowableArray<Definition*>*> out_values_; | |
| 3296 | |
| 3297 // List of phis generated during ComputeOutValues and ForwardLoads. | |
| 3298 // Some of these phis might be redundant and thus a separate pass is | |
| 3299 // needed to emit only non-redundant ones. | |
| 3300 GrowableArray<PhiInstr*> phis_; | |
| 3301 | |
| 3302 // Auxiliary worklist used by redundant phi elimination. | |
| 3303 GrowableArray<PhiInstr*> worklist_; | |
| 3304 BitVector* in_worklist_; | |
| 3305 | |
| 3306 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); | |
| 3307 }; | |
| 3057 | 3308 |
| 3058 | 3309 |
| 3059 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { | 3310 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { |
| 3060 bool changed = false; | 3311 bool changed = false; |
| 3061 if (FLAG_load_cse) { | 3312 if (FLAG_load_cse) { |
| 3062 GrowableArray<BitVector*> kill_by_offs(10); | 3313 GrowableArray<BitVector*> kill_by_offs(10); |
| 3063 intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs); | 3314 const intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs); |
| 3064 if (max_expr_id > 0) { | 3315 if (max_expr_id > 0) { |
| 3065 intptr_t num_blocks = graph->preorder().length(); | 3316 LoadOptimizer load_optimizer(graph, max_expr_id, kill_by_offs); |
| 3066 GrowableArray<BitVector*> avail_in(num_blocks); | 3317 load_optimizer.Optimize(); |
| 3067 for (intptr_t i = 0; i < num_blocks; i++) { | 3318 } |
| 3068 avail_in.Add(new BitVector(max_expr_id)); | 3319 } |
| 3069 } | 3320 |
| 3070 | |
| 3071 ComputeAvailableLoads(graph, max_expr_id, avail_in, kill_by_offs); | |
| 3072 | |
| 3073 GrowableArray<Definition*> definitions(max_expr_id); | |
| 3074 for (intptr_t j = 0; j < max_expr_id ; j++) { | |
| 3075 definitions.Add(NULL); | |
| 3076 } | |
| 3077 changed = OptimizeLoads( | |
| 3078 graph->graph_entry(), &definitions, avail_in, kill_by_offs); | |
| 3079 } | |
| 3080 } | |
| 3081 | |
| 3082 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; | 3321 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; |
| 3083 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; | 3322 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; |
| 3084 | 3323 |
| 3085 return changed; | 3324 return changed; |
| 3086 } | 3325 } |
| 3087 | 3326 |
| 3088 | 3327 |
| 3089 bool DominatorBasedCSE::OptimizeRecursive( | 3328 bool DominatorBasedCSE::OptimizeRecursive( |
| 3090 BlockEntryInstr* block, | 3329 BlockEntryInstr* block, |
| 3091 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { | 3330 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { |
| (...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3922 | 4161 |
| 3923 if (FLAG_trace_constant_propagation) { | 4162 if (FLAG_trace_constant_propagation) { |
| 3924 OS::Print("\n==== After constant propagation ====\n"); | 4163 OS::Print("\n==== After constant propagation ====\n"); |
| 3925 FlowGraphPrinter printer(*graph_); | 4164 FlowGraphPrinter printer(*graph_); |
| 3926 printer.PrintBlocks(); | 4165 printer.PrintBlocks(); |
| 3927 } | 4166 } |
| 3928 } | 4167 } |
| 3929 | 4168 |
| 3930 | 4169 |
| 3931 } // namespace dart | 4170 } // namespace dart |
| OLD | NEW |