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

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