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/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 5598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5609 GrowableArray<ZoneGrowableArray<Move>* > moves_; | 5609 GrowableArray<ZoneGrowableArray<Move>* > moves_; |
| 5610 }; | 5610 }; |
| 5611 | 5611 |
| 5612 | 5612 |
| 5613 // A map from aliases to a set of places sharing the alias. Additionally | 5613 // A map from aliases to a set of places sharing the alias. Additionally |
| 5614 // carries a set of places that can be aliased by side-effects, essentially | 5614 // carries a set of places that can be aliased by side-effects, essentially |
| 5615 // those that are affected by calls. | 5615 // those that are affected by calls. |
| 5616 class AliasedSet : public ZoneAllocated { | 5616 class AliasedSet : public ZoneAllocated { |
| 5617 public: | 5617 public: |
| 5618 AliasedSet(Isolate* isolate, | 5618 AliasedSet(Isolate* isolate, |
| 5619 DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map, | |
| 5619 ZoneGrowableArray<Place*>* places, | 5620 ZoneGrowableArray<Place*>* places, |
| 5620 PhiPlaceMoves* phi_moves) | 5621 PhiPlaceMoves* phi_moves) |
| 5621 : isolate_(isolate), | 5622 : isolate_(isolate), |
| 5623 places_map_(places_map), | |
| 5622 places_(*places), | 5624 places_(*places), |
| 5623 phi_moves_(phi_moves), | 5625 phi_moves_(phi_moves), |
| 5624 aliases_(5), | 5626 aliases_(5), |
| 5625 aliases_map_(), | 5627 aliases_map_(), |
| 5626 representatives_(), | 5628 representatives_(), |
| 5627 killed_(), | 5629 killed_(), |
| 5628 aliased_by_effects_(new(isolate) BitVector(isolate, places->length())) { | 5630 aliased_by_effects_(new(isolate) BitVector(isolate, places->length())) { |
| 5629 InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(isolate_, | 5631 InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(isolate_, |
| 5630 kAnyInstanceAnyIndexAlias)); | 5632 kAnyInstanceAnyIndexAlias)); |
| 5631 for (intptr_t i = 0; i < places_.length(); i++) { | 5633 for (intptr_t i = 0; i < places_.length(); i++) { |
| 5632 AddRepresentative(places_[i]); | 5634 AddRepresentative(places_[i]); |
| 5633 } | 5635 } |
| 5634 ComputeKillSets(); | 5636 ComputeKillSets(); |
| 5635 } | 5637 } |
| 5636 | 5638 |
| 5637 intptr_t LookupAliasId(const Place& alias) { | 5639 intptr_t LookupAliasId(const Place& alias) { |
| 5638 const Place* result = aliases_map_.Lookup(&alias); | 5640 const Place* result = aliases_map_.Lookup(&alias); |
| 5639 return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias); | 5641 return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias); |
| 5640 } | 5642 } |
| 5641 | 5643 |
| 5642 bool IsStore(Instruction* instr, BitVector** killed) { | 5644 bool IsStore(Instruction* instr, BitVector** killed) { |
|
Florian Schneider
2014/11/17 12:46:02
The name is a little misleading since this method
| |
| 5643 bool is_load = false, is_store = false; | 5645 bool is_load = false, is_store = false; |
| 5644 Place place(instr, &is_load, &is_store); | 5646 Place place(instr, &is_load, &is_store); |
| 5645 if (is_store && (place.kind() != Place::kNone)) { | 5647 if (is_store && (place.kind() != Place::kNone)) { |
| 5646 const intptr_t alias_id = LookupAliasId(place.ToAlias()); | 5648 const intptr_t alias_id = LookupAliasId(place.ToAlias()); |
| 5647 if (alias_id != kNoAlias) { | 5649 if (alias_id != kNoAlias) { |
| 5648 *killed = GetKilledSet(alias_id); | 5650 *killed = GetKilledSet(alias_id); |
| 5649 } else if (!place.IsFinalField()) { | 5651 } else if (!place.IsFinalField()) { |
| 5650 // We encountered unknown alias: this means intrablock load forwarding | 5652 // We encountered unknown alias: this means intrablock load forwarding |
| 5651 // refined parameter of this store, for example | 5653 // refined parameter of this store, for example |
| 5652 // | 5654 // |
| 5653 // o <- alloc() | 5655 // o <- alloc() |
| 5654 // a.f <- o | 5656 // a.f <- o |
| 5655 // u <- a.f | 5657 // u <- a.f |
| 5656 // u.x <- null ;; this store alias is *.x | 5658 // u.x <- null ;; this store alias is *.x |
| 5657 // | 5659 // |
| 5658 // after intrablock load forwarding | 5660 // after intrablock load forwarding |
| 5659 // | 5661 // |
| 5660 // o <- alloc() | 5662 // o <- alloc() |
| 5661 // a.f <- o | 5663 // a.f <- o |
| 5662 // o.x <- null ;; this store alias is o.x | 5664 // o.x <- null ;; this store alias is o.x |
| 5663 // | 5665 // |
| 5664 // In this case we fallback to using place id recorded in the | 5666 // In this case we fallback to using place id recorded in the |
| 5665 // instruction that still points to the old place with a more generic | 5667 // instruction that still points to the old place with a more generic |
| 5666 // alias. | 5668 // alias. |
| 5667 *killed = GetKilledSet( | 5669 *killed = GetKilledSet( |
| 5668 LookupAliasId(places_[instr->place_id()]->ToAlias())); | 5670 LookupAliasId(places_[instr->place_id()]->ToAlias())); |
| 5669 } | 5671 } |
| 5672 } else if (is_load && (place.kind() != Place::kNone)) { | |
| 5673 const Place* canonical = LookupCanonical(&place); | |
| 5674 if ((canonical != NULL) && | |
| 5675 (canonical->id() != instr->AsDefinition()->place_id())) { | |
| 5676 instr->AsDefinition()->set_place_id(canonical->id()); | |
| 5677 } | |
| 5670 } | 5678 } |
| 5671 return is_store; | 5679 return is_store; |
| 5672 } | 5680 } |
| 5673 | 5681 |
| 5674 BitVector* GetKilledSet(intptr_t alias) { | 5682 BitVector* GetKilledSet(intptr_t alias) { |
| 5675 return (alias < killed_.length()) ? killed_[alias] : NULL; | 5683 return (alias < killed_.length()) ? killed_[alias] : NULL; |
| 5676 } | 5684 } |
| 5677 | 5685 |
| 5678 intptr_t max_place_id() const { return places().length(); } | 5686 intptr_t max_place_id() const { return places().length(); } |
| 5679 bool IsEmpty() const { return max_place_id() == 0; } | 5687 bool IsEmpty() const { return max_place_id() == 0; } |
| 5680 | 5688 |
| 5681 BitVector* aliased_by_effects() const { return aliased_by_effects_; } | 5689 BitVector* aliased_by_effects() const { return aliased_by_effects_; } |
| 5682 | 5690 |
| 5683 const ZoneGrowableArray<Place*>& places() const { | 5691 const ZoneGrowableArray<Place*>& places() const { |
| 5684 return places_; | 5692 return places_; |
| 5685 } | 5693 } |
| 5686 | 5694 |
| 5695 Place* LookupCanonical(Place* place) const { | |
| 5696 return places_map_->Lookup(place); | |
| 5697 } | |
| 5698 | |
| 5687 void PrintSet(BitVector* set) { | 5699 void PrintSet(BitVector* set) { |
| 5688 bool comma = false; | 5700 bool comma = false; |
| 5689 for (BitVector::Iterator it(set); | 5701 for (BitVector::Iterator it(set); |
| 5690 !it.Done(); | 5702 !it.Done(); |
| 5691 it.Advance()) { | 5703 it.Advance()) { |
| 5692 if (comma) { | 5704 if (comma) { |
| 5693 OS::Print(", "); | 5705 OS::Print(", "); |
| 5694 } | 5706 } |
| 5695 OS::Print("%s", places_[it.Current()]->ToCString()); | 5707 OS::Print("%s", places_[it.Current()]->ToCString()); |
| 5696 comma = true; | 5708 comma = true; |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6048 // If the allocation site is marked as aliased conservatively mark | 6060 // If the allocation site is marked as aliased conservatively mark |
| 6049 // any values stored into the object aliased too. | 6061 // any values stored into the object aliased too. |
| 6050 if (defn->Identity().IsAliased()) { | 6062 if (defn->Identity().IsAliased()) { |
| 6051 MarkStoredValuesEscaping(defn); | 6063 MarkStoredValuesEscaping(defn); |
| 6052 } | 6064 } |
| 6053 } | 6065 } |
| 6054 } | 6066 } |
| 6055 | 6067 |
| 6056 Isolate* isolate_; | 6068 Isolate* isolate_; |
| 6057 | 6069 |
| 6070 DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map_; | |
| 6071 | |
| 6058 const ZoneGrowableArray<Place*>& places_; | 6072 const ZoneGrowableArray<Place*>& places_; |
| 6059 | 6073 |
| 6060 const PhiPlaceMoves* phi_moves_; | 6074 const PhiPlaceMoves* phi_moves_; |
| 6061 | 6075 |
| 6062 // A list of all seen aliases and a map that allows looking up canonical | 6076 // A list of all seen aliases and a map that allows looking up canonical |
| 6063 // alias object. | 6077 // alias object. |
| 6064 GrowableArray<const Place*> aliases_; | 6078 GrowableArray<const Place*> aliases_; |
| 6065 DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_; | 6079 DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_; |
| 6066 | 6080 |
| 6067 // Maps alias id to set of ids of places representing the alias. | 6081 // Maps alias id to set of ids of places representing the alias. |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6217 if ((mode == kOptimizeLoads) && !has_loads) { | 6231 if ((mode == kOptimizeLoads) && !has_loads) { |
| 6218 return NULL; | 6232 return NULL; |
| 6219 } | 6233 } |
| 6220 if ((mode == kOptimizeStores) && !has_stores) { | 6234 if ((mode == kOptimizeStores) && !has_stores) { |
| 6221 return NULL; | 6235 return NULL; |
| 6222 } | 6236 } |
| 6223 | 6237 |
| 6224 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); | 6238 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); |
| 6225 | 6239 |
| 6226 // Build aliasing sets mapping aliases to loads. | 6240 // Build aliasing sets mapping aliases to loads. |
| 6227 return new(isolate) AliasedSet(isolate, places, phi_moves); | 6241 return new(isolate) AliasedSet(isolate, map, places, phi_moves); |
| 6228 } | 6242 } |
| 6229 | 6243 |
| 6230 | 6244 |
| 6231 class LoadOptimizer : public ValueObject { | 6245 class LoadOptimizer : public ValueObject { |
| 6232 public: | 6246 public: |
| 6233 LoadOptimizer(FlowGraph* graph, | 6247 LoadOptimizer(FlowGraph* graph, AliasedSet* aliased_set) |
| 6234 AliasedSet* aliased_set, | |
| 6235 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) | |
| 6236 : graph_(graph), | 6248 : graph_(graph), |
| 6237 map_(map), | |
| 6238 aliased_set_(aliased_set), | 6249 aliased_set_(aliased_set), |
| 6239 in_(graph_->preorder().length()), | 6250 in_(graph_->preorder().length()), |
| 6240 out_(graph_->preorder().length()), | 6251 out_(graph_->preorder().length()), |
| 6241 gen_(graph_->preorder().length()), | 6252 gen_(graph_->preorder().length()), |
| 6242 kill_(graph_->preorder().length()), | 6253 kill_(graph_->preorder().length()), |
| 6243 exposed_values_(graph_->preorder().length()), | 6254 exposed_values_(graph_->preorder().length()), |
| 6244 out_values_(graph_->preorder().length()), | 6255 out_values_(graph_->preorder().length()), |
| 6245 phis_(5), | 6256 phis_(5), |
| 6246 worklist_(5), | 6257 worklist_(5), |
| 6247 congruency_worklist_(6), | 6258 congruency_worklist_(6), |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 6273 | 6284 |
| 6274 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; | 6285 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
| 6275 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads); | 6286 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads); |
| 6276 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { | 6287 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
| 6277 // If any loads were forwarded return true from Optimize to run load | 6288 // If any loads were forwarded return true from Optimize to run load |
| 6278 // forwarding again. This will allow to forward chains of loads. | 6289 // forwarding again. This will allow to forward chains of loads. |
| 6279 // This is especially important for context variables as they are built | 6290 // This is especially important for context variables as they are built |
| 6280 // as loads from loaded context. | 6291 // as loads from loaded context. |
| 6281 // TODO(vegorov): renumber newly discovered congruences during the | 6292 // TODO(vegorov): renumber newly discovered congruences during the |
| 6282 // forwarding to forward chains without running whole pass twice. | 6293 // forwarding to forward chains without running whole pass twice. |
| 6283 LoadOptimizer load_optimizer(graph, aliased_set, &map); | 6294 LoadOptimizer load_optimizer(graph, aliased_set); |
| 6284 return load_optimizer.Optimize(); | 6295 return load_optimizer.Optimize(); |
| 6285 } | 6296 } |
| 6286 return false; | 6297 return false; |
| 6287 } | 6298 } |
| 6288 | 6299 |
| 6289 private: | 6300 private: |
| 6290 bool Optimize() { | 6301 bool Optimize() { |
| 6291 ComputeInitialSets(); | 6302 ComputeInitialSets(); |
| 6292 ComputeOutSets(); | 6303 ComputeOutSets(); |
| 6293 ComputeOutValues(); | 6304 ComputeOutValues(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6343 // may implicitly convert the value stored. | 6354 // may implicitly convert the value stored. |
| 6344 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); | 6355 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); |
| 6345 if ((array_store == NULL) || | 6356 if ((array_store == NULL) || |
| 6346 (array_store->class_id() == kArrayCid) || | 6357 (array_store->class_id() == kArrayCid) || |
| 6347 (array_store->class_id() == kTypedDataFloat64ArrayCid) || | 6358 (array_store->class_id() == kTypedDataFloat64ArrayCid) || |
| 6348 (array_store->class_id() == kTypedDataFloat32ArrayCid) || | 6359 (array_store->class_id() == kTypedDataFloat32ArrayCid) || |
| 6349 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { | 6360 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { |
| 6350 bool is_load = false, is_store = false; | 6361 bool is_load = false, is_store = false; |
| 6351 Place store_place(instr, &is_load, &is_store); | 6362 Place store_place(instr, &is_load, &is_store); |
| 6352 ASSERT(!is_load && is_store); | 6363 ASSERT(!is_load && is_store); |
| 6353 Place* place = map_->Lookup(&store_place); | 6364 Place* place = aliased_set_->LookupCanonical(&store_place); |
| 6354 if (place != NULL) { | 6365 if (place != NULL) { |
| 6355 // Store has a corresponding numbered place that might have a | 6366 // Store has a corresponding numbered place that might have a |
| 6356 // load. Try forwarding stored value to it. | 6367 // load. Try forwarding stored value to it. |
| 6357 gen->Add(place->id()); | 6368 gen->Add(place->id()); |
| 6358 if (out_values == NULL) out_values = CreateBlockOutValues(); | 6369 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 6359 (*out_values)[place->id()] = GetStoredValue(instr); | 6370 (*out_values)[place->id()] = GetStoredValue(instr); |
| 6360 } | 6371 } |
| 6361 } | 6372 } |
| 6362 | 6373 |
| 6363 ASSERT(!instr->IsDefinition() || | 6374 ASSERT(!instr->IsDefinition() || |
| (...skipping 3649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10013 | 10024 |
| 10014 // Insert materializations at environment uses. | 10025 // Insert materializations at environment uses. |
| 10015 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 10026 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 10016 CreateMaterializationAt( | 10027 CreateMaterializationAt( |
| 10017 exits_collector_.exits()[i], alloc, *slots); | 10028 exits_collector_.exits()[i], alloc, *slots); |
| 10018 } | 10029 } |
| 10019 } | 10030 } |
| 10020 | 10031 |
| 10021 | 10032 |
| 10022 } // namespace dart | 10033 } // namespace dart |
| OLD | NEW |