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

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: address comments 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
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698