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

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

Issue 11505002: Improve redundant load elimination (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fix for real Created 8 years 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_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
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 {
2885 FlowGraph* graph, 2885 public:
2886 intptr_t max_expr_id, 2886 explicit LoadOptimizer(FlowGraph* graph,
Florian Schneider 2012/12/13 13:17:13 No explicit needed.
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
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 exposed_values = new ZoneGrowableArray<Definition*>(5);
Florian Schneider 2012/12/13 13:17:13 max_expr_id should be upper bound. Maybe sth like:
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
3010 ASSERT(instr->IsDefinition() && 2996 }
3011 !IsLoadEliminationCandidate(instr->AsDefinition())); 2997
3012 continue; 2998 exposed_values->Add(defn);
3013 } else if (instr->HasSideEffect()) { 2999 }
3014 // Handle local side effects by clearing current definitions. 3000
3015 for (intptr_t i = 0; i < definitions->length(); i++) { 3001 gen->Add(expr_id);
3016 (*definitions)[i] = NULL; 3002
3017 } 3003 if (out_values == NULL) out_values = CreateBlockOutValues();
3018 continue; 3004 (*out_values)[expr_id] = defn;
3019 } 3005 }
3020 Definition* defn = instr->AsDefinition(); 3006
3021 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { 3007 out_[preorder_number]->CopyFrom(gen);
3022 continue; 3008 exposed_values_[preorder_number] = exposed_values;
3023 } 3009 out_values_[preorder_number] = out_values;
3024 Definition* result = (*definitions)[defn->expr_id()]; 3010 }
3025 if (result == NULL) { 3011 }
3026 (*definitions)[defn->expr_id()] = defn; 3012
3027 continue; 3013 // Compute OUT sets and corresponding out_values mappings by propagating them
3028 } 3014 // iteratively until fix point is reached.
3029 3015 // No replacement is done at this point and thus any out_value[expr_id] is
3030 // Replace current with lookup result. 3016 // changed at most once: from NULL to an actual value.
3031 defn->ReplaceUsesWith(result); 3017 // When merging incomming loads we might need to create a phi.
Florian Schneider 2012/12/13 13:17:13 s/incomming/incoming/
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
3032 it.RemoveCurrentFromGraph(); 3018 // These phies are not inserted at the graph immediately because some of them
Florian Schneider 2012/12/13 13:17:13 s/phies/phis/
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
3033 changed = true; 3019 // might become redundant after load forwarding is done.
3034 if (FLAG_trace_optimization) { 3020 void ComputeOutValues() {
3035 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", 3021 BitVector* temp = new BitVector(max_expr_id_);
3036 defn->ssa_temp_index(), 3022
3037 result->ssa_temp_index()); 3023 bool changed = true;
3038 } 3024 while (changed) {
3039 } 3025 changed = false;
3040 3026
3041 // Process children in the dominator tree recursively. 3027 for (BlockIterator block_it = graph_->reverse_postorder_iterator();
3042 intptr_t num_children = block->dominated_blocks().length(); 3028 !block_it.Done();
3043 for (intptr_t i = 0; i < num_children; ++i) { 3029 block_it.Advance()) {
3044 BlockEntryInstr* child = block->dominated_blocks()[i]; 3030 BlockEntryInstr* block = block_it.Current();
3045 if (i < num_children - 1) { 3031
3046 GrowableArray<Definition*> child_defs(definitions->length()); 3032 const intptr_t preorder_number = block->preorder_number();
3047 child_defs.AddArray(*definitions); 3033
3048 changed = OptimizeLoads(child, &child_defs, avail_in, kill_by_offs) || 3034 BitVector* block_in = in_[preorder_number];
3049 changed; 3035 BitVector* block_out = out_[preorder_number];
3036 BitVector* block_kill = kill_[preorder_number];
3037 BitVector* block_gen = gen_[preorder_number];
3038
3039 if (FLAG_trace_optimization) {
3040 OS::Print("B%"Pd"", block->block_id());
3041 block_in->Print();
3042 block_out->Print();
3043 block_kill->Print();
3044 block_gen->Print();
3045 OS::Print("\n");
3046 }
3047
3048 ZoneGrowableArray<Definition*>* block_out_values =
3049 out_values_[preorder_number];
3050
3051 // Compute block_in as the intersection of all out(p) where p
3052 // is a predecessor of the current block.
3053 if (block->IsGraphEntry()) {
3054 temp->Clear();
3055 } else {
3056 // TODO(vegorov): this can be optimized for the case of a single
3057 // predecessor.
3058 // TODO(vegorov): this can be reordered to reduce amount of operations
3059 // temp->CopyFrom(first_predecessor)
3060 temp->SetAll();
3061 ASSERT(block->PredecessorCount() > 0);
3062 for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
3063 BlockEntryInstr* pred = block->PredecessorAt(i);
3064 BitVector* pred_out = out_[pred->preorder_number()];
3065 temp->Intersect(*pred_out);
3066 }
3067 }
3068
3069 if (!temp->Equals(*block_in)) {
3070 // If IN set has changed propagate the change to OUT set.
3071 block_in->CopyFrom(temp);
3072 if (block_out->KillAndAdd(block_kill, block_in)) {
3073 // If OUT set has changed then we have new values available out of
3074 // the block. Compute these values creating phi where necessary.
3075 for (BitVector::Iterator it(block_out);
3076 !it.Done();
3077 it.Advance()) {
3078 const intptr_t expr_id = it.Current();
3079
3080 if (block_out_values == NULL) {
3081 out_values_[preorder_number] = block_out_values =
3082 CreateBlockOutValues();
3083 }
3084
3085 if ((*block_out_values)[expr_id] == NULL) {
3086 ASSERT(block->PredecessorCount() > 0);
3087 (*block_out_values)[expr_id] =
3088 MergeIncomingValues(block, expr_id);
3089 }
3090 }
3091 changed = true;
3092 }
3093 }
3094
3095 if (FLAG_trace_optimization) {
3096 OS::Print("after B%"Pd"", block->block_id());
3097 block_in->Print();
3098 block_out->Print();
3099 block_kill->Print();
3100 block_gen->Print();
3101 OS::Print("\n");
3102 }
3103 }
3104 }
3105 }
3106
3107 // Compute incoming value for the given expression id.
3108 // Will create a phi if different values are incoming from multiple
3109 // predecessors.
3110 Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t expr_id) {
3111 // First check if the same value is coming in from all predecessors.
3112 Definition* incoming = NULL;
3113 for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
3114 BlockEntryInstr* pred = block->PredecessorAt(i);
3115 ZoneGrowableArray<Definition*>* pred_out_values =
3116 out_values_[pred->preorder_number()];
3117 if (incoming == NULL) {
3118 incoming = (*pred_out_values)[expr_id];
3119 } else if (incoming != (*pred_out_values)[expr_id]) {
3120 incoming = NULL;
3121 break;
3122 }
3123 }
3124
3125 if (incoming != NULL) {
3126 return incoming;
3127 }
3128
3129 // Incoming values are different. Phi is required to merge.
3130 PhiInstr* phi = new PhiInstr(
3131 block->AsJoinEntry(), block->PredecessorCount());
3132
3133 for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
3134 BlockEntryInstr* pred = block->PredecessorAt(i);
3135 ZoneGrowableArray<Definition*>* pred_out_values =
3136 out_values_[pred->preorder_number()];
3137
3138 // Sets of outgoing values are not linked into use lists so
3139 // they might contain values that were replace and removed
Florian Schneider 2012/12/13 13:17:13 s/replace/replaced/
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
3140 // from the graph by this iteration.
3141 // To prevent using them we additionally mark definitions themselves
3142 // as replaced and store a pointer to the replacement.
Florian Schneider 2012/12/13 13:17:13 Maybe add an assert that: (*pred_out_values)[expr
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Done.
3143 Value* input = new Value((*pred_out_values)[expr_id]->Replacement());
3144 phi->SetInputAt(i, input);
3145
3146 input->set_instruction(phi);
Florian Schneider 2012/12/13 13:17:13 Should we have a helper RegisterUse that does thes
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 I will leave it for a separate CL.
3147 input->set_use_index(i);
3148 input->AddToInputUseList();
3149 }
3150
3151 phi->set_ssa_temp_index(graph_->alloc_ssa_temp_index());
3152 phis_.Add(phi); // Postpone phi insertion until after load forwarding.
3153
3154 return phi;
3155 }
3156
3157 Definition* IncomingValue(BlockEntryInstr* block, intptr_t expr_id) {
3158 // We might have already computed the value during OUT set computation.
3159 // Reuse it to prevent creation of identical phis.
3160 if (!kill_[block->preorder_number()]->Contains(expr_id) &&
3161 !gen_[block->preorder_number()]->Contains(expr_id)) {
Florian Schneider 2012/12/13 13:17:13 I think this can be simplified: upward exposed loa
Vyacheslav Egorov (Google) 2012/12/13 14:02:59 Good observation. Killed the helper.
3162 ASSERT(out_[block->preorder_number()]->Contains(expr_id));
3163 ASSERT(out_values_[block->preorder_number()] != NULL);
3164 ASSERT((*out_values_[block->preorder_number()])[expr_id] != NULL);
3165 return (*out_values_[block->preorder_number()])[expr_id];
3166 }
3167
3168 return MergeIncomingValues(block, expr_id);
3169 }
3170
3171 // Iterate over basic blocks and replace exposed loads with incoming
3172 // values.
3173 void ForwardLoads() {
3174 for (BlockIterator block_it = graph_->reverse_postorder_iterator();
3175 !block_it.Done();
3176 block_it.Advance()) {
3177 BlockEntryInstr* block = block_it.Current();
3178
3179 ZoneGrowableArray<Definition*>* loads =
3180 exposed_values_[block->preorder_number()];
3181 if (loads == NULL) continue; // No exposed loads.
3182
3183 BitVector* in = in_[block->preorder_number()];
3184
3185 for (intptr_t i = 0; i < loads->length(); i++) {
3186 Definition* load = (*loads)[i];
3187 if (!in->Contains(load->expr_id())) continue; // No incoming value.
3188
3189 Definition* replacement = IncomingValue(block, load->expr_id());
3190
3191 // Sets of outgoing values are not linked into use lists so
3192 // they might contain values that were replace and removed
3193 // from the graph by this iteration.
3194 // To prevent using them we additionally mark definitions themselves
3195 // as replaced and store a pointer to the replacement.
3196 replacement = replacement->Replacement();
3197
3198 if (load != replacement) {
3199 if (FLAG_trace_optimization) {
3200 OS::Print("Replacing load v%"Pd" with v%"Pd"\n",
3201 load->ssa_temp_index(),
3202 replacement->ssa_temp_index());
3203 }
3204
3205 load->ReplaceUsesWith(replacement);
3206 load->RemoveFromGraph();
3207 load->SetReplacement(replacement);
3208 }
3209 }
3210 }
3211 }
3212
3213 // Check if the given phi take the same value on all code paths.
3214 // Eliminate it as redundant if this is the case.
3215 // When analyzing phi operands assumes that only generated during
3216 // this load phase can be redundant. They can be distinguished because
3217 // they are not marked alive.
3218 // TODO(vegorov): move this into a separate phase over all phis.
3219 bool EliminateRedundantPhi(PhiInstr* phi) {
3220 Definition* value = NULL; // Possible value of this phi.
3221
3222 worklist_.Clear();
3223 if (in_worklist_ == NULL) {
3224 in_worklist_ = new BitVector(graph_->current_ssa_temp_index());
3050 } else { 3225 } else {
3051 changed = OptimizeLoads(child, definitions, avail_in, kill_by_offs) || 3226 in_worklist_->Clear();
3052 changed; 3227 }
3053 } 3228
3054 } 3229 worklist_.Add(phi);
3055 return changed; 3230 in_worklist_->Add(phi->ssa_temp_index());
3056 } 3231
3232 for (intptr_t i = 0; i < worklist_.length(); i++) {
3233 PhiInstr* phi = worklist_[i];
3234
3235 for (intptr_t i = 0; i < phi->InputCount(); i++) {
3236 Definition* input = phi->InputAt(i)->definition();
3237 if (input == phi) continue;
3238
3239 PhiInstr* phi_input = input->AsPhi();
3240 if ((phi_input != NULL) && !phi_input->is_alive()) {
3241 if (!in_worklist_->Contains(phi_input->ssa_temp_index())) {
3242 worklist_.Add(phi_input);
3243 in_worklist_->Add(phi_input->ssa_temp_index());
3244 }
3245 continue;
3246 }
3247
3248 if (value == NULL) {
3249 value = input;
3250 } else if (value != input) {
3251 return false; // This phi is not redundant.
3252 }
3253 }
3254 }
3255
3256 // All phis in the worklist are redundant and have the same computed
3257 // value on all code paths.
3258 ASSERT(value != NULL);
3259 for (intptr_t i = 0; i < worklist_.length(); i++) {
3260 worklist_[i]->ReplaceUsesWith(value);
3261 }
3262
3263 return true;
3264 }
3265
3266 // Emit non-redundant phis created during ComputeOutValues and ForwardLoads.
3267 void EmitPhis() {
3268 for (intptr_t i = 0; i < phis_.length(); i++) {
3269 PhiInstr* phi = phis_[i];
3270 if ((phi->input_use_list() != NULL) && !EliminateRedundantPhi(phi)) {
3271 phi->mark_alive();
3272 phi->block()->InsertPhi(phi);
3273 }
3274 }
3275 }
3276
3277 ZoneGrowableArray<Definition*>* CreateBlockOutValues() {
3278 ZoneGrowableArray<Definition*>* out =
3279 new ZoneGrowableArray<Definition*>(max_expr_id_);
3280 for (intptr_t i = 0; i < max_expr_id_; i++) {
3281 out->Add(NULL);
3282 }
3283 return out;
3284 }
3285
3286 FlowGraph* graph_;
3287 const intptr_t max_expr_id_;
3288
3289 // Mapping between field offsets in words and expression ids of loads from
3290 // that offset.
3291 const GrowableArray<BitVector*>& kill_by_offset_;
3292
3293 // Per block sets of expression ids for loads that are: incoming (available
3294 // on the entry), outgoing (available on the exit), generated and killed.
3295 GrowableArray<BitVector*> in_;
3296 GrowableArray<BitVector*> out_;
3297 GrowableArray<BitVector*> gen_;
3298 GrowableArray<BitVector*> kill_;
3299
3300 // Per block list of upwards exposed loads.
3301 GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_;
3302
3303 // Per block mappings between expression ids and outgoing definitions that
3304 // represent those ids.
3305 GrowableArray<ZoneGrowableArray<Definition*>*> out_values_;
3306
3307 // List of phis generated during ComputeOutValues and ForwardLoads.
3308 // Some of these phis might be redundant and thus a separate pass is
3309 // needed to emit only non-redundant ones.
3310 GrowableArray<PhiInstr*> phis_;
3311
3312 // Auxiliary worklist used by redundant phi elimination.
3313 GrowableArray<PhiInstr*> worklist_;
3314 BitVector* in_worklist_;
3315
3316 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer);
3317 };
3057 3318
3058 3319
3059 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { 3320 bool DominatorBasedCSE::Optimize(FlowGraph* graph) {
3060 bool changed = false; 3321 bool changed = false;
3061 if (FLAG_load_cse) { 3322 if (FLAG_load_cse) {
3062 GrowableArray<BitVector*> kill_by_offs(10); 3323 GrowableArray<BitVector*> kill_by_offs(10);
3063 intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs); 3324 const intptr_t max_expr_id = NumberLoadExpressions(graph, &kill_by_offs);
3064 if (max_expr_id > 0) { 3325 if (max_expr_id > 0) {
3065 intptr_t num_blocks = graph->preorder().length(); 3326 LoadOptimizer load_optimizer(graph, max_expr_id, kill_by_offs);
3066 GrowableArray<BitVector*> avail_in(num_blocks); 3327 load_optimizer.Optimize();
3067 for (intptr_t i = 0; i < num_blocks; i++) { 3328 }
3068 avail_in.Add(new BitVector(max_expr_id)); 3329 }
3069 } 3330
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; 3331 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map;
3083 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; 3332 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed;
3084 3333
3085 return changed; 3334 return changed;
3086 } 3335 }
3087 3336
3088 3337
3089 bool DominatorBasedCSE::OptimizeRecursive( 3338 bool DominatorBasedCSE::OptimizeRecursive(
3090 BlockEntryInstr* block, 3339 BlockEntryInstr* block,
3091 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { 3340 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) {
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after
3922 4171
3923 if (FLAG_trace_constant_propagation) { 4172 if (FLAG_trace_constant_propagation) {
3924 OS::Print("\n==== After constant propagation ====\n"); 4173 OS::Print("\n==== After constant propagation ====\n");
3925 FlowGraphPrinter printer(*graph_); 4174 FlowGraphPrinter printer(*graph_);
3926 printer.PrintBlocks(); 4175 printer.PrintBlocks();
3927 } 4176 }
3928 } 4177 }
3929 4178
3930 4179
3931 } // namespace dart 4180 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698