| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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/redundancy_elimination.h" | 5 #include "vm/redundancy_elimination.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph.h" | 8 #include "vm/flow_graph.h" |
| 9 #include "vm/hash_map.h" | 9 #include "vm/hash_map.h" |
| 10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
| 11 #include "vm/intermediate_language.h" | 11 #include "vm/intermediate_language.h" |
| 12 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); | 16 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); |
| 17 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 17 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 18 DEFINE_FLAG(bool, | 18 DEFINE_FLAG(bool, |
| 19 trace_load_optimization, | 19 trace_load_optimization, |
| 20 false, | 20 false, |
| 21 "Print live sets for load optimization pass."); | 21 "Print live sets for load optimization pass."); |
| 22 | 22 |
| 23 // Quick access to the current zone. | 23 // Quick access to the current zone. |
| 24 #define Z (zone()) | 24 #define Z (zone()) |
| 25 | 25 |
| 26 class CSEInstructionMap : public ValueObject { | 26 class CSEInstructionMap : public ValueObject { |
| 27 public: | 27 public: |
| 28 // Right now CSE and LICM track a single effect which is no longer used. | 28 CSEInstructionMap() : map_() {} |
| 29 // TODO(alexmarkov): cleanup. | 29 explicit CSEInstructionMap(const CSEInstructionMap& other) |
| 30 // Other effects like modifications of fields are tracked in a separate load | 30 : ValueObject(), map_(other.map_) {} |
| 31 // forwarding pass via Alias structure. | |
| 32 COMPILE_ASSERT(EffectSet::kLastEffect == 1); | |
| 33 | 31 |
| 34 CSEInstructionMap() : independent_(), dependent_() {} | 32 Instruction* Lookup(Instruction* other) const { |
| 35 explicit CSEInstructionMap(const CSEInstructionMap& other) | 33 ASSERT(other->AllowsCSE()); |
| 36 : ValueObject(), | 34 ASSERT(other->Dependencies().IsNone()); |
| 37 independent_(other.independent_), | 35 return map_.LookupValue(other); |
| 38 dependent_(other.dependent_) {} | |
| 39 | |
| 40 void RemoveAffected(EffectSet effects) { | |
| 41 if (!effects.IsNone()) { | |
| 42 dependent_.Clear(); | |
| 43 } | |
| 44 } | 36 } |
| 45 | 37 |
| 46 Instruction* Lookup(Instruction* other) const { | 38 void Insert(Instruction* instr) { |
| 47 return GetMapFor(other)->LookupValue(other); | 39 ASSERT(instr->AllowsCSE()); |
| 40 ASSERT(instr->Dependencies().IsNone()); |
| 41 return map_.Insert(instr); |
| 48 } | 42 } |
| 49 | 43 |
| 50 void Insert(Instruction* instr) { return GetMapFor(instr)->Insert(instr); } | |
| 51 | |
| 52 private: | 44 private: |
| 53 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; | 45 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; |
| 54 | 46 |
| 55 Map* GetMapFor(Instruction* instr) { | 47 Map map_; |
| 56 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | |
| 57 } | |
| 58 | |
| 59 const Map* GetMapFor(Instruction* instr) const { | |
| 60 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | |
| 61 } | |
| 62 | |
| 63 // All computations that are not affected by any side-effect. | |
| 64 // Majority of computations are not affected by anything and will be in | |
| 65 // this map. | |
| 66 Map independent_; | |
| 67 | |
| 68 // All computations that are affected by side effect. | |
| 69 Map dependent_; | |
| 70 }; | 48 }; |
| 71 | 49 |
| 72 // Place describes an abstract location (e.g. field) that IR can load | 50 // Place describes an abstract location (e.g. field) that IR can load |
| 73 // from or store to. | 51 // from or store to. |
| 74 // | 52 // |
| 75 // Places are also used to describe wild-card locations also known as aliases, | 53 // Places are also used to describe wild-card locations also known as aliases, |
| 76 // that essentially represent sets of places that alias each other. Places A | 54 // that essentially represent sets of places that alias each other. Places A |
| 77 // and B are said to alias each other if store into A can affect load from B. | 55 // and B are said to alias each other if store into A can affect load from B. |
| 78 // | 56 // |
| 79 // We distinguish the following aliases: | 57 // We distinguish the following aliases: |
| (...skipping 1510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1590 // Check if this load needs renumbering because of the intrablock | 1568 // Check if this load needs renumbering because of the intrablock |
| 1591 // load forwarding. | 1569 // load forwarding. |
| 1592 const Place* canonical = aliased_set_->LookupCanonical(&place); | 1570 const Place* canonical = aliased_set_->LookupCanonical(&place); |
| 1593 if ((canonical != NULL) && | 1571 if ((canonical != NULL) && |
| 1594 (canonical->id() != instr->AsDefinition()->place_id())) { | 1572 (canonical->id() != instr->AsDefinition()->place_id())) { |
| 1595 instr->AsDefinition()->set_place_id(canonical->id()); | 1573 instr->AsDefinition()->set_place_id(canonical->id()); |
| 1596 } | 1574 } |
| 1597 } | 1575 } |
| 1598 | 1576 |
| 1599 // If instruction has effects then kill all loads affected. | 1577 // If instruction has effects then kill all loads affected. |
| 1600 if (!instr->Effects().IsNone()) { | 1578 if (instr->HasSideEffects()) { |
| 1601 kill->AddAll(aliased_set_->aliased_by_effects()); | 1579 kill->AddAll(aliased_set_->aliased_by_effects()); |
| 1602 // There is no need to clear out_values when removing values from GEN | 1580 // There is no need to clear out_values when removing values from GEN |
| 1603 // set because only those values that are in the GEN set | 1581 // set because only those values that are in the GEN set |
| 1604 // will ever be used. | 1582 // will ever be used. |
| 1605 gen->RemoveAll(aliased_set_->aliased_by_effects()); | 1583 gen->RemoveAll(aliased_set_->aliased_by_effects()); |
| 1606 continue; | 1584 continue; |
| 1607 } | 1585 } |
| 1608 | 1586 |
| 1609 Definition* defn = instr->AsDefinition(); | 1587 Definition* defn = instr->AsDefinition(); |
| 1610 if (defn == NULL) { | 1588 if (defn == NULL) { |
| (...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2349 } | 2327 } |
| 2350 | 2328 |
| 2351 bool DominatorBasedCSE::OptimizeRecursive(FlowGraph* graph, | 2329 bool DominatorBasedCSE::OptimizeRecursive(FlowGraph* graph, |
| 2352 BlockEntryInstr* block, | 2330 BlockEntryInstr* block, |
| 2353 CSEInstructionMap* map) { | 2331 CSEInstructionMap* map) { |
| 2354 bool changed = false; | 2332 bool changed = false; |
| 2355 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2333 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 2356 Instruction* current = it.Current(); | 2334 Instruction* current = it.Current(); |
| 2357 if (current->AllowsCSE()) { | 2335 if (current->AllowsCSE()) { |
| 2358 Instruction* replacement = map->Lookup(current); | 2336 Instruction* replacement = map->Lookup(current); |
| 2337 ASSERT((replacement == NULL) || replacement->AllowsCSE()); |
| 2359 if ((replacement != NULL) && | 2338 if ((replacement != NULL) && |
| 2360 graph->block_effects()->IsAvailableAt(replacement, block)) { | 2339 graph->block_effects()->IsAvailableAt(replacement, block)) { |
| 2361 // Replace current with lookup result. | 2340 // Replace current with lookup result. |
| 2362 graph->ReplaceCurrentInstruction(&it, current, replacement); | 2341 graph->ReplaceCurrentInstruction(&it, current, replacement); |
| 2363 changed = true; | 2342 changed = true; |
| 2364 continue; | 2343 continue; |
| 2365 } | 2344 } |
| 2366 | 2345 |
| 2367 // For simplicity we assume that instruction either does not depend on | 2346 // For simplicity we assume that instruction either does not depend on |
| 2368 // anything or does not affect anything. If this is not the case then | 2347 // anything or does not affect anything. If this is not the case then |
| 2369 // we should first remove affected instructions from the map and | 2348 // we should first remove affected instructions from the map and |
| 2370 // then add instruction to the map so that it does not kill itself. | 2349 // then add instruction to the map so that it does not kill itself. |
| 2371 ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); | 2350 ASSERT(!current->HasSideEffects() || current->Dependencies().IsNone()); |
| 2372 map->Insert(current); | 2351 map->Insert(current); |
| 2373 } | 2352 } |
| 2374 | |
| 2375 map->RemoveAffected(current->Effects()); | |
| 2376 } | 2353 } |
| 2377 | 2354 |
| 2378 // Process children in the dominator tree recursively. | 2355 // Process children in the dominator tree recursively. |
| 2379 intptr_t num_children = block->dominated_blocks().length(); | 2356 intptr_t num_children = block->dominated_blocks().length(); |
| 2380 if (num_children != 0) { | 2357 if (num_children != 0) { |
| 2381 graph->thread()->CheckForSafepoint(); | 2358 graph->thread()->CheckForSafepoint(); |
| 2382 } | 2359 } |
| 2383 for (intptr_t i = 0; i < num_children; ++i) { | 2360 for (intptr_t i = 0; i < num_children; ++i) { |
| 2384 BlockEntryInstr* child = block->dominated_blocks()[i]; | 2361 BlockEntryInstr* child = block->dominated_blocks()[i]; |
| 2385 if (i < num_children - 1) { | 2362 if (i < num_children - 1) { |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2512 } | 2489 } |
| 2513 exposed_stores->Add(instr); | 2490 exposed_stores->Add(instr); |
| 2514 } | 2491 } |
| 2515 // Interfering stores kill only loads from the same place. | 2492 // Interfering stores kill only loads from the same place. |
| 2516 kill->Add(instr->place_id()); | 2493 kill->Add(instr->place_id()); |
| 2517 live_in->Remove(instr->place_id()); | 2494 live_in->Remove(instr->place_id()); |
| 2518 continue; | 2495 continue; |
| 2519 } | 2496 } |
| 2520 | 2497 |
| 2521 // Handle side effects, deoptimization and function return. | 2498 // Handle side effects, deoptimization and function return. |
| 2522 if (!instr->Effects().IsNone() || instr->CanDeoptimize() || | 2499 if (instr->HasSideEffects() || instr->CanDeoptimize() || |
| 2523 instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { | 2500 instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { |
| 2524 // Instructions that return from the function, instructions with side | 2501 // Instructions that return from the function, instructions with side |
| 2525 // effects and instructions that can deoptimize are considered as | 2502 // effects and instructions that can deoptimize are considered as |
| 2526 // loads from all places. | 2503 // loads from all places. |
| 2527 live_in->CopyFrom(all_places); | 2504 live_in->CopyFrom(all_places); |
| 2528 if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { | 2505 if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { |
| 2529 // Initialize live-out for exit blocks since it won't be computed | 2506 // Initialize live-out for exit blocks since it won't be computed |
| 2530 // otherwise during the fixed point iteration. | 2507 // otherwise during the fixed point iteration. |
| 2531 live_out->CopyFrom(all_places); | 2508 live_out->CopyFrom(all_places); |
| 2532 } | 2509 } |
| (...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3327 if (to_index == 0) { | 3304 if (to_index == 0) { |
| 3328 join->phis_ = NULL; | 3305 join->phis_ = NULL; |
| 3329 } else { | 3306 } else { |
| 3330 join->phis_->TruncateTo(to_index); | 3307 join->phis_->TruncateTo(to_index); |
| 3331 } | 3308 } |
| 3332 } | 3309 } |
| 3333 } | 3310 } |
| 3334 } | 3311 } |
| 3335 | 3312 |
| 3336 } // namespace dart | 3313 } // namespace dart |
| OLD | NEW |