Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |