| 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 |