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

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

Issue 14326006: Optimize static field and context load/stores as part of CSE pass. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months 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 | « no previous file | runtime/vm/hash_map.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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 3045 matching lines...) Expand 10 before | Expand all | Expand 10 after
3056 } 3056 }
3057 } 3057 }
3058 } 3058 }
3059 3059
3060 3060
3061 static bool IsLoadEliminationCandidate(Definition* def) { 3061 static bool IsLoadEliminationCandidate(Definition* def) {
3062 // Immutable loads (not affected by side effects) are handled 3062 // Immutable loads (not affected by side effects) are handled
3063 // in the DominatorBasedCSE pass. 3063 // in the DominatorBasedCSE pass.
3064 // TODO(fschneider): Extend to other load instructions. 3064 // TODO(fschneider): Extend to other load instructions.
3065 return (def->IsLoadField() && def->AffectedBySideEffect()) 3065 return (def->IsLoadField() && def->AffectedBySideEffect())
3066 || def->IsLoadIndexed(); 3066 || def->IsLoadIndexed()
3067 || def->IsLoadStaticField()
3068 || def->IsCurrentContext();
3067 } 3069 }
3068 3070
3069 3071
3070 static intptr_t ComputeLoadOffsetInWords(Definition* defn) { 3072 // Alias represents a family of locations. It is used to capture aliasing
3071 if (defn->IsLoadIndexed()) { 3073 // between stores and loads. Store can alias another load or store if and only
3072 // We are assuming that LoadField is never used to load the first word. 3074 // if they have the same alias.
3073 return 0; 3075 class Alias : public ValueObject {
3074 } 3076 public:
3075 3077 Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { }
3076 LoadFieldInstr* load_field = defn->AsLoadField(); 3078
3077 if (load_field != NULL) { 3079 // All indexed load/stores alias each other.
3078 const intptr_t idx = load_field->offset_in_bytes() / kWordSize; 3080 // TODO(vegorov): incorporate type of array into alias to disambiguate
3079 ASSERT(idx > 0); 3081 // different typed data and normal arrays.
3080 return idx; 3082 static Alias Indexes() {
3081 } 3083 return Alias(kIndexesAlias);
3082 3084 }
3083 UNREACHABLE(); 3085
3084 return 0; 3086 // Field load/stores alias each other when field offset matches.
3085 } 3087 // TODO(vegorov): use field information to disambiguate load/stores into
3086 3088 // different fields that by accident share offset.
3087 3089 static Alias Field(intptr_t offset_in_bytes) {
3088 static bool IsInterferingStore(Instruction* instr, 3090 const intptr_t idx = offset_in_bytes / kWordSize;
3089 intptr_t* offset_in_words) { 3091 ASSERT(idx >= kFirstFieldAlias);
3090 if (instr->IsStoreIndexed()) { 3092 return Alias(idx * 2);
3091 // We are assuming that LoadField is never used to load the first word. 3093 }
3092 *offset_in_words = 0; 3094
3093 return true; 3095 // Static field load/stores alias each other.
3094 } 3096 // AliasedSet assigns ids to static fields during optimization phase.
3095 3097 static Alias StaticField(intptr_t id) {
3096 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField(); 3098 ASSERT(id >= kFirstFieldAlias);
3097 if (store_instance_field != NULL) { 3099 return Alias(id * 2 + 1);
3098 ASSERT(store_instance_field->field().Offset() != 0); 3100 }
3099 *offset_in_words = store_instance_field->field().Offset() / kWordSize; 3101
3100 return true; 3102 // Current context load/stores alias each other.
3101 } 3103 static Alias CurrentContext() {
3102 3104 return Alias(kCurrentContextAlias);
3103 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField(); 3105 }
3104 if (store_vm_field != NULL) { 3106
3105 ASSERT(store_vm_field->offset_in_bytes() != 0); 3107 // Operation does not alias anything.
3106 *offset_in_words = store_vm_field->offset_in_bytes() / kWordSize; 3108 static Alias None() {
3107 return true; 3109 return Alias(kNoneAlias);
3108 } 3110 }
3109 3111
3110 return false; 3112 bool IsNone() const {
3111 } 3113 return alias_ == kNoneAlias;
3114 }
3115
3116 // Convert this alias to a positive array index.
3117 intptr_t ToIndex() const {
3118 ASSERT(!IsNone());
3119 return alias_ - kAliasBase;
3120 }
3121
3122 private:
3123 explicit Alias(intptr_t alias) : alias_(alias) { }
3124
3125 enum {
3126 kNoneAlias = -2,
3127 kCurrentContextAlias = -1,
3128 kIndexesAlias = 0,
3129 kFirstFieldAlias = kIndexesAlias + 1,
3130 kAliasBase = kCurrentContextAlias
3131 };
3132
3133 const intptr_t alias_;
3134 };
3135
3136
3137 // Set mapping alias to a list of loads sharing this alias.
3138 class AliasedSet : public ZoneAllocated {
3139 public:
3140 explicit AliasedSet(intptr_t max_expr_id)
3141 : max_expr_id_(max_expr_id),
3142 sets_(),
3143 field_ids_(),
3144 max_field_id_(0) { }
3145
3146 Alias ComputeAliasForLoad(Definition* defn) {
3147 if (defn->IsLoadIndexed()) {
3148 // We are assuming that LoadField is never used to load the first word.
3149 return Alias::Indexes();
3150 }
3151
3152 LoadFieldInstr* load_field = defn->AsLoadField();
3153 if (load_field != NULL) {
3154 return Alias::Field(load_field->offset_in_bytes());
3155 }
3156
3157 if (defn->IsCurrentContext()) {
3158 return Alias::CurrentContext();
3159 }
3160
3161 LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
3162 if (load_static_field != NULL) {
3163 return Alias::StaticField(GetFieldId(load_static_field->field()));
3164 }
3165
3166 UNREACHABLE();
3167 return Alias::None();
3168 }
3169
3170 Alias ComputeAliasForStore(Instruction* instr) {
3171 if (instr->IsStoreIndexed()) {
3172 return Alias::Indexes();
3173 }
3174
3175 StoreInstanceFieldInstr* store_instance_field =
3176 instr->AsStoreInstanceField();
3177 if (store_instance_field != NULL) {
3178 return Alias::Field(store_instance_field->field().Offset());
3179 }
3180
3181 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
3182 if (store_vm_field != NULL) {
3183 return Alias::Field(store_vm_field->offset_in_bytes());
3184 }
3185
3186 if (instr->IsStoreContext() || instr->IsChainContext()) {
3187 return Alias::CurrentContext();
3188 }
3189
3190 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
3191 if (store_static_field != NULL) {
3192 return Alias::StaticField(GetFieldId(store_static_field->field()));
3193 }
3194
3195 return Alias::None();
3196 }
3197
3198 bool Contains(const Alias alias) {
3199 const intptr_t idx = alias.ToIndex();
3200 return (idx < sets_.length()) && (sets_[idx] != NULL);
3201 }
3202
3203 BitVector* Get(const Alias alias) {
3204 ASSERT(Contains(alias));
3205 return sets_[alias.ToIndex()];
3206 }
3207
3208 void Add(const Alias alias, intptr_t ssa_index) {
3209 const intptr_t idx = alias.ToIndex();
3210
3211 while (sets_.length() <= idx) {
3212 sets_.Add(NULL);
3213 }
3214
3215 if (sets_[idx] == NULL) {
3216 sets_[idx] = new BitVector(max_expr_id_);
3217 }
3218
3219 sets_[idx]->Add(ssa_index);
3220 }
3221
3222 intptr_t max_expr_id() const { return max_expr_id_; }
3223 bool IsEmpty() const { return max_expr_id_ == 0; }
3224
3225 private:
3226 const intptr_t max_expr_id_;
3227
3228 // Maps alias index to a set of ssa indexes corresponding to loads with the
3229 // given alias.
3230 GrowableArray<BitVector*> sets_;
3231
3232 // Get id assigned to the given field. Assign a new id if the field is seen
3233 // for the first time.
3234 intptr_t GetFieldId(const Field& field) {
3235 intptr_t id = field_ids_.Lookup(&field);
3236 if (id == 0) {
3237 id = ++max_field_id_;
3238 field_ids_.Insert(FieldIdPair(&field, id));
3239 }
3240 return id;
3241 }
3242
3243 class FieldIdPair {
3244 public:
3245 typedef const Field* Key;
3246 typedef intptr_t Value;
3247 typedef FieldIdPair Pair;
3248
3249 FieldIdPair(Key key, Value value) : key_(key), value_(value) { }
3250
3251 static Key KeyOf(Pair kv) {
3252 return kv.key_;
3253 }
3254
3255 static Value ValueOf(Pair kv) {
3256 return kv.value_;
3257 }
3258
3259 static intptr_t Hashcode(Key key) {
3260 return String::Handle(key->name()).Hash();
3261 }
3262
3263 static inline bool IsKeyEqual(Pair kv, Key key) {
3264 return KeyOf(kv)->raw() == key->raw();
3265 }
3266
3267 private:
3268 Key key_;
3269 Value value_;
3270 };
3271
3272 // Table mapping static field to their id used during optimization pass.
3273 DirectChainedHashMap<FieldIdPair> field_ids_;
3274 intptr_t max_field_id_;
3275 };
3112 3276
3113 3277
3114 static Definition* GetStoredValue(Instruction* instr) { 3278 static Definition* GetStoredValue(Instruction* instr) {
3115 if (instr->IsStoreIndexed()) { 3279 if (instr->IsStoreIndexed()) {
3116 return instr->AsStoreIndexed()->value()->definition(); 3280 return instr->AsStoreIndexed()->value()->definition();
3117 } 3281 }
3118 3282
3119 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField(); 3283 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField();
3120 if (store_instance_field != NULL) { 3284 if (store_instance_field != NULL) {
3121 return store_instance_field->value()->definition(); 3285 return store_instance_field->value()->definition();
3122 } 3286 }
3123 3287
3124 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField(); 3288 StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
3125 if (store_vm_field != NULL) { 3289 if (store_vm_field != NULL) {
3126 return store_vm_field->value()->definition(); 3290 return store_vm_field->value()->definition();
3127 } 3291 }
3128 3292
3293 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
3294 if (store_static_field != NULL) {
3295 return store_static_field->value()->definition();
3296 }
3297
3298 if (instr->IsStoreContext() || instr->IsChainContext()) {
3299 return instr->InputAt(0)->definition();
3300 }
3301
3129 UNREACHABLE(); // Should only be called for supported store instructions. 3302 UNREACHABLE(); // Should only be called for supported store instructions.
3130 return NULL; 3303 return NULL;
3131 } 3304 }
3132 3305
3133 3306
3134 // KeyValueTrait used for numbering of loads. Allows to lookup loads 3307 // KeyValueTrait used for numbering of loads. Allows to lookup loads
3135 // corresponding to stores. 3308 // corresponding to stores.
3136 class LoadKeyValueTrait { 3309 class LoadKeyValueTrait {
3137 public: 3310 public:
3138 typedef Definition* Value; 3311 typedef Definition* Value;
3139 typedef Definition* Key; 3312 typedef Instruction* Key;
3140 typedef Definition* Pair; 3313 typedef Definition* Pair;
3141 3314
3142 static Key KeyOf(Pair kv) { 3315 static Key KeyOf(Pair kv) {
3143 return kv; 3316 return kv;
3144 } 3317 }
3145 3318
3146 static Value ValueOf(Pair kv) { 3319 static Value ValueOf(Pair kv) {
3147 return kv; 3320 return kv;
3148 } 3321 }
3149 3322
(...skipping 14 matching lines...) Expand all
3164 object = load_field->value()->definition()->ssa_temp_index(); 3337 object = load_field->value()->definition()->ssa_temp_index();
3165 location = load_field->offset_in_bytes(); 3338 location = load_field->offset_in_bytes();
3166 } else if (key->IsStoreInstanceField()) { 3339 } else if (key->IsStoreInstanceField()) {
3167 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); 3340 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
3168 object = store_field->instance()->definition()->ssa_temp_index(); 3341 object = store_field->instance()->definition()->ssa_temp_index();
3169 location = store_field->field().Offset(); 3342 location = store_field->field().Offset();
3170 } else if (key->IsStoreVMField()) { 3343 } else if (key->IsStoreVMField()) {
3171 StoreVMFieldInstr* store_field = key->AsStoreVMField(); 3344 StoreVMFieldInstr* store_field = key->AsStoreVMField();
3172 object = store_field->dest()->definition()->ssa_temp_index(); 3345 object = store_field->dest()->definition()->ssa_temp_index();
3173 location = store_field->offset_in_bytes(); 3346 location = store_field->offset_in_bytes();
3347 } else if (key->IsLoadStaticField()) {
3348 LoadStaticFieldInstr* load_static_field = key->AsLoadStaticField();
3349 object = String::Handle(load_static_field->field().name()).Hash();
3350 } else if (key->IsStoreStaticField()) {
3351 StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
3352 object = String::Handle(store_static_field->field().name()).Hash();
3353 } else {
3354 ASSERT(key->IsStoreContext() ||
3355 key->IsCurrentContext() ||
3356 key->IsChainContext());
3174 } 3357 }
3175 3358
3176 return object * 31 + location; 3359 return object * 31 + location;
3177 } 3360 }
3178 3361
3179 static inline bool IsKeyEqual(Pair kv, Key key) { 3362 static inline bool IsKeyEqual(Pair kv, Key key) {
3180 if (kv->Equals(key)) return true; 3363 if (kv->Equals(key)) return true;
3181 3364
3182 if (kv->IsLoadIndexed()) { 3365 if (kv->IsLoadIndexed()) {
3183 if (key->IsStoreIndexed()) { 3366 if (key->IsStoreIndexed()) {
3184 LoadIndexedInstr* load_indexed = kv->AsLoadIndexed(); 3367 LoadIndexedInstr* load_indexed = kv->AsLoadIndexed();
3185 StoreIndexedInstr* store_indexed = key->AsStoreIndexed(); 3368 StoreIndexedInstr* store_indexed = key->AsStoreIndexed();
3186 return load_indexed->array()->Equals(store_indexed->array()) && 3369 return load_indexed->array()->Equals(store_indexed->array()) &&
3187 load_indexed->index()->Equals(store_indexed->index()); 3370 load_indexed->index()->Equals(store_indexed->index());
3188 } 3371 }
3189 return false; 3372 return false;
3190 } 3373 }
3191 3374
3375 if (kv->IsLoadStaticField()) {
3376 if (key->IsStoreStaticField()) {
3377 LoadStaticFieldInstr* load_static_field = kv->AsLoadStaticField();
3378 StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
3379 return load_static_field->field().raw() ==
3380 store_static_field->field().raw();
3381 }
3382 return false;
3383 }
3384
3385 if (kv->IsCurrentContext()) {
3386 return key->IsStoreContext() || key->IsChainContext();
3387 }
3388
3192 ASSERT(kv->IsLoadField()); 3389 ASSERT(kv->IsLoadField());
3193 LoadFieldInstr* load_field = kv->AsLoadField(); 3390 LoadFieldInstr* load_field = kv->AsLoadField();
3194 if (key->IsStoreVMField()) { 3391 if (key->IsStoreVMField()) {
3195 StoreVMFieldInstr* store_field = key->AsStoreVMField(); 3392 StoreVMFieldInstr* store_field = key->AsStoreVMField();
3196 return load_field->value()->Equals(store_field->dest()) && 3393 return load_field->value()->Equals(store_field->dest()) &&
3197 (load_field->offset_in_bytes() == store_field->offset_in_bytes()); 3394 (load_field->offset_in_bytes() == store_field->offset_in_bytes());
3198 } else if (key->IsStoreInstanceField()) { 3395 } else if (key->IsStoreInstanceField()) {
3199 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField(); 3396 StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
3200 return load_field->value()->Equals(store_field->instance()) && 3397 return load_field->value()->Equals(store_field->instance()) &&
3201 (load_field->offset_in_bytes() == store_field->field().Offset()); 3398 (load_field->offset_in_bytes() == store_field->field().Offset());
3202 } 3399 }
3203 3400
3204 return false; 3401 return false;
3205 } 3402 }
3206 }; 3403 };
3207 3404
3208 3405
3209 static intptr_t NumberLoadExpressions( 3406 static AliasedSet* NumberLoadExpressions(
3210 FlowGraph* graph, 3407 FlowGraph* graph,
3211 DirectChainedHashMap<LoadKeyValueTrait>* map, 3408 DirectChainedHashMap<LoadKeyValueTrait>* map) {
3212 GrowableArray<BitVector*>* kill_by_offs) {
3213 intptr_t expr_id = 0; 3409 intptr_t expr_id = 0;
3214 3410
3215 // Loads representing different expression ids will be collected and 3411 // Loads representing different expression ids will be collected and
3216 // used to build per offset kill sets. 3412 // used to build per offset kill sets.
3217 GrowableArray<Definition*> loads(10); 3413 GrowableArray<Definition*> loads(10);
3218 3414
3219 for (BlockIterator it = graph->reverse_postorder_iterator(); 3415 for (BlockIterator it = graph->reverse_postorder_iterator();
3220 !it.Done(); 3416 !it.Done();
3221 it.Advance()) { 3417 it.Advance()) {
3222 BlockEntryInstr* block = it.Current(); 3418 BlockEntryInstr* block = it.Current();
3223 for (ForwardInstructionIterator instr_it(block); 3419 for (ForwardInstructionIterator instr_it(block);
3224 !instr_it.Done(); 3420 !instr_it.Done();
3225 instr_it.Advance()) { 3421 instr_it.Advance()) {
3226 Definition* defn = instr_it.Current()->AsDefinition(); 3422 Definition* defn = instr_it.Current()->AsDefinition();
3227 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { 3423 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) {
3228 continue; 3424 continue;
3229 } 3425 }
3230 Definition* result = map->Lookup(defn); 3426 Definition* result = map->Lookup(defn);
3231 if (result == NULL) { 3427 if (result == NULL) {
3232 map->Insert(defn); 3428 map->Insert(defn);
3233 defn->set_expr_id(expr_id++); 3429 defn->set_expr_id(expr_id++);
3234 loads.Add(defn); 3430 loads.Add(defn);
3235 } else { 3431 } else {
3236 defn->set_expr_id(result->expr_id()); 3432 defn->set_expr_id(result->expr_id());
3237 } 3433 }
3238 } 3434 }
3239 } 3435 }
3240 3436
3241 // Build per offset kill sets. Any store interferes only with loads from 3437 // Build aliasing sets mapping aliases to loads.
3242 // the same offset. 3438 AliasedSet* aliased_set = new AliasedSet(expr_id);
3243 for (intptr_t i = 0; i < loads.length(); i++) { 3439 for (intptr_t i = 0; i < loads.length(); i++) {
3244 Definition* defn = loads[i]; 3440 Definition* defn = loads[i];
3245 3441 aliased_set->Add(aliased_set->ComputeAliasForLoad(defn), defn->expr_id());
3246 const intptr_t offset_in_words = ComputeLoadOffsetInWords(defn);
3247 while (kill_by_offs->length() <= offset_in_words) {
3248 kill_by_offs->Add(NULL);
3249 }
3250 if ((*kill_by_offs)[offset_in_words] == NULL) {
3251 (*kill_by_offs)[offset_in_words] = new BitVector(expr_id);
3252 }
3253 (*kill_by_offs)[offset_in_words]->Add(defn->expr_id());
3254 } 3442 }
3255 3443 return aliased_set;
3256 return expr_id;
3257 } 3444 }
3258 3445
3259 3446
3260 class LoadOptimizer : public ValueObject { 3447 class LoadOptimizer : public ValueObject {
3261 public: 3448 public:
3262 LoadOptimizer(FlowGraph* graph, 3449 LoadOptimizer(FlowGraph* graph,
3263 intptr_t max_expr_id, 3450 AliasedSet* aliased_set,
3264 DirectChainedHashMap<LoadKeyValueTrait>* map, 3451 DirectChainedHashMap<LoadKeyValueTrait>* map)
3265 const GrowableArray<BitVector*>& kill_by_offset)
3266 : graph_(graph), 3452 : graph_(graph),
3267 map_(map), 3453 map_(map),
3268 max_expr_id_(max_expr_id), 3454 aliased_set_(aliased_set),
3269 kill_by_offset_(kill_by_offset),
3270 in_(graph_->preorder().length()), 3455 in_(graph_->preorder().length()),
3271 out_(graph_->preorder().length()), 3456 out_(graph_->preorder().length()),
3272 gen_(graph_->preorder().length()), 3457 gen_(graph_->preorder().length()),
3273 kill_(graph_->preorder().length()), 3458 kill_(graph_->preorder().length()),
3274 exposed_values_(graph_->preorder().length()), 3459 exposed_values_(graph_->preorder().length()),
3275 out_values_(graph_->preorder().length()), 3460 out_values_(graph_->preorder().length()),
3276 phis_(5), 3461 phis_(5),
3277 worklist_(5), 3462 worklist_(5),
3278 in_worklist_(NULL) { 3463 in_worklist_(NULL),
3464 forwarded_(false) {
3279 const intptr_t num_blocks = graph_->preorder().length(); 3465 const intptr_t num_blocks = graph_->preorder().length();
3280 for (intptr_t i = 0; i < num_blocks; i++) { 3466 for (intptr_t i = 0; i < num_blocks; i++) {
3281 out_.Add(new BitVector(max_expr_id_)); 3467 out_.Add(new BitVector(aliased_set_->max_expr_id()));
3282 gen_.Add(new BitVector(max_expr_id_)); 3468 gen_.Add(new BitVector(aliased_set_->max_expr_id()));
3283 kill_.Add(new BitVector(max_expr_id_)); 3469 kill_.Add(new BitVector(aliased_set_->max_expr_id()));
3284 in_.Add(new BitVector(max_expr_id_)); 3470 in_.Add(new BitVector(aliased_set_->max_expr_id()));
3285 3471
3286 exposed_values_.Add(NULL); 3472 exposed_values_.Add(NULL);
3287 out_values_.Add(NULL); 3473 out_values_.Add(NULL);
3288 } 3474 }
3289 } 3475 }
3290 3476
3291 void Optimize() { 3477 bool Optimize() {
3292 ComputeInitialSets(); 3478 ComputeInitialSets();
3293 ComputeOutValues(); 3479 ComputeOutValues();
3294 ForwardLoads(); 3480 ForwardLoads();
3295 EmitPhis(); 3481 EmitPhis();
3482 return forwarded_;
3296 } 3483 }
3297 3484
3298 private: 3485 private:
3299 // Compute sets of loads generated and killed by each block. 3486 // Compute sets of loads generated and killed by each block.
3300 // Additionally compute upwards exposed and generated loads for each block. 3487 // Additionally compute upwards exposed and generated loads for each block.
3301 // Exposed loads are those that can be replaced if a corresponding 3488 // Exposed loads are those that can be replaced if a corresponding
3302 // reaching load will be found. 3489 // reaching load will be found.
3303 // Loads that are locally redundant will be replaced as we go through 3490 // Loads that are locally redundant will be replaced as we go through
3304 // instructions. 3491 // instructions.
3305 void ComputeInitialSets() { 3492 void ComputeInitialSets() {
3306 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); 3493 for (BlockIterator block_it = graph_->reverse_postorder_iterator();
3307 !block_it.Done(); 3494 !block_it.Done();
3308 block_it.Advance()) { 3495 block_it.Advance()) {
3309 BlockEntryInstr* block = block_it.Current(); 3496 BlockEntryInstr* block = block_it.Current();
3310 const intptr_t preorder_number = block->preorder_number(); 3497 const intptr_t preorder_number = block->preorder_number();
3311 3498
3312 BitVector* kill = kill_[preorder_number]; 3499 BitVector* kill = kill_[preorder_number];
3313 BitVector* gen = gen_[preorder_number]; 3500 BitVector* gen = gen_[preorder_number];
3314 3501
3315 ZoneGrowableArray<Definition*>* exposed_values = NULL; 3502 ZoneGrowableArray<Definition*>* exposed_values = NULL;
3316 ZoneGrowableArray<Definition*>* out_values = NULL; 3503 ZoneGrowableArray<Definition*>* out_values = NULL;
3317 3504
3318 for (ForwardInstructionIterator instr_it(block); 3505 for (ForwardInstructionIterator instr_it(block);
3319 !instr_it.Done(); 3506 !instr_it.Done();
3320 instr_it.Advance()) { 3507 instr_it.Advance()) {
3321 Instruction* instr = instr_it.Current(); 3508 Instruction* instr = instr_it.Current();
3322 3509
3323 intptr_t offset_in_words = 0; 3510 const Alias alias = aliased_set_->ComputeAliasForStore(instr);
3324 if (IsInterferingStore(instr, &offset_in_words)) { 3511 if (!alias.IsNone()) {
3325 // Interfering stores kill only loads from the same offset. 3512 // Interfering stores kill only loads from the same offset.
3326 if ((offset_in_words < kill_by_offset_.length()) && 3513 if (aliased_set_->Contains(alias)) {
3327 (kill_by_offset_[offset_in_words] != NULL)) { 3514 BitVector* killed = aliased_set_->Get(alias);
3328 kill->AddAll(kill_by_offset_[offset_in_words]); 3515 kill->AddAll(killed);
3329 // There is no need to clear out_values when clearing GEN set 3516 // There is no need to clear out_values when clearing GEN set
3330 // because only those values that are in the GEN set 3517 // because only those values that are in the GEN set
3331 // will ever be used. 3518 // will ever be used.
3332 gen->RemoveAll(kill_by_offset_[offset_in_words]); 3519 gen->RemoveAll(killed);
3333 3520
3334 // Only forward stores to normal arrays and float64 arrays 3521 // Only forward stores to normal arrays and float64 arrays
3335 // to loads because other array stores (intXX/uintXX/float32) 3522 // to loads because other array stores (intXX/uintXX/float32)
3336 // may implicitly convert the value stored. 3523 // may implicitly convert the value stored.
3337 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); 3524 StoreIndexedInstr* array_store = instr->AsStoreIndexed();
3338 if (array_store == NULL || 3525 if (array_store == NULL ||
3339 array_store->class_id() == kArrayCid || 3526 array_store->class_id() == kArrayCid ||
3340 array_store->class_id() == kTypedDataFloat64ArrayCid) { 3527 array_store->class_id() == kTypedDataFloat64ArrayCid) {
3341 Definition* load = map_->Lookup(instr->AsDefinition()); 3528 Definition* load = map_->Lookup(instr);
3342 if (load != NULL) { 3529 if (load != NULL) {
3343 // Store has a corresponding numbered load. Try forwarding 3530 // Store has a corresponding numbered load. Try forwarding
3344 // stored value to it. 3531 // stored value to it.
3345 gen->Add(load->expr_id()); 3532 gen->Add(load->expr_id());
3346 if (out_values == NULL) out_values = CreateBlockOutValues(); 3533 if (out_values == NULL) out_values = CreateBlockOutValues();
3347 (*out_values)[load->expr_id()] = GetStoredValue(instr); 3534 (*out_values)[load->expr_id()] = GetStoredValue(instr);
3348 } 3535 }
3349 } 3536 }
3350 } 3537 }
3351 ASSERT(instr->IsDefinition() && 3538 ASSERT(!instr->IsDefinition() ||
3352 !IsLoadEliminationCandidate(instr->AsDefinition())); 3539 !IsLoadEliminationCandidate(instr->AsDefinition()));
3353 continue; 3540 continue;
3354 } 3541 }
3355 3542
3356 // Other instructions with side effects kill all loads. 3543 // Other instructions with side effects kill all loads.
3357 if (instr->HasSideEffect()) { 3544 if (instr->HasSideEffect()) {
3358 kill->SetAll(); 3545 kill->SetAll();
3359 // There is no need to clear out_values when clearing GEN set 3546 // There is no need to clear out_values when clearing GEN set
3360 // because only those values that are in the GEN set 3547 // because only those values that are in the GEN set
3361 // will ever be used. 3548 // will ever be used.
(...skipping 14 matching lines...) Expand all
3376 Definition* replacement = (*out_values)[expr_id]; 3563 Definition* replacement = (*out_values)[expr_id];
3377 EnsureSSATempIndex(graph_, defn, replacement); 3564 EnsureSSATempIndex(graph_, defn, replacement);
3378 if (FLAG_trace_optimization) { 3565 if (FLAG_trace_optimization) {
3379 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", 3566 OS::Print("Replacing load v%"Pd" with v%"Pd"\n",
3380 defn->ssa_temp_index(), 3567 defn->ssa_temp_index(),
3381 replacement->ssa_temp_index()); 3568 replacement->ssa_temp_index());
3382 } 3569 }
3383 3570
3384 defn->ReplaceUsesWith(replacement); 3571 defn->ReplaceUsesWith(replacement);
3385 instr_it.RemoveCurrentFromGraph(); 3572 instr_it.RemoveCurrentFromGraph();
3573 forwarded_ = true;
3386 continue; 3574 continue;
3387 } else if (!kill->Contains(expr_id)) { 3575 } else if (!kill->Contains(expr_id)) {
3388 // This is an exposed load: it is the first representative of a 3576 // This is an exposed load: it is the first representative of a
3389 // given expression id and it is not killed on the path from 3577 // given expression id and it is not killed on the path from
3390 // the block entry. 3578 // the block entry.
3391 if (exposed_values == NULL) { 3579 if (exposed_values == NULL) {
3392 static const intptr_t kMaxExposedValuesInitialSize = 5; 3580 static const intptr_t kMaxExposedValuesInitialSize = 5;
3393 exposed_values = new ZoneGrowableArray<Definition*>( 3581 exposed_values = new ZoneGrowableArray<Definition*>(
3394 Utils::Minimum(kMaxExposedValuesInitialSize, max_expr_id_)); 3582 Utils::Minimum(kMaxExposedValuesInitialSize,
3583 aliased_set_->max_expr_id()));
3395 } 3584 }
3396 3585
3397 exposed_values->Add(defn); 3586 exposed_values->Add(defn);
3398 } 3587 }
3399 3588
3400 gen->Add(expr_id); 3589 gen->Add(expr_id);
3401 3590
3402 if (out_values == NULL) out_values = CreateBlockOutValues(); 3591 if (out_values == NULL) out_values = CreateBlockOutValues();
3403 (*out_values)[expr_id] = defn; 3592 (*out_values)[expr_id] = defn;
3404 } 3593 }
3405 3594
3406 out_[preorder_number]->CopyFrom(gen); 3595 out_[preorder_number]->CopyFrom(gen);
3407 exposed_values_[preorder_number] = exposed_values; 3596 exposed_values_[preorder_number] = exposed_values;
3408 out_values_[preorder_number] = out_values; 3597 out_values_[preorder_number] = out_values;
3409 } 3598 }
3410 } 3599 }
3411 3600
3412 // Compute OUT sets and corresponding out_values mappings by propagating them 3601 // Compute OUT sets and corresponding out_values mappings by propagating them
3413 // iteratively until fix point is reached. 3602 // iteratively until fix point is reached.
3414 // No replacement is done at this point and thus any out_value[expr_id] is 3603 // No replacement is done at this point and thus any out_value[expr_id] is
3415 // changed at most once: from NULL to an actual value. 3604 // changed at most once: from NULL to an actual value.
3416 // When merging incoming loads we might need to create a phi. 3605 // When merging incoming loads we might need to create a phi.
3417 // These phis are not inserted at the graph immediately because some of them 3606 // These phis are not inserted at the graph immediately because some of them
3418 // might become redundant after load forwarding is done. 3607 // might become redundant after load forwarding is done.
3419 void ComputeOutValues() { 3608 void ComputeOutValues() {
3420 BitVector* temp = new BitVector(max_expr_id_); 3609 BitVector* temp = new BitVector(aliased_set_->max_expr_id());
3421 3610
3422 bool changed = true; 3611 bool changed = true;
3423 while (changed) { 3612 while (changed) {
3424 changed = false; 3613 changed = false;
3425 3614
3426 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); 3615 for (BlockIterator block_it = graph_->reverse_postorder_iterator();
3427 !block_it.Done(); 3616 !block_it.Done();
3428 block_it.Advance()) { 3617 block_it.Advance()) {
3429 BlockEntryInstr* block = block_it.Current(); 3618 BlockEntryInstr* block = block_it.Current();
3430 3619
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
3584 3773
3585 if (FLAG_trace_optimization) { 3774 if (FLAG_trace_optimization) {
3586 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", 3775 OS::Print("Replacing load v%"Pd" with v%"Pd"\n",
3587 load->ssa_temp_index(), 3776 load->ssa_temp_index(),
3588 replacement->ssa_temp_index()); 3777 replacement->ssa_temp_index());
3589 } 3778 }
3590 3779
3591 load->ReplaceUsesWith(replacement); 3780 load->ReplaceUsesWith(replacement);
3592 load->RemoveFromGraph(); 3781 load->RemoveFromGraph();
3593 load->SetReplacement(replacement); 3782 load->SetReplacement(replacement);
3783 forwarded_ = true;
3594 } 3784 }
3595 } 3785 }
3596 } 3786 }
3597 } 3787 }
3598 3788
3599 // Check if the given phi take the same value on all code paths. 3789 // Check if the given phi take the same value on all code paths.
3600 // Eliminate it as redundant if this is the case. 3790 // Eliminate it as redundant if this is the case.
3601 // When analyzing phi operands assumes that only generated during 3791 // When analyzing phi operands assumes that only generated during
3602 // this load phase can be redundant. They can be distinguished because 3792 // this load phase can be redundant. They can be distinguished because
3603 // they are not marked alive. 3793 // they are not marked alive.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3661 } else { 3851 } else {
3662 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) { 3852 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) {
3663 phi->InputAt(j)->RemoveFromUseList(); 3853 phi->InputAt(j)->RemoveFromUseList();
3664 } 3854 }
3665 } 3855 }
3666 } 3856 }
3667 } 3857 }
3668 3858
3669 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { 3859 ZoneGrowableArray<Definition*>* CreateBlockOutValues() {
3670 ZoneGrowableArray<Definition*>* out = 3860 ZoneGrowableArray<Definition*>* out =
3671 new ZoneGrowableArray<Definition*>(max_expr_id_); 3861 new ZoneGrowableArray<Definition*>(aliased_set_->max_expr_id());
3672 for (intptr_t i = 0; i < max_expr_id_; i++) { 3862 for (intptr_t i = 0; i < aliased_set_->max_expr_id(); i++) {
3673 out->Add(NULL); 3863 out->Add(NULL);
3674 } 3864 }
3675 return out; 3865 return out;
3676 } 3866 }
3677 3867
3678 FlowGraph* graph_; 3868 FlowGraph* graph_;
3679 DirectChainedHashMap<LoadKeyValueTrait>* map_; 3869 DirectChainedHashMap<LoadKeyValueTrait>* map_;
3680 const intptr_t max_expr_id_;
3681 3870
3682 // Mapping between field offsets in words and expression ids of loads from 3871 // Mapping between field offsets in words and expression ids of loads from
3683 // that offset. 3872 // that offset.
3684 const GrowableArray<BitVector*>& kill_by_offset_; 3873 AliasedSet* aliased_set_;
3685 3874
3686 // Per block sets of expression ids for loads that are: incoming (available 3875 // Per block sets of expression ids for loads that are: incoming (available
3687 // on the entry), outgoing (available on the exit), generated and killed. 3876 // on the entry), outgoing (available on the exit), generated and killed.
3688 GrowableArray<BitVector*> in_; 3877 GrowableArray<BitVector*> in_;
3689 GrowableArray<BitVector*> out_; 3878 GrowableArray<BitVector*> out_;
3690 GrowableArray<BitVector*> gen_; 3879 GrowableArray<BitVector*> gen_;
3691 GrowableArray<BitVector*> kill_; 3880 GrowableArray<BitVector*> kill_;
3692 3881
3693 // Per block list of upwards exposed loads. 3882 // Per block list of upwards exposed loads.
3694 GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_; 3883 GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_;
3695 3884
3696 // Per block mappings between expression ids and outgoing definitions that 3885 // Per block mappings between expression ids and outgoing definitions that
3697 // represent those ids. 3886 // represent those ids.
3698 GrowableArray<ZoneGrowableArray<Definition*>*> out_values_; 3887 GrowableArray<ZoneGrowableArray<Definition*>*> out_values_;
3699 3888
3700 // List of phis generated during ComputeOutValues and ForwardLoads. 3889 // List of phis generated during ComputeOutValues and ForwardLoads.
3701 // Some of these phis might be redundant and thus a separate pass is 3890 // Some of these phis might be redundant and thus a separate pass is
3702 // needed to emit only non-redundant ones. 3891 // needed to emit only non-redundant ones.
3703 GrowableArray<PhiInstr*> phis_; 3892 GrowableArray<PhiInstr*> phis_;
3704 3893
3705 // Auxiliary worklist used by redundant phi elimination. 3894 // Auxiliary worklist used by redundant phi elimination.
3706 GrowableArray<PhiInstr*> worklist_; 3895 GrowableArray<PhiInstr*> worklist_;
3707 BitVector* in_worklist_; 3896 BitVector* in_worklist_;
3708 3897
3898 // True if any load was eliminated.
3899 bool forwarded_;
3900
3709 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); 3901 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer);
3710 }; 3902 };
3711 3903
3712 3904
3713 bool DominatorBasedCSE::Optimize(FlowGraph* graph) { 3905 bool DominatorBasedCSE::Optimize(FlowGraph* graph) {
3714 bool changed = false; 3906 bool changed = false;
3715 if (FLAG_load_cse) { 3907 if (FLAG_load_cse) {
3716 GrowableArray<BitVector*> kill_by_offs(10); 3908 GrowableArray<BitVector*> kill_by_offs(10);
3717 DirectChainedHashMap<LoadKeyValueTrait> map; 3909 DirectChainedHashMap<LoadKeyValueTrait> map;
3718 const intptr_t max_expr_id = 3910 AliasedSet* aliased_set = NumberLoadExpressions(graph, &map);
3719 NumberLoadExpressions(graph, &map, &kill_by_offs); 3911 if (!aliased_set->IsEmpty()) {
3720 if (max_expr_id > 0) { 3912 // If any loads were forwarded return true from Optimize to run load
3721 LoadOptimizer load_optimizer(graph, max_expr_id, &map, kill_by_offs); 3913 // forwarding again. This will allow to forward chains of loads.
3722 load_optimizer.Optimize(); 3914 // This is especially important for context variables as they are built
3915 // as loads from loaded context.
3916 // TODO(vegorov): renumber newly discovered congruences during the
3917 // forwarding to forward chains without running whole pass twice.
3918 LoadOptimizer load_optimizer(graph, aliased_set, &map);
3919 changed = load_optimizer.Optimize() || changed;
3723 } 3920 }
3724 } 3921 }
3725 3922
3726 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; 3923 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map;
3727 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; 3924 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed;
3728 3925
3729 return changed; 3926 return changed;
3730 } 3927 }
3731 3928
3732 3929
(...skipping 1386 matching lines...) Expand 10 before | Expand all | Expand 10 after
5119 if (changed) { 5316 if (changed) {
5120 // We may have changed the block order and the dominator tree. 5317 // We may have changed the block order and the dominator tree.
5121 flow_graph->DiscoverBlocks(); 5318 flow_graph->DiscoverBlocks();
5122 GrowableArray<BitVector*> dominance_frontier; 5319 GrowableArray<BitVector*> dominance_frontier;
5123 flow_graph->ComputeDominators(&dominance_frontier); 5320 flow_graph->ComputeDominators(&dominance_frontier);
5124 } 5321 }
5125 } 5322 }
5126 5323
5127 5324
5128 } // namespace dart 5325 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/hash_map.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698