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" |
11 #include "vm/flow_graph_builder.h" | 11 #include "vm/flow_graph_builder.h" |
12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
13 #include "vm/hash_map.h" | 13 #include "vm/hash_map.h" |
14 #include "vm/il_printer.h" | 14 #include "vm/il_printer.h" |
15 #include "vm/intermediate_language.h" | 15 #include "vm/intermediate_language.h" |
16 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
17 #include "vm/parser.h" | 17 #include "vm/parser.h" |
18 #include "vm/resolver.h" | 18 #include "vm/resolver.h" |
19 #include "vm/scopes.h" | 19 #include "vm/scopes.h" |
20 #include "vm/stack_frame.h" | 20 #include "vm/stack_frame.h" |
21 #include "vm/symbols.h" | 21 #include "vm/symbols.h" |
22 | 22 |
23 namespace dart { | 23 namespace dart { |
24 | 24 |
25 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 25 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
26 "Eliminate redundant bounds checks."); | 26 "Eliminate redundant bounds checks."); |
27 DEFINE_FLAG(int, getter_setter_ratio, 13, | 27 DEFINE_FLAG(int, getter_setter_ratio, 13, |
28 "Ratio of getter/setter usage used for double field unboxing heuristics"); | 28 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
29 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 29 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 30 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); |
30 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 31 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
31 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 32 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
32 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | 33 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
33 "Maximum number of polymorphic checks in equality operator," | 34 "Maximum number of polymorphic checks in equality operator," |
34 " otherwise use megamorphic dispatch."); | 35 " otherwise use megamorphic dispatch."); |
35 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 36 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
36 DEFINE_FLAG(bool, trace_constant_propagation, false, | 37 DEFINE_FLAG(bool, trace_constant_propagation, false, |
37 "Print constant propagation and useless code elimination."); | 38 "Print constant propagation and useless code elimination."); |
38 DEFINE_FLAG(bool, trace_load_optimization, false, | 39 DEFINE_FLAG(bool, trace_load_optimization, false, |
39 "Print live sets for load optimization pass."); | 40 "Print live sets for load optimization pass."); |
(...skipping 4051 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4091 } else { | 4092 } else { |
4092 call_with_checks = true; | 4093 call_with_checks = true; |
4093 } | 4094 } |
4094 PolymorphicInstanceCallInstr* call = | 4095 PolymorphicInstanceCallInstr* call = |
4095 new PolymorphicInstanceCallInstr(instr, unary_checks, | 4096 new PolymorphicInstanceCallInstr(instr, unary_checks, |
4096 call_with_checks); | 4097 call_with_checks); |
4097 instr->ReplaceWith(call, current_iterator()); | 4098 instr->ReplaceWith(call, current_iterator()); |
4098 } | 4099 } |
4099 } | 4100 } |
4100 | 4101 |
| 4102 |
4101 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 4103 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { |
4102 MethodRecognizer::Kind recognized_kind = | 4104 MethodRecognizer::Kind recognized_kind = |
4103 MethodRecognizer::RecognizeKind(call->function()); | 4105 MethodRecognizer::RecognizeKind(call->function()); |
4104 MathUnaryInstr::MathUnaryKind unary_kind; | 4106 MathUnaryInstr::MathUnaryKind unary_kind; |
4105 switch (recognized_kind) { | 4107 switch (recognized_kind) { |
4106 case MethodRecognizer::kMathSqrt: | 4108 case MethodRecognizer::kMathSqrt: |
4107 unary_kind = MathUnaryInstr::kSqrt; | 4109 unary_kind = MathUnaryInstr::kSqrt; |
4108 break; | 4110 break; |
4109 case MethodRecognizer::kMathSin: | 4111 case MethodRecognizer::kMathSin: |
4110 unary_kind = MathUnaryInstr::kSin; | 4112 unary_kind = MathUnaryInstr::kSin; |
(...skipping 983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5094 Hoist(it, pre_header, current); | 5096 Hoist(it, pre_header, current); |
5095 | 5097 |
5096 // Replace value we are checking with phi's input. | 5098 // Replace value we are checking with phi's input. |
5097 current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); | 5099 current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); |
5098 | 5100 |
5099 phi->UpdateType(CompileType::FromCid(kSmiCid)); | 5101 phi->UpdateType(CompileType::FromCid(kSmiCid)); |
5100 } | 5102 } |
5101 | 5103 |
5102 | 5104 |
5103 // Load instructions handled by load elimination. | 5105 // Load instructions handled by load elimination. |
5104 static bool IsCandidateLoad(Instruction* instr) { | 5106 static bool IsLoadEliminationCandidate(Instruction* instr) { |
5105 return instr->IsLoadField() | 5107 return instr->IsLoadField() |
5106 || instr->IsLoadIndexed() | 5108 || instr->IsLoadIndexed() |
5107 || instr->IsLoadStaticField() | 5109 || instr->IsLoadStaticField() |
5108 || instr->IsCurrentContext(); | 5110 || instr->IsCurrentContext(); |
5109 } | 5111 } |
5110 | 5112 |
5111 | 5113 |
5112 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, | 5114 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, |
5113 intptr_t loop_header_index, | 5115 intptr_t loop_header_index, |
5114 Instruction* instr) { | 5116 Instruction* instr) { |
5115 return IsCandidateLoad(instr) && | 5117 return IsLoadEliminationCandidate(instr) && |
5116 (sets != NULL) && | 5118 (sets != NULL) && |
5117 instr->HasPlaceId() && | 5119 instr->HasPlaceId() && |
5118 ((*sets)[loop_header_index] != NULL) && | 5120 ((*sets)[loop_header_index] != NULL) && |
5119 (*sets)[loop_header_index]->Contains(instr->place_id()); | 5121 (*sets)[loop_header_index]->Contains(instr->place_id()); |
5120 } | 5122 } |
5121 | 5123 |
5122 | 5124 |
5123 void LICM::Optimize() { | 5125 void LICM::Optimize() { |
5124 if (!flow_graph()->parsed_function().function(). | 5126 if (!flow_graph()->parsed_function().function(). |
5125 allows_hoisting_check_class()) { | 5127 allows_hoisting_check_class()) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5171 TryHoistCheckSmiThroughPhi( | 5173 TryHoistCheckSmiThroughPhi( |
5172 &it, header, pre_header, current->AsCheckSmi()); | 5174 &it, header, pre_header, current->AsCheckSmi()); |
5173 } | 5175 } |
5174 } | 5176 } |
5175 } | 5177 } |
5176 } | 5178 } |
5177 } | 5179 } |
5178 } | 5180 } |
5179 | 5181 |
5180 | 5182 |
5181 static bool IsLoadEliminationCandidate(Definition* def) { | |
5182 return def->IsLoadField() | |
5183 || def->IsLoadIndexed() | |
5184 || def->IsLoadStaticField() | |
5185 || def->IsCurrentContext(); | |
5186 } | |
5187 | |
5188 | |
5189 // Alias represents a family of locations. It is used to capture aliasing | 5183 // Alias represents a family of locations. It is used to capture aliasing |
5190 // between stores and loads. Store can alias another load or store if and only | 5184 // between stores and loads. Store can alias another load or store if and only |
5191 // if they have the same alias. | 5185 // if they have the same alias. |
5192 class Alias : public ValueObject { | 5186 class Alias : public ValueObject { |
5193 public: | 5187 public: |
5194 Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { } | 5188 Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { } |
5195 | 5189 |
5196 // All indexed load/stores alias each other. | 5190 // All indexed load/stores alias each other. |
5197 // TODO(vegorov): incorporate type of array into alias to disambiguate | 5191 // TODO(vegorov): incorporate type of array into alias to disambiguate |
5198 // different typed data and normal arrays. | 5192 // different typed data and normal arrays. |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5308 : ValueObject(), | 5302 : ValueObject(), |
5309 kind_(other.kind_), | 5303 kind_(other.kind_), |
5310 representation_(other.representation_), | 5304 representation_(other.representation_), |
5311 instance_(other.instance_), | 5305 instance_(other.instance_), |
5312 raw_selector_(other.raw_selector_), | 5306 raw_selector_(other.raw_selector_), |
5313 id_(other.id_) { | 5307 id_(other.id_) { |
5314 } | 5308 } |
5315 | 5309 |
5316 // Construct a place from instruction if instruction accesses any place. | 5310 // Construct a place from instruction if instruction accesses any place. |
5317 // Otherwise constructs kNone place. | 5311 // Otherwise constructs kNone place. |
5318 Place(Instruction* instr, bool* is_load) | 5312 Place(Instruction* instr, bool* is_load, bool* is_store) |
5319 : kind_(kNone), | 5313 : kind_(kNone), |
5320 representation_(kNoRepresentation), | 5314 representation_(kNoRepresentation), |
5321 instance_(NULL), | 5315 instance_(NULL), |
5322 raw_selector_(0), | 5316 raw_selector_(0), |
5323 id_(0) { | 5317 id_(0) { |
5324 switch (instr->tag()) { | 5318 switch (instr->tag()) { |
5325 case Instruction::kLoadField: { | 5319 case Instruction::kLoadField: { |
5326 LoadFieldInstr* load_field = instr->AsLoadField(); | 5320 LoadFieldInstr* load_field = instr->AsLoadField(); |
5327 representation_ = load_field->representation(); | 5321 representation_ = load_field->representation(); |
5328 instance_ = load_field->instance()->definition()->OriginalDefinition(); | 5322 instance_ = load_field->instance()->definition()->OriginalDefinition(); |
(...skipping 14 matching lines...) Expand all Loading... |
5343 representation_ = store->RequiredInputRepresentation( | 5337 representation_ = store->RequiredInputRepresentation( |
5344 StoreInstanceFieldInstr::kValuePos); | 5338 StoreInstanceFieldInstr::kValuePos); |
5345 instance_ = store->instance()->definition()->OriginalDefinition(); | 5339 instance_ = store->instance()->definition()->OriginalDefinition(); |
5346 if (!store->field().IsNull()) { | 5340 if (!store->field().IsNull()) { |
5347 kind_ = kField; | 5341 kind_ = kField; |
5348 field_ = &store->field(); | 5342 field_ = &store->field(); |
5349 } else { | 5343 } else { |
5350 kind_ = kVMField; | 5344 kind_ = kVMField; |
5351 offset_in_bytes_ = store->offset_in_bytes(); | 5345 offset_in_bytes_ = store->offset_in_bytes(); |
5352 } | 5346 } |
| 5347 *is_store = true; |
5353 break; | 5348 break; |
5354 } | 5349 } |
5355 | 5350 |
5356 case Instruction::kLoadStaticField: | 5351 case Instruction::kLoadStaticField: |
5357 kind_ = kField; | 5352 kind_ = kField; |
5358 representation_ = instr->AsLoadStaticField()->representation(); | 5353 representation_ = instr->AsLoadStaticField()->representation(); |
5359 field_ = &instr->AsLoadStaticField()->StaticField(); | 5354 field_ = &instr->AsLoadStaticField()->StaticField(); |
5360 *is_load = true; | 5355 *is_load = true; |
5361 break; | 5356 break; |
5362 | 5357 |
5363 case Instruction::kStoreStaticField: | 5358 case Instruction::kStoreStaticField: |
5364 kind_ = kField; | 5359 kind_ = kField; |
5365 representation_ = instr->AsStoreStaticField()-> | 5360 representation_ = instr->AsStoreStaticField()-> |
5366 RequiredInputRepresentation(StoreStaticFieldInstr::kValuePos); | 5361 RequiredInputRepresentation(StoreStaticFieldInstr::kValuePos); |
5367 field_ = &instr->AsStoreStaticField()->field(); | 5362 field_ = &instr->AsStoreStaticField()->field(); |
| 5363 *is_store = true; |
5368 break; | 5364 break; |
5369 | 5365 |
5370 case Instruction::kLoadIndexed: { | 5366 case Instruction::kLoadIndexed: { |
5371 LoadIndexedInstr* load_indexed = instr->AsLoadIndexed(); | 5367 LoadIndexedInstr* load_indexed = instr->AsLoadIndexed(); |
5372 kind_ = kIndexed; | 5368 kind_ = kIndexed; |
5373 representation_ = load_indexed->representation(); | 5369 representation_ = load_indexed->representation(); |
5374 instance_ = load_indexed->array()->definition()->OriginalDefinition(); | 5370 instance_ = load_indexed->array()->definition()->OriginalDefinition(); |
5375 index_ = load_indexed->index()->definition(); | 5371 index_ = load_indexed->index()->definition(); |
5376 *is_load = true; | 5372 *is_load = true; |
5377 break; | 5373 break; |
5378 } | 5374 } |
5379 | 5375 |
5380 case Instruction::kStoreIndexed: { | 5376 case Instruction::kStoreIndexed: { |
5381 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed(); | 5377 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed(); |
5382 kind_ = kIndexed; | 5378 kind_ = kIndexed; |
5383 representation_ = store_indexed-> | 5379 representation_ = store_indexed-> |
5384 RequiredInputRepresentation(StoreIndexedInstr::kValuePos); | 5380 RequiredInputRepresentation(StoreIndexedInstr::kValuePos); |
5385 instance_ = store_indexed->array()->definition()->OriginalDefinition(); | 5381 instance_ = store_indexed->array()->definition()->OriginalDefinition(); |
5386 index_ = store_indexed->index()->definition(); | 5382 index_ = store_indexed->index()->definition(); |
| 5383 *is_store = true; |
5387 break; | 5384 break; |
5388 } | 5385 } |
5389 | 5386 |
5390 case Instruction::kCurrentContext: | 5387 case Instruction::kCurrentContext: |
5391 kind_ = kContext; | 5388 kind_ = kContext; |
5392 ASSERT(instr->AsCurrentContext()->representation() == kTagged); | 5389 ASSERT(instr->AsCurrentContext()->representation() == kTagged); |
5393 representation_ = kTagged; | 5390 representation_ = kTagged; |
5394 *is_load = true; | 5391 *is_load = true; |
5395 break; | 5392 break; |
5396 | 5393 |
5397 case Instruction::kStoreContext: | 5394 case Instruction::kStoreContext: |
5398 kind_ = kContext; | 5395 kind_ = kContext; |
5399 ASSERT(instr->AsStoreContext()->RequiredInputRepresentation( | 5396 ASSERT(instr->AsStoreContext()->RequiredInputRepresentation( |
5400 StoreContextInstr::kValuePos) == kTagged); | 5397 StoreContextInstr::kValuePos) == kTagged); |
5401 representation_ = kTagged; | 5398 representation_ = kTagged; |
| 5399 *is_store = true; |
5402 break; | 5400 break; |
5403 | 5401 |
5404 default: | 5402 default: |
5405 break; | 5403 break; |
5406 } | 5404 } |
5407 } | 5405 } |
5408 | 5406 |
5409 intptr_t id() const { return id_; } | 5407 intptr_t id() const { return id_; } |
5410 void set_id(intptr_t id) { id_ = id; } | 5408 void set_id(intptr_t id) { id_ = id; } |
5411 | 5409 |
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6165 phi_moves->CreateOutgoingMove(block->PredecessorAt(j), | 6163 phi_moves->CreateOutgoingMove(block->PredecessorAt(j), |
6166 result->id(), | 6164 result->id(), |
6167 place->id()); | 6165 place->id()); |
6168 } | 6166 } |
6169 } | 6167 } |
6170 } | 6168 } |
6171 | 6169 |
6172 return phi_moves; | 6170 return phi_moves; |
6173 } | 6171 } |
6174 | 6172 |
| 6173 |
| 6174 enum CSEMode { |
| 6175 kOptimizeLoads, |
| 6176 kOptimizeStores |
| 6177 }; |
| 6178 |
| 6179 |
6175 static AliasedSet* NumberPlaces( | 6180 static AliasedSet* NumberPlaces( |
6176 FlowGraph* graph, | 6181 FlowGraph* graph, |
6177 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) { | 6182 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, |
| 6183 CSEMode mode) { |
6178 // Loads representing different expression ids will be collected and | 6184 // Loads representing different expression ids will be collected and |
6179 // used to build per offset kill sets. | 6185 // used to build per offset kill sets. |
6180 ZoneGrowableArray<Place*>* places = new ZoneGrowableArray<Place*>(10); | 6186 ZoneGrowableArray<Place*>* places = new ZoneGrowableArray<Place*>(10); |
6181 | 6187 |
6182 bool has_loads = false; | 6188 bool has_loads = false; |
| 6189 bool has_stores = false; |
6183 for (BlockIterator it = graph->reverse_postorder_iterator(); | 6190 for (BlockIterator it = graph->reverse_postorder_iterator(); |
6184 !it.Done(); | 6191 !it.Done(); |
6185 it.Advance()) { | 6192 it.Advance()) { |
6186 BlockEntryInstr* block = it.Current(); | 6193 BlockEntryInstr* block = it.Current(); |
6187 for (ForwardInstructionIterator instr_it(block); | 6194 for (ForwardInstructionIterator instr_it(block); |
6188 !instr_it.Done(); | 6195 !instr_it.Done(); |
6189 instr_it.Advance()) { | 6196 instr_it.Advance()) { |
6190 Instruction* instr = instr_it.Current(); | 6197 Instruction* instr = instr_it.Current(); |
6191 | 6198 Place place(instr, &has_loads, &has_stores); |
6192 Place place(instr, &has_loads); | |
6193 if (place.kind() == Place::kNone) { | 6199 if (place.kind() == Place::kNone) { |
6194 continue; | 6200 continue; |
6195 } | 6201 } |
6196 | 6202 |
6197 Place* result = map->Lookup(&place); | 6203 Place* result = map->Lookup(&place); |
6198 if (result == NULL) { | 6204 if (result == NULL) { |
6199 place.set_id(places->length()); | 6205 place.set_id(places->length()); |
6200 result = Place::Wrap(place); | 6206 result = Place::Wrap(place); |
6201 map->Insert(result); | 6207 map->Insert(result); |
6202 places->Add(result); | 6208 places->Add(result); |
6203 | 6209 |
6204 if (FLAG_trace_optimization) { | 6210 if (FLAG_trace_optimization) { |
6205 OS::Print("numbering %s as %" Pd "\n", | 6211 OS::Print("numbering %s as %" Pd "\n", |
6206 result->ToCString(), | 6212 result->ToCString(), |
6207 result->id()); | 6213 result->id()); |
6208 } | 6214 } |
6209 } | 6215 } |
6210 | 6216 |
6211 instr->set_place_id(result->id()); | 6217 instr->set_place_id(result->id()); |
6212 } | 6218 } |
6213 } | 6219 } |
6214 | 6220 |
6215 if (!has_loads) { | 6221 if ((mode == kOptimizeLoads) && !has_loads) { |
| 6222 return NULL; |
| 6223 } |
| 6224 if ((mode == kOptimizeStores) && !has_stores) { |
6216 return NULL; | 6225 return NULL; |
6217 } | 6226 } |
6218 | 6227 |
6219 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); | 6228 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); |
6220 | 6229 |
6221 // Build aliasing sets mapping aliases to loads. | 6230 // Build aliasing sets mapping aliases to loads. |
6222 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); | 6231 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); |
6223 for (intptr_t i = 0; i < places->length(); i++) { | 6232 for (intptr_t i = 0; i < places->length(); i++) { |
6224 Place* place = (*places)[i]; | 6233 Place* place = (*places)[i]; |
6225 aliased_set->AddRepresentative(place); | 6234 aliased_set->AddRepresentative(place); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6261 } | 6270 } |
6262 } | 6271 } |
6263 | 6272 |
6264 static bool OptimizeGraph(FlowGraph* graph) { | 6273 static bool OptimizeGraph(FlowGraph* graph) { |
6265 ASSERT(FLAG_load_cse); | 6274 ASSERT(FLAG_load_cse); |
6266 if (FLAG_trace_load_optimization) { | 6275 if (FLAG_trace_load_optimization) { |
6267 FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph); | 6276 FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph); |
6268 } | 6277 } |
6269 | 6278 |
6270 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; | 6279 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
6271 AliasedSet* aliased_set = NumberPlaces(graph, &map); | 6280 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads); |
6272 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { | 6281 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
6273 // If any loads were forwarded return true from Optimize to run load | 6282 // If any loads were forwarded return true from Optimize to run load |
6274 // forwarding again. This will allow to forward chains of loads. | 6283 // forwarding again. This will allow to forward chains of loads. |
6275 // This is especially important for context variables as they are built | 6284 // This is especially important for context variables as they are built |
6276 // as loads from loaded context. | 6285 // as loads from loaded context. |
6277 // TODO(vegorov): renumber newly discovered congruences during the | 6286 // TODO(vegorov): renumber newly discovered congruences during the |
6278 // forwarding to forward chains without running whole pass twice. | 6287 // forwarding to forward chains without running whole pass twice. |
6279 LoadOptimizer load_optimizer(graph, aliased_set, &map); | 6288 LoadOptimizer load_optimizer(graph, aliased_set, &map); |
6280 return load_optimizer.Optimize(); | 6289 return load_optimizer.Optimize(); |
6281 } | 6290 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6339 | 6348 |
6340 // Only forward stores to normal arrays, float64, and simd arrays | 6349 // Only forward stores to normal arrays, float64, and simd arrays |
6341 // to loads because other array stores (intXX/uintXX/float32) | 6350 // to loads because other array stores (intXX/uintXX/float32) |
6342 // may implicitly convert the value stored. | 6351 // may implicitly convert the value stored. |
6343 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); | 6352 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); |
6344 if ((array_store == NULL) || | 6353 if ((array_store == NULL) || |
6345 (array_store->class_id() == kArrayCid) || | 6354 (array_store->class_id() == kArrayCid) || |
6346 (array_store->class_id() == kTypedDataFloat64ArrayCid) || | 6355 (array_store->class_id() == kTypedDataFloat64ArrayCid) || |
6347 (array_store->class_id() == kTypedDataFloat32ArrayCid) || | 6356 (array_store->class_id() == kTypedDataFloat32ArrayCid) || |
6348 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { | 6357 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { |
6349 bool is_load = false; | 6358 bool is_load = false, is_store = false; |
6350 Place store_place(instr, &is_load); | 6359 Place store_place(instr, &is_load, &is_store); |
6351 ASSERT(!is_load); | 6360 ASSERT(!is_load && is_store); |
6352 Place* place = map_->Lookup(&store_place); | 6361 Place* place = map_->Lookup(&store_place); |
6353 if (place != NULL) { | 6362 if (place != NULL) { |
6354 // Store has a corresponding numbered place that might have a | 6363 // Store has a corresponding numbered place that might have a |
6355 // load. Try forwarding stored value to it. | 6364 // load. Try forwarding stored value to it. |
6356 gen->Add(place->id()); | 6365 gen->Add(place->id()); |
6357 if (out_values == NULL) out_values = CreateBlockOutValues(); | 6366 if (out_values == NULL) out_values = CreateBlockOutValues(); |
6358 (*out_values)[place->id()] = GetStoredValue(instr); | 6367 (*out_values)[place->id()] = GetStoredValue(instr); |
6359 } | 6368 } |
6360 } | 6369 } |
6361 | 6370 |
(...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7041 GrowableArray<PhiInstr*> worklist_; | 7050 GrowableArray<PhiInstr*> worklist_; |
7042 BitVector* in_worklist_; | 7051 BitVector* in_worklist_; |
7043 | 7052 |
7044 // True if any load was eliminated. | 7053 // True if any load was eliminated. |
7045 bool forwarded_; | 7054 bool forwarded_; |
7046 | 7055 |
7047 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); | 7056 DISALLOW_COPY_AND_ASSIGN(LoadOptimizer); |
7048 }; | 7057 }; |
7049 | 7058 |
7050 | 7059 |
| 7060 class StoreOptimizer : public LivenessAnalysis { |
| 7061 public: |
| 7062 StoreOptimizer(FlowGraph* graph, |
| 7063 AliasedSet* aliased_set, |
| 7064 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) |
| 7065 : LivenessAnalysis(aliased_set->max_place_id(), graph->postorder()), |
| 7066 graph_(graph), |
| 7067 map_(map), |
| 7068 aliased_set_(aliased_set), |
| 7069 exposed_stores_(graph_->postorder().length()) { |
| 7070 const intptr_t num_blocks = graph_->postorder().length(); |
| 7071 for (intptr_t i = 0; i < num_blocks; i++) { |
| 7072 exposed_stores_.Add(NULL); |
| 7073 } |
| 7074 } |
| 7075 |
| 7076 static void OptimizeGraph(FlowGraph* graph) { |
| 7077 ASSERT(FLAG_load_cse); |
| 7078 if (FLAG_trace_load_optimization) { |
| 7079 FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph); |
| 7080 } |
| 7081 |
| 7082 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
| 7083 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores); |
| 7084 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
| 7085 StoreOptimizer store_optimizer(graph, aliased_set, &map); |
| 7086 store_optimizer.Optimize(); |
| 7087 } |
| 7088 } |
| 7089 |
| 7090 private: |
| 7091 void Optimize() { |
| 7092 Analyze(); |
| 7093 if (FLAG_trace_load_optimization) { |
| 7094 Dump(); |
| 7095 } |
| 7096 EliminateDeadStores(); |
| 7097 if (FLAG_trace_load_optimization) { |
| 7098 FlowGraphPrinter::PrintGraph("After StoreOptimizer", graph_); |
| 7099 } |
| 7100 } |
| 7101 |
| 7102 bool CanEliminateStore(Instruction* instr) { |
| 7103 switch (instr->tag()) { |
| 7104 case Instruction::kStoreInstanceField: |
| 7105 if (instr->AsStoreInstanceField()->is_initialization()) { |
| 7106 // Can't eliminate stores that initialized unboxed fields. |
| 7107 return false; |
| 7108 } |
| 7109 case Instruction::kStoreContext: |
| 7110 case Instruction::kStoreIndexed: |
| 7111 case Instruction::kStoreStaticField: |
| 7112 return true; |
| 7113 default: |
| 7114 UNREACHABLE(); |
| 7115 return false; |
| 7116 } |
| 7117 } |
| 7118 |
| 7119 virtual void ComputeInitialSets() { |
| 7120 BitVector* all_places = new BitVector(aliased_set_->max_place_id()); |
| 7121 all_places->SetAll(); |
| 7122 for (BlockIterator block_it = graph_->postorder_iterator(); |
| 7123 !block_it.Done(); |
| 7124 block_it.Advance()) { |
| 7125 BlockEntryInstr* block = block_it.Current(); |
| 7126 const intptr_t postorder_number = block->postorder_number(); |
| 7127 |
| 7128 BitVector* kill = kill_[postorder_number]; |
| 7129 BitVector* live_in = live_in_[postorder_number]; |
| 7130 BitVector* live_out = live_out_[postorder_number]; |
| 7131 |
| 7132 ZoneGrowableArray<Instruction*>* exposed_stores = NULL; |
| 7133 |
| 7134 // Iterate backwards starting at the last instruction. |
| 7135 for (BackwardInstructionIterator instr_it(block); |
| 7136 !instr_it.Done(); |
| 7137 instr_it.Advance()) { |
| 7138 Instruction* instr = instr_it.Current(); |
| 7139 |
| 7140 bool is_load = false; |
| 7141 bool is_store = false; |
| 7142 Place place(instr, &is_load, &is_store); |
| 7143 if (place.IsFinalField()) { |
| 7144 // Loads/stores of final fields do not participate. |
| 7145 continue; |
| 7146 } |
| 7147 |
| 7148 // Handle stores. |
| 7149 if (is_store) { |
| 7150 if (kill->Contains(instr->place_id())) { |
| 7151 if (!live_in->Contains(instr->place_id()) && |
| 7152 CanEliminateStore(instr)) { |
| 7153 if (FLAG_trace_optimization) { |
| 7154 OS::Print( |
| 7155 "Removing dead store to place %" Pd " in block B%" Pd "\n", |
| 7156 instr->place_id(), block->block_id()); |
| 7157 } |
| 7158 instr_it.RemoveCurrentFromGraph(); |
| 7159 } |
| 7160 } else if (!live_in->Contains(instr->place_id())) { |
| 7161 // Mark this store as down-ward exposed: They are the only |
| 7162 // candidates for the global store elimination. |
| 7163 if (exposed_stores == NULL) { |
| 7164 const intptr_t kMaxExposedStoresInitialSize = 5; |
| 7165 exposed_stores = new ZoneGrowableArray<Instruction*>( |
| 7166 Utils::Minimum(kMaxExposedStoresInitialSize, |
| 7167 aliased_set_->max_place_id())); |
| 7168 } |
| 7169 exposed_stores->Add(instr); |
| 7170 } |
| 7171 // Interfering stores kill only loads from the same place. |
| 7172 kill->Add(instr->place_id()); |
| 7173 live_in->Remove(instr->place_id()); |
| 7174 continue; |
| 7175 } |
| 7176 |
| 7177 // Handle side effects, deoptimization and function return. |
| 7178 if (!instr->Effects().IsNone() || |
| 7179 instr->CanDeoptimize() || |
| 7180 instr->IsThrow() || |
| 7181 instr->IsReThrow() || |
| 7182 instr->IsReturn()) { |
| 7183 // Instructions that return from the function, instructions with side |
| 7184 // effects and instructions that can deoptimize are considered as |
| 7185 // loads from all places. |
| 7186 live_in->CopyFrom(all_places); |
| 7187 if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { |
| 7188 // Initialize live-out for exit blocks since it won't be computed |
| 7189 // otherwise during the fixed point iteration. |
| 7190 live_out->CopyFrom(all_places); |
| 7191 } |
| 7192 continue; |
| 7193 } |
| 7194 |
| 7195 // Handle loads. |
| 7196 Definition* defn = instr->AsDefinition(); |
| 7197 if ((defn != NULL) && IsLoadEliminationCandidate(defn)) { |
| 7198 const Alias alias = aliased_set_->ComputeAlias(&place); |
| 7199 live_in->AddAll(aliased_set_->Get(alias)); |
| 7200 continue; |
| 7201 } |
| 7202 } |
| 7203 exposed_stores_[postorder_number] = exposed_stores; |
| 7204 } |
| 7205 if (FLAG_trace_load_optimization) { |
| 7206 Dump(); |
| 7207 OS::Print("---\n"); |
| 7208 } |
| 7209 } |
| 7210 |
| 7211 void EliminateDeadStores() { |
| 7212 // Iteration order does not matter here. |
| 7213 for (BlockIterator block_it = graph_->postorder_iterator(); |
| 7214 !block_it.Done(); |
| 7215 block_it.Advance()) { |
| 7216 BlockEntryInstr* block = block_it.Current(); |
| 7217 const intptr_t postorder_number = block->postorder_number(); |
| 7218 |
| 7219 BitVector* live_out = live_out_[postorder_number]; |
| 7220 |
| 7221 ZoneGrowableArray<Instruction*>* exposed_stores = |
| 7222 exposed_stores_[postorder_number]; |
| 7223 if (exposed_stores == NULL) continue; // No exposed stores. |
| 7224 |
| 7225 // Iterate over candidate stores. |
| 7226 for (intptr_t i = 0; i < exposed_stores->length(); ++i) { |
| 7227 Instruction* instr = (*exposed_stores)[i]; |
| 7228 bool is_load = false; |
| 7229 bool is_store = false; |
| 7230 Place place(instr, &is_load, &is_store); |
| 7231 ASSERT(!is_load && is_store); |
| 7232 if (place.IsFinalField()) { |
| 7233 // Final field do not participate in dead store elimination. |
| 7234 continue; |
| 7235 } |
| 7236 // Eliminate a downward exposed store if the corresponding place is not |
| 7237 // in live-out. |
| 7238 if (!live_out->Contains(instr->place_id()) && |
| 7239 CanEliminateStore(instr)) { |
| 7240 if (FLAG_trace_optimization) { |
| 7241 OS::Print("Removing dead store to place %"Pd" in block B%"Pd"\n", |
| 7242 instr->place_id(), block->block_id()); |
| 7243 } |
| 7244 instr->RemoveFromGraph(/* ignored */ false); |
| 7245 } |
| 7246 } |
| 7247 } |
| 7248 } |
| 7249 |
| 7250 FlowGraph* graph_; |
| 7251 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_; |
| 7252 |
| 7253 // Mapping between field offsets in words and expression ids of loads from |
| 7254 // that offset. |
| 7255 AliasedSet* aliased_set_; |
| 7256 |
| 7257 // Per block list of downward exposed stores. |
| 7258 GrowableArray<ZoneGrowableArray<Instruction*>*> exposed_stores_; |
| 7259 |
| 7260 DISALLOW_COPY_AND_ASSIGN(StoreOptimizer); |
| 7261 }; |
| 7262 |
| 7263 |
| 7264 void DeadStoreElimination::Optimize(FlowGraph* graph) { |
| 7265 if (FLAG_dead_store_elimination) { |
| 7266 StoreOptimizer::OptimizeGraph(graph); |
| 7267 } |
| 7268 } |
| 7269 |
| 7270 |
7051 class CSEInstructionMap : public ValueObject { | 7271 class CSEInstructionMap : public ValueObject { |
7052 public: | 7272 public: |
7053 // Right now CSE and LICM track a single effect: possible externalization of | 7273 // Right now CSE and LICM track a single effect: possible externalization of |
7054 // strings. | 7274 // strings. |
7055 // Other effects like modifications of fields are tracked in a separate load | 7275 // Other effects like modifications of fields are tracked in a separate load |
7056 // forwarding pass via Alias structure. | 7276 // forwarding pass via Alias structure. |
7057 COMPILE_ASSERT(EffectSet::kLastEffect == 1, single_effect_is_tracked); | 7277 COMPILE_ASSERT(EffectSet::kLastEffect == 1, single_effect_is_tracked); |
7058 | 7278 |
7059 CSEInstructionMap() : independent_(), dependent_() { } | 7279 CSEInstructionMap() : independent_(), dependent_() { } |
7060 explicit CSEInstructionMap(const CSEInstructionMap& other) | 7280 explicit CSEInstructionMap(const CSEInstructionMap& other) |
(...skipping 2237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9298 } | 9518 } |
9299 | 9519 |
9300 // Insert materializations at environment uses. | 9520 // Insert materializations at environment uses. |
9301 for (intptr_t i = 0; i < exits.length(); i++) { | 9521 for (intptr_t i = 0; i < exits.length(); i++) { |
9302 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); | 9522 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); |
9303 } | 9523 } |
9304 } | 9524 } |
9305 | 9525 |
9306 | 9526 |
9307 } // namespace dart | 9527 } // namespace dart |
OLD | NEW |