Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 143263010: Implement simple dead store elimination. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698