| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/redundancy_elimination.h" | 5 #include "vm/redundancy_elimination.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph.h" | 8 #include "vm/flow_graph.h" |
| 9 #include "vm/hash_map.h" | 9 #include "vm/hash_map.h" |
| 10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
| 11 #include "vm/intermediate_language.h" | 11 #include "vm/intermediate_language.h" |
| 12 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 | 16 |
| 17 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); | 17 DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores"); |
| 18 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 18 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 19 DEFINE_FLAG(bool, trace_load_optimization, false, | 19 DEFINE_FLAG(bool, |
| 20 "Print live sets for load optimization pass."); | 20 trace_load_optimization, |
| 21 false, |
| 22 "Print live sets for load optimization pass."); |
| 21 | 23 |
| 22 // Quick access to the current zone. | 24 // Quick access to the current zone. |
| 23 #define Z (zone()) | 25 #define Z (zone()) |
| 24 | 26 |
| 25 | 27 |
| 26 class CSEInstructionMap : public ValueObject { | 28 class CSEInstructionMap : public ValueObject { |
| 27 public: | 29 public: |
| 28 // Right now CSE and LICM track a single effect: possible externalization of | 30 // Right now CSE and LICM track a single effect: possible externalization of |
| 29 // strings. | 31 // strings. |
| 30 // Other effects like modifications of fields are tracked in a separate load | 32 // Other effects like modifications of fields are tracked in a separate load |
| 31 // forwarding pass via Alias structure. | 33 // forwarding pass via Alias structure. |
| 32 COMPILE_ASSERT(EffectSet::kLastEffect == 1); | 34 COMPILE_ASSERT(EffectSet::kLastEffect == 1); |
| 33 | 35 |
| 34 CSEInstructionMap() : independent_(), dependent_() { } | 36 CSEInstructionMap() : independent_(), dependent_() {} |
| 35 explicit CSEInstructionMap(const CSEInstructionMap& other) | 37 explicit CSEInstructionMap(const CSEInstructionMap& other) |
| 36 : ValueObject(), | 38 : ValueObject(), |
| 37 independent_(other.independent_), | 39 independent_(other.independent_), |
| 38 dependent_(other.dependent_) { | 40 dependent_(other.dependent_) {} |
| 39 } | |
| 40 | 41 |
| 41 void RemoveAffected(EffectSet effects) { | 42 void RemoveAffected(EffectSet effects) { |
| 42 if (!effects.IsNone()) { | 43 if (!effects.IsNone()) { |
| 43 dependent_.Clear(); | 44 dependent_.Clear(); |
| 44 } | 45 } |
| 45 } | 46 } |
| 46 | 47 |
| 47 Instruction* Lookup(Instruction* other) const { | 48 Instruction* Lookup(Instruction* other) const { |
| 48 return GetMapFor(other)->LookupValue(other); | 49 return GetMapFor(other)->LookupValue(other); |
| 49 } | 50 } |
| 50 | 51 |
| 51 void Insert(Instruction* instr) { | 52 void Insert(Instruction* instr) { return GetMapFor(instr)->Insert(instr); } |
| 52 return GetMapFor(instr)->Insert(instr); | |
| 53 } | |
| 54 | 53 |
| 55 private: | 54 private: |
| 56 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; | 55 typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> > Map; |
| 57 | 56 |
| 58 Map* GetMapFor(Instruction* instr) { | 57 Map* GetMapFor(Instruction* instr) { |
| 59 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | 58 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
| 60 } | 59 } |
| 61 | 60 |
| 62 const Map* GetMapFor(Instruction* instr) const { | 61 const Map* GetMapFor(Instruction* instr) const { |
| 63 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; | 62 return instr->Dependencies().IsNone() ? &independent_ : &dependent_; |
| 64 } | 63 } |
| 65 | 64 |
| 66 // All computations that are not affected by any side-effect. | 65 // All computations that are not affected by any side-effect. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 kInt128, | 170 kInt128, |
| 172 | 171 |
| 173 kLargestElementSize = kInt128, | 172 kLargestElementSize = kInt128, |
| 174 }; | 173 }; |
| 175 | 174 |
| 176 Place(const Place& other) | 175 Place(const Place& other) |
| 177 : ValueObject(), | 176 : ValueObject(), |
| 178 flags_(other.flags_), | 177 flags_(other.flags_), |
| 179 instance_(other.instance_), | 178 instance_(other.instance_), |
| 180 raw_selector_(other.raw_selector_), | 179 raw_selector_(other.raw_selector_), |
| 181 id_(other.id_) { | 180 id_(other.id_) {} |
| 182 } | |
| 183 | 181 |
| 184 // Construct a place from instruction if instruction accesses any place. | 182 // Construct a place from instruction if instruction accesses any place. |
| 185 // Otherwise constructs kNone place. | 183 // Otherwise constructs kNone place. |
| 186 Place(Instruction* instr, bool* is_load, bool* is_store) | 184 Place(Instruction* instr, bool* is_load, bool* is_store) |
| 187 : flags_(0), | 185 : flags_(0), instance_(NULL), raw_selector_(0), id_(0) { |
| 188 instance_(NULL), | |
| 189 raw_selector_(0), | |
| 190 id_(0) { | |
| 191 switch (instr->tag()) { | 186 switch (instr->tag()) { |
| 192 case Instruction::kLoadField: { | 187 case Instruction::kLoadField: { |
| 193 LoadFieldInstr* load_field = instr->AsLoadField(); | 188 LoadFieldInstr* load_field = instr->AsLoadField(); |
| 194 set_representation(load_field->representation()); | 189 set_representation(load_field->representation()); |
| 195 instance_ = load_field->instance()->definition()->OriginalDefinition(); | 190 instance_ = load_field->instance()->definition()->OriginalDefinition(); |
| 196 if (load_field->field() != NULL) { | 191 if (load_field->field() != NULL) { |
| 197 set_kind(kField); | 192 set_kind(kField); |
| 198 field_ = load_field->field(); | 193 field_ = load_field->field(); |
| 199 } else { | 194 } else { |
| 200 set_kind(kVMField); | 195 set_kind(kVMField); |
| 201 offset_in_bytes_ = load_field->offset_in_bytes(); | 196 offset_in_bytes_ = load_field->offset_in_bytes(); |
| 202 } | 197 } |
| 203 *is_load = true; | 198 *is_load = true; |
| 204 break; | 199 break; |
| 205 } | 200 } |
| 206 | 201 |
| 207 case Instruction::kStoreInstanceField: { | 202 case Instruction::kStoreInstanceField: { |
| 208 StoreInstanceFieldInstr* store = | 203 StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); |
| 209 instr->AsStoreInstanceField(); | |
| 210 set_representation(store->RequiredInputRepresentation( | 204 set_representation(store->RequiredInputRepresentation( |
| 211 StoreInstanceFieldInstr::kValuePos)); | 205 StoreInstanceFieldInstr::kValuePos)); |
| 212 instance_ = store->instance()->definition()->OriginalDefinition(); | 206 instance_ = store->instance()->definition()->OriginalDefinition(); |
| 213 if (!store->field().IsNull()) { | 207 if (!store->field().IsNull()) { |
| 214 set_kind(kField); | 208 set_kind(kField); |
| 215 field_ = &store->field(); | 209 field_ = &store->field(); |
| 216 } else { | 210 } else { |
| 217 set_kind(kVMField); | 211 set_kind(kVMField); |
| 218 offset_in_bytes_ = store->offset_in_bytes(); | 212 offset_in_bytes_ = store->offset_in_bytes(); |
| 219 } | 213 } |
| 220 *is_store = true; | 214 *is_store = true; |
| 221 break; | 215 break; |
| 222 } | 216 } |
| 223 | 217 |
| 224 case Instruction::kLoadStaticField: | 218 case Instruction::kLoadStaticField: |
| 225 set_kind(kField); | 219 set_kind(kField); |
| 226 set_representation(instr->AsLoadStaticField()->representation()); | 220 set_representation(instr->AsLoadStaticField()->representation()); |
| 227 field_ = &instr->AsLoadStaticField()->StaticField(); | 221 field_ = &instr->AsLoadStaticField()->StaticField(); |
| 228 *is_load = true; | 222 *is_load = true; |
| 229 break; | 223 break; |
| 230 | 224 |
| 231 case Instruction::kStoreStaticField: | 225 case Instruction::kStoreStaticField: |
| 232 set_kind(kField); | 226 set_kind(kField); |
| 233 set_representation(instr->AsStoreStaticField()-> | 227 set_representation( |
| 234 RequiredInputRepresentation(StoreStaticFieldInstr::kValuePos)); | 228 instr->AsStoreStaticField()->RequiredInputRepresentation( |
| 229 StoreStaticFieldInstr::kValuePos)); |
| 235 field_ = &instr->AsStoreStaticField()->field(); | 230 field_ = &instr->AsStoreStaticField()->field(); |
| 236 *is_store = true; | 231 *is_store = true; |
| 237 break; | 232 break; |
| 238 | 233 |
| 239 case Instruction::kLoadIndexed: { | 234 case Instruction::kLoadIndexed: { |
| 240 LoadIndexedInstr* load_indexed = instr->AsLoadIndexed(); | 235 LoadIndexedInstr* load_indexed = instr->AsLoadIndexed(); |
| 241 set_representation(load_indexed->representation()); | 236 set_representation(load_indexed->representation()); |
| 242 instance_ = load_indexed->array()->definition()->OriginalDefinition(); | 237 instance_ = load_indexed->array()->definition()->OriginalDefinition(); |
| 243 SetIndex(load_indexed->index()->definition(), | 238 SetIndex(load_indexed->index()->definition(), |
| 244 load_indexed->index_scale(), | 239 load_indexed->index_scale(), load_indexed->class_id()); |
| 245 load_indexed->class_id()); | |
| 246 *is_load = true; | 240 *is_load = true; |
| 247 break; | 241 break; |
| 248 } | 242 } |
| 249 | 243 |
| 250 case Instruction::kStoreIndexed: { | 244 case Instruction::kStoreIndexed: { |
| 251 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed(); | 245 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed(); |
| 252 set_representation(store_indexed-> | 246 set_representation(store_indexed->RequiredInputRepresentation( |
| 253 RequiredInputRepresentation(StoreIndexedInstr::kValuePos)); | 247 StoreIndexedInstr::kValuePos)); |
| 254 instance_ = store_indexed->array()->definition()->OriginalDefinition(); | 248 instance_ = store_indexed->array()->definition()->OriginalDefinition(); |
| 255 SetIndex(store_indexed->index()->definition(), | 249 SetIndex(store_indexed->index()->definition(), |
| 256 store_indexed->index_scale(), | 250 store_indexed->index_scale(), store_indexed->class_id()); |
| 257 store_indexed->class_id()); | |
| 258 *is_store = true; | 251 *is_store = true; |
| 259 break; | 252 break; |
| 260 } | 253 } |
| 261 | 254 |
| 262 default: | 255 default: |
| 263 break; | 256 break; |
| 264 } | 257 } |
| 265 } | 258 } |
| 266 | 259 |
| 267 // Create object representing *[*] alias. | 260 // Create object representing *[*] alias. |
| 268 static Place* CreateAnyInstanceAnyIndexAlias(Zone* zone, | 261 static Place* CreateAnyInstanceAnyIndexAlias(Zone* zone, intptr_t id) { |
| 269 intptr_t id) { | 262 return Wrap( |
| 270 return Wrap(zone, Place( | 263 zone, Place(EncodeFlags(kIndexed, kNoRepresentation, kNoSize), NULL, 0), |
| 271 EncodeFlags(kIndexed, kNoRepresentation, kNoSize), | 264 id); |
| 272 NULL, | |
| 273 0), id); | |
| 274 } | 265 } |
| 275 | 266 |
| 276 // Return least generic alias for this place. Given that aliases are | 267 // Return least generic alias for this place. Given that aliases are |
| 277 // essentially sets of places we define least generic alias as a smallest | 268 // essentially sets of places we define least generic alias as a smallest |
| 278 // alias that contains this place. | 269 // alias that contains this place. |
| 279 // | 270 // |
| 280 // We obtain such alias by a simple transformation: | 271 // We obtain such alias by a simple transformation: |
| 281 // | 272 // |
| 282 // - for places that depend on an instance X.f, X.@offs, X[i], X[C] | 273 // - for places that depend on an instance X.f, X.@offs, X[i], X[C] |
| 283 // we drop X if X is not an allocation because in this case X does not | 274 // we drop X if X is not an allocation because in this case X does not |
| (...skipping 30 matching lines...) Expand all Loading... |
| 314 // Given instance dependent alias X.f, X.@offs, X[C], X[*] return | 305 // Given instance dependent alias X.f, X.@offs, X[C], X[*] return |
| 315 // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively. | 306 // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively. |
| 316 Place CopyWithoutInstance() const { | 307 Place CopyWithoutInstance() const { |
| 317 ASSERT(DependsOnInstance()); | 308 ASSERT(DependsOnInstance()); |
| 318 return Place(flags_, NULL, raw_selector_); | 309 return Place(flags_, NULL, raw_selector_); |
| 319 } | 310 } |
| 320 | 311 |
| 321 // Given alias X[C] or *[C] return X[*] and *[*] respectively. | 312 // Given alias X[C] or *[C] return X[*] and *[*] respectively. |
| 322 Place CopyWithoutIndex() const { | 313 Place CopyWithoutIndex() const { |
| 323 ASSERT(kind() == kConstantIndexed); | 314 ASSERT(kind() == kConstantIndexed); |
| 324 return Place(EncodeFlags(kIndexed, kNoRepresentation, kNoSize), | 315 return Place(EncodeFlags(kIndexed, kNoRepresentation, kNoSize), instance_, |
| 325 instance_, | |
| 326 0); | 316 0); |
| 327 } | 317 } |
| 328 | 318 |
| 329 // Given alias X[ByteOffs|S] and a larger element size S', return | 319 // Given alias X[ByteOffs|S] and a larger element size S', return |
| 330 // alias X[RoundDown(ByteOffs, S')|S'] - this is the byte offset of a larger | 320 // alias X[RoundDown(ByteOffs, S')|S'] - this is the byte offset of a larger |
| 331 // typed array element that contains this typed array element. | 321 // typed array element that contains this typed array element. |
| 332 // In other words this method computes the only possible place with the given | 322 // In other words this method computes the only possible place with the given |
| 333 // size that can alias this place (due to alignment restrictions). | 323 // size that can alias this place (due to alignment restrictions). |
| 334 // For example for X[9|kInt8] and target size kInt32 we would return | 324 // For example for X[9|kInt8] and target size kInt32 we would return |
| 335 // X[8|kInt32]. | 325 // X[8|kInt32]. |
| 336 Place ToLargerElement(ElementSize to) const { | 326 Place ToLargerElement(ElementSize to) const { |
| 337 ASSERT(kind() == kConstantIndexed); | 327 ASSERT(kind() == kConstantIndexed); |
| 338 ASSERT(element_size() != kNoSize); | 328 ASSERT(element_size() != kNoSize); |
| 339 ASSERT(element_size() < to); | 329 ASSERT(element_size() < to); |
| 340 return Place(ElementSizeBits::update(to, flags_), | 330 return Place(ElementSizeBits::update(to, flags_), instance_, |
| 341 instance_, | |
| 342 RoundByteOffset(to, index_constant_)); | 331 RoundByteOffset(to, index_constant_)); |
| 343 } | 332 } |
| 344 | 333 |
| 345 | 334 |
| 346 intptr_t id() const { return id_; } | 335 intptr_t id() const { return id_; } |
| 347 | 336 |
| 348 Kind kind() const { return KindBits::decode(flags_); } | 337 Kind kind() const { return KindBits::decode(flags_); } |
| 349 | 338 |
| 350 Representation representation() const { | 339 Representation representation() const { |
| 351 return RepresentationBits::decode(flags_); | 340 return RepresentationBits::decode(flags_); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 369 intptr_t offset_in_bytes() const { | 358 intptr_t offset_in_bytes() const { |
| 370 ASSERT(kind() == kVMField); | 359 ASSERT(kind() == kVMField); |
| 371 return offset_in_bytes_; | 360 return offset_in_bytes_; |
| 372 } | 361 } |
| 373 | 362 |
| 374 Definition* index() const { | 363 Definition* index() const { |
| 375 ASSERT(kind() == kIndexed); | 364 ASSERT(kind() == kIndexed); |
| 376 return index_; | 365 return index_; |
| 377 } | 366 } |
| 378 | 367 |
| 379 ElementSize element_size() const { | 368 ElementSize element_size() const { return ElementSizeBits::decode(flags_); } |
| 380 return ElementSizeBits::decode(flags_); | |
| 381 } | |
| 382 | 369 |
| 383 intptr_t index_constant() const { | 370 intptr_t index_constant() const { |
| 384 ASSERT(kind() == kConstantIndexed); | 371 ASSERT(kind() == kConstantIndexed); |
| 385 return index_constant_; | 372 return index_constant_; |
| 386 } | 373 } |
| 387 | 374 |
| 388 static const char* DefinitionName(Definition* def) { | 375 static const char* DefinitionName(Definition* def) { |
| 389 if (def == NULL) { | 376 if (def == NULL) { |
| 390 return "*"; | 377 return "*"; |
| 391 } else { | 378 } else { |
| 392 return Thread::Current()->zone()->PrintToString( | 379 return Thread::Current()->zone()->PrintToString("v%" Pd, |
| 393 "v%" Pd, def->ssa_temp_index()); | 380 def->ssa_temp_index()); |
| 394 } | 381 } |
| 395 } | 382 } |
| 396 | 383 |
| 397 const char* ToCString() const { | 384 const char* ToCString() const { |
| 398 switch (kind()) { | 385 switch (kind()) { |
| 399 case kNone: | 386 case kNone: |
| 400 return "<none>"; | 387 return "<none>"; |
| 401 | 388 |
| 402 case kField: { | 389 case kField: { |
| 403 const char* field_name = String::Handle(field().name()).ToCString(); | 390 const char* field_name = String::Handle(field().name()).ToCString(); |
| 404 if (field().is_static()) { | 391 if (field().is_static()) { |
| 405 return Thread::Current()->zone()->PrintToString( | 392 return Thread::Current()->zone()->PrintToString("<%s>", field_name); |
| 406 "<%s>", field_name); | |
| 407 } else { | 393 } else { |
| 408 return Thread::Current()->zone()->PrintToString( | 394 return Thread::Current()->zone()->PrintToString( |
| 409 "<%s.%s>", DefinitionName(instance()), field_name); | 395 "<%s.%s>", DefinitionName(instance()), field_name); |
| 410 } | 396 } |
| 411 } | 397 } |
| 412 | 398 |
| 413 case kVMField: | 399 case kVMField: |
| 414 return Thread::Current()->zone()->PrintToString( | 400 return Thread::Current()->zone()->PrintToString( |
| 415 "<%s.@%" Pd ">", | 401 "<%s.@%" Pd ">", DefinitionName(instance()), offset_in_bytes()); |
| 416 DefinitionName(instance()), | |
| 417 offset_in_bytes()); | |
| 418 | 402 |
| 419 case kIndexed: | 403 case kIndexed: |
| 420 return Thread::Current()->zone()->PrintToString( | 404 return Thread::Current()->zone()->PrintToString( |
| 421 "<%s[%s]>", | 405 "<%s[%s]>", DefinitionName(instance()), DefinitionName(index())); |
| 422 DefinitionName(instance()), | |
| 423 DefinitionName(index())); | |
| 424 | 406 |
| 425 case kConstantIndexed: | 407 case kConstantIndexed: |
| 426 if (element_size() == kNoSize) { | 408 if (element_size() == kNoSize) { |
| 427 return Thread::Current()->zone()->PrintToString( | 409 return Thread::Current()->zone()->PrintToString( |
| 428 "<%s[%" Pd "]>", | 410 "<%s[%" Pd "]>", DefinitionName(instance()), index_constant()); |
| 429 DefinitionName(instance()), | |
| 430 index_constant()); | |
| 431 } else { | 411 } else { |
| 432 return Thread::Current()->zone()->PrintToString( | 412 return Thread::Current()->zone()->PrintToString( |
| 433 "<%s[%" Pd "|%" Pd "]>", | 413 "<%s[%" Pd "|%" Pd "]>", DefinitionName(instance()), |
| 434 DefinitionName(instance()), | 414 index_constant(), ElementSizeMultiplier(element_size())); |
| 435 index_constant(), | |
| 436 ElementSizeMultiplier(element_size())); | |
| 437 } | 415 } |
| 438 } | 416 } |
| 439 UNREACHABLE(); | 417 UNREACHABLE(); |
| 440 return "<?>"; | 418 return "<?>"; |
| 441 } | 419 } |
| 442 | 420 |
| 443 // Fields that are considered immutable by load optimization. | 421 // Fields that are considered immutable by load optimization. |
| 444 // Handle static finals as non-final with precompilation because | 422 // Handle static finals as non-final with precompilation because |
| 445 // they may be reset to uninitialized after compilation. | 423 // they may be reset to uninitialized after compilation. |
| 446 bool IsImmutableField() const { | 424 bool IsImmutableField() const { |
| 447 return (kind() == kField) | 425 return (kind() == kField) && field().is_final() && |
| 448 && field().is_final() | 426 (!field().is_static() || !FLAG_fields_may_be_reset); |
| 449 && (!field().is_static() || !FLAG_fields_may_be_reset); | |
| 450 } | 427 } |
| 451 | 428 |
| 452 intptr_t Hashcode() const { | 429 intptr_t Hashcode() const { |
| 453 return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 + | 430 return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 + |
| 454 FieldHashcode(); | 431 FieldHashcode(); |
| 455 } | 432 } |
| 456 | 433 |
| 457 bool Equals(const Place* other) const { | 434 bool Equals(const Place* other) const { |
| 458 return (flags_ == other->flags_) && | 435 return (flags_ == other->flags_) && (instance_ == other->instance_) && |
| 459 (instance_ == other->instance_) && | 436 SameField(other); |
| 460 SameField(other); | |
| 461 } | 437 } |
| 462 | 438 |
| 463 // Create a zone allocated copy of this place and assign given id to it. | 439 // Create a zone allocated copy of this place and assign given id to it. |
| 464 static Place* Wrap(Zone* zone, const Place& place, intptr_t id); | 440 static Place* Wrap(Zone* zone, const Place& place, intptr_t id); |
| 465 | 441 |
| 466 static bool IsAllocation(Definition* defn) { | 442 static bool IsAllocation(Definition* defn) { |
| 467 return (defn != NULL) && | 443 return (defn != NULL) && |
| 468 (defn->IsAllocateObject() || | 444 (defn->IsAllocateObject() || defn->IsCreateArray() || |
| 469 defn->IsCreateArray() || | 445 defn->IsAllocateUninitializedContext() || |
| 470 defn->IsAllocateUninitializedContext() || | 446 (defn->IsStaticCall() && |
| 471 (defn->IsStaticCall() && | 447 defn->AsStaticCall()->IsRecognizedFactory())); |
| 472 defn->AsStaticCall()->IsRecognizedFactory())); | |
| 473 } | 448 } |
| 474 | 449 |
| 475 private: | 450 private: |
| 476 Place(uword flags, Definition* instance, intptr_t selector) | 451 Place(uword flags, Definition* instance, intptr_t selector) |
| 477 : flags_(flags), | 452 : flags_(flags), instance_(instance), raw_selector_(selector), id_(0) {} |
| 478 instance_(instance), | |
| 479 raw_selector_(selector), | |
| 480 id_(0) { | |
| 481 } | |
| 482 | 453 |
| 483 bool SameField(const Place* other) const { | 454 bool SameField(const Place* other) const { |
| 484 return (kind() == kField) ? | 455 return (kind() == kField) |
| 485 (field().Original() == other->field().Original()) : | 456 ? (field().Original() == other->field().Original()) |
| 486 (offset_in_bytes_ == other->offset_in_bytes_); | 457 : (offset_in_bytes_ == other->offset_in_bytes_); |
| 487 } | 458 } |
| 488 | 459 |
| 489 intptr_t FieldHashcode() const { | 460 intptr_t FieldHashcode() const { |
| 490 return (kind() == kField) ? reinterpret_cast<intptr_t>(field().Original()) | 461 return (kind() == kField) ? reinterpret_cast<intptr_t>(field().Original()) |
| 491 : offset_in_bytes_; | 462 : offset_in_bytes_; |
| 492 } | 463 } |
| 493 | 464 |
| 494 void set_representation(Representation rep) { | 465 void set_representation(Representation rep) { |
| 495 flags_ = RepresentationBits::update(rep, flags_); | 466 flags_ = RepresentationBits::update(rep, flags_); |
| 496 } | 467 } |
| 497 | 468 |
| 498 void set_kind(Kind kind) { | 469 void set_kind(Kind kind) { flags_ = KindBits::update(kind, flags_); } |
| 499 flags_ = KindBits::update(kind, flags_); | |
| 500 } | |
| 501 | 470 |
| 502 void set_element_size(ElementSize scale) { | 471 void set_element_size(ElementSize scale) { |
| 503 flags_ = ElementSizeBits::update(scale, flags_); | 472 flags_ = ElementSizeBits::update(scale, flags_); |
| 504 } | 473 } |
| 505 | 474 |
| 506 void SetIndex(Definition* index, intptr_t scale, intptr_t class_id) { | 475 void SetIndex(Definition* index, intptr_t scale, intptr_t class_id) { |
| 507 ConstantInstr* index_constant = index->AsConstant(); | 476 ConstantInstr* index_constant = index->AsConstant(); |
| 508 if ((index_constant != NULL) && index_constant->value().IsSmi()) { | 477 if ((index_constant != NULL) && index_constant->value().IsSmi()) { |
| 509 const intptr_t index_value = Smi::Cast(index_constant->value()).Value(); | 478 const intptr_t index_value = Smi::Cast(index_constant->value()).Value(); |
| 510 const ElementSize size = ElementSizeFor(class_id); | 479 const ElementSize size = ElementSizeFor(class_id); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 532 | 501 |
| 533 // Fallthrough: create generic _[*] place. | 502 // Fallthrough: create generic _[*] place. |
| 534 } | 503 } |
| 535 | 504 |
| 536 set_kind(kIndexed); | 505 set_kind(kIndexed); |
| 537 index_ = index; | 506 index_ = index; |
| 538 } | 507 } |
| 539 | 508 |
| 540 static uword EncodeFlags(Kind kind, Representation rep, ElementSize scale) { | 509 static uword EncodeFlags(Kind kind, Representation rep, ElementSize scale) { |
| 541 ASSERT((kind == kConstantIndexed) || (scale == kNoSize)); | 510 ASSERT((kind == kConstantIndexed) || (scale == kNoSize)); |
| 542 return KindBits::encode(kind) | | 511 return KindBits::encode(kind) | RepresentationBits::encode(rep) | |
| 543 RepresentationBits::encode(rep) | | 512 ElementSizeBits::encode(scale); |
| 544 ElementSizeBits::encode(scale); | |
| 545 } | 513 } |
| 546 | 514 |
| 547 static ElementSize ElementSizeFor(intptr_t class_id) { | 515 static ElementSize ElementSizeFor(intptr_t class_id) { |
| 548 switch (class_id) { | 516 switch (class_id) { |
| 549 case kArrayCid: | 517 case kArrayCid: |
| 550 case kImmutableArrayCid: | 518 case kImmutableArrayCid: |
| 551 case kOneByteStringCid: | 519 case kOneByteStringCid: |
| 552 case kTwoByteStringCid: | 520 case kTwoByteStringCid: |
| 553 case kExternalOneByteStringCid: | 521 case kExternalOneByteStringCid: |
| 554 case kExternalTwoByteStringCid: | 522 case kExternalTwoByteStringCid: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 | 558 |
| 591 static intptr_t ElementSizeMultiplier(ElementSize size) { | 559 static intptr_t ElementSizeMultiplier(ElementSize size) { |
| 592 return 1 << (static_cast<intptr_t>(size) - static_cast<intptr_t>(kInt8)); | 560 return 1 << (static_cast<intptr_t>(size) - static_cast<intptr_t>(kInt8)); |
| 593 } | 561 } |
| 594 | 562 |
| 595 static intptr_t RoundByteOffset(ElementSize size, intptr_t offset) { | 563 static intptr_t RoundByteOffset(ElementSize size, intptr_t offset) { |
| 596 return offset & ~(ElementSizeMultiplier(size) - 1); | 564 return offset & ~(ElementSizeMultiplier(size) - 1); |
| 597 } | 565 } |
| 598 | 566 |
| 599 class KindBits : public BitField<uword, Kind, 0, 3> {}; | 567 class KindBits : public BitField<uword, Kind, 0, 3> {}; |
| 600 class RepresentationBits : | 568 class RepresentationBits |
| 601 public BitField<uword, Representation, KindBits::kNextBit, 11> {}; | 569 : public BitField<uword, Representation, KindBits::kNextBit, 11> {}; |
| 602 class ElementSizeBits : | 570 class ElementSizeBits |
| 603 public BitField<uword, ElementSize, RepresentationBits::kNextBit, 3> {}; | 571 : public BitField<uword, ElementSize, RepresentationBits::kNextBit, 3> {}; |
| 604 | 572 |
| 605 uword flags_; | 573 uword flags_; |
| 606 Definition* instance_; | 574 Definition* instance_; |
| 607 union { | 575 union { |
| 608 intptr_t raw_selector_; | 576 intptr_t raw_selector_; |
| 609 const Field* field_; | 577 const Field* field_; |
| 610 intptr_t offset_in_bytes_; | 578 intptr_t offset_in_bytes_; |
| 611 intptr_t index_constant_; | 579 intptr_t index_constant_; |
| 612 Definition* index_; | 580 Definition* index_; |
| 613 }; | 581 }; |
| 614 | 582 |
| 615 intptr_t id_; | 583 intptr_t id_; |
| 616 }; | 584 }; |
| 617 | 585 |
| 618 | 586 |
| 619 class ZonePlace : public ZoneAllocated { | 587 class ZonePlace : public ZoneAllocated { |
| 620 public: | 588 public: |
| 621 explicit ZonePlace(const Place& place) : place_(place) { } | 589 explicit ZonePlace(const Place& place) : place_(place) {} |
| 622 | 590 |
| 623 Place* place() { return &place_; } | 591 Place* place() { return &place_; } |
| 624 | 592 |
| 625 private: | 593 private: |
| 626 Place place_; | 594 Place place_; |
| 627 }; | 595 }; |
| 628 | 596 |
| 629 | 597 |
| 630 Place* Place::Wrap(Zone* zone, const Place& place, intptr_t id) { | 598 Place* Place::Wrap(Zone* zone, const Place& place, intptr_t id) { |
| 631 Place* wrapped = (new(zone) ZonePlace(place))->place(); | 599 Place* wrapped = (new (zone) ZonePlace(place))->place(); |
| 632 wrapped->id_ = id; | 600 wrapped->id_ = id; |
| 633 return wrapped; | 601 return wrapped; |
| 634 } | 602 } |
| 635 | 603 |
| 636 | 604 |
| 637 // Correspondence between places connected through outgoing phi moves on the | 605 // Correspondence between places connected through outgoing phi moves on the |
| 638 // edge that targets join. | 606 // edge that targets join. |
| 639 class PhiPlaceMoves : public ZoneAllocated { | 607 class PhiPlaceMoves : public ZoneAllocated { |
| 640 public: | 608 public: |
| 641 // Record a move from the place with id |from| to the place with id |to| at | 609 // Record a move from the place with id |from| to the place with id |to| at |
| 642 // the given block. | 610 // the given block. |
| 643 void CreateOutgoingMove(Zone* zone, | 611 void CreateOutgoingMove(Zone* zone, |
| 644 BlockEntryInstr* block, intptr_t from, intptr_t to) { | 612 BlockEntryInstr* block, |
| 613 intptr_t from, |
| 614 intptr_t to) { |
| 645 const intptr_t block_num = block->preorder_number(); | 615 const intptr_t block_num = block->preorder_number(); |
| 646 while (moves_.length() <= block_num) { | 616 while (moves_.length() <= block_num) { |
| 647 moves_.Add(NULL); | 617 moves_.Add(NULL); |
| 648 } | 618 } |
| 649 | 619 |
| 650 if (moves_[block_num] == NULL) { | 620 if (moves_[block_num] == NULL) { |
| 651 moves_[block_num] = new(zone) ZoneGrowableArray<Move>(5); | 621 moves_[block_num] = new (zone) ZoneGrowableArray<Move>(5); |
| 652 } | 622 } |
| 653 | 623 |
| 654 moves_[block_num]->Add(Move(from, to)); | 624 moves_[block_num]->Add(Move(from, to)); |
| 655 } | 625 } |
| 656 | 626 |
| 657 class Move { | 627 class Move { |
| 658 public: | 628 public: |
| 659 Move(intptr_t from, intptr_t to) : from_(from), to_(to) { } | 629 Move(intptr_t from, intptr_t to) : from_(from), to_(to) {} |
| 660 | 630 |
| 661 intptr_t from() const { return from_; } | 631 intptr_t from() const { return from_; } |
| 662 intptr_t to() const { return to_; } | 632 intptr_t to() const { return to_; } |
| 663 | 633 |
| 664 private: | 634 private: |
| 665 intptr_t from_; | 635 intptr_t from_; |
| 666 intptr_t to_; | 636 intptr_t to_; |
| 667 }; | 637 }; |
| 668 | 638 |
| 669 typedef const ZoneGrowableArray<Move>* MovesList; | 639 typedef const ZoneGrowableArray<Move>* MovesList; |
| 670 | 640 |
| 671 MovesList GetOutgoingMoves(BlockEntryInstr* block) const { | 641 MovesList GetOutgoingMoves(BlockEntryInstr* block) const { |
| 672 const intptr_t block_num = block->preorder_number(); | 642 const intptr_t block_num = block->preorder_number(); |
| 673 return (block_num < moves_.length()) ? | 643 return (block_num < moves_.length()) ? moves_[block_num] : NULL; |
| 674 moves_[block_num] : NULL; | |
| 675 } | 644 } |
| 676 | 645 |
| 677 private: | 646 private: |
| 678 GrowableArray<ZoneGrowableArray<Move>* > moves_; | 647 GrowableArray<ZoneGrowableArray<Move>*> moves_; |
| 679 }; | 648 }; |
| 680 | 649 |
| 681 | 650 |
| 682 // A map from aliases to a set of places sharing the alias. Additionally | 651 // A map from aliases to a set of places sharing the alias. Additionally |
| 683 // carries a set of places that can be aliased by side-effects, essentially | 652 // carries a set of places that can be aliased by side-effects, essentially |
| 684 // those that are affected by calls. | 653 // those that are affected by calls. |
| 685 class AliasedSet : public ZoneAllocated { | 654 class AliasedSet : public ZoneAllocated { |
| 686 public: | 655 public: |
| 687 AliasedSet(Zone* zone, | 656 AliasedSet(Zone* zone, |
| 688 DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map, | 657 DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map, |
| 689 ZoneGrowableArray<Place*>* places, | 658 ZoneGrowableArray<Place*>* places, |
| 690 PhiPlaceMoves* phi_moves) | 659 PhiPlaceMoves* phi_moves) |
| 691 : zone_(zone), | 660 : zone_(zone), |
| 692 places_map_(places_map), | 661 places_map_(places_map), |
| 693 places_(*places), | 662 places_(*places), |
| 694 phi_moves_(phi_moves), | 663 phi_moves_(phi_moves), |
| 695 aliases_(5), | 664 aliases_(5), |
| 696 aliases_map_(), | 665 aliases_map_(), |
| 697 typed_data_access_sizes_(), | 666 typed_data_access_sizes_(), |
| 698 representatives_(), | 667 representatives_(), |
| 699 killed_(), | 668 killed_(), |
| 700 aliased_by_effects_(new(zone) BitVector(zone, places->length())) { | 669 aliased_by_effects_(new (zone) BitVector(zone, places->length())) { |
| 701 InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(zone_, | 670 InsertAlias(Place::CreateAnyInstanceAnyIndexAlias( |
| 702 kAnyInstanceAnyIndexAlias)); | 671 zone_, kAnyInstanceAnyIndexAlias)); |
| 703 for (intptr_t i = 0; i < places_.length(); i++) { | 672 for (intptr_t i = 0; i < places_.length(); i++) { |
| 704 AddRepresentative(places_[i]); | 673 AddRepresentative(places_[i]); |
| 705 } | 674 } |
| 706 ComputeKillSets(); | 675 ComputeKillSets(); |
| 707 } | 676 } |
| 708 | 677 |
| 709 intptr_t LookupAliasId(const Place& alias) { | 678 intptr_t LookupAliasId(const Place& alias) { |
| 710 const Place* result = aliases_map_.LookupValue(&alias); | 679 const Place* result = aliases_map_.LookupValue(&alias); |
| 711 return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias); | 680 return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias); |
| 712 } | 681 } |
| 713 | 682 |
| 714 BitVector* GetKilledSet(intptr_t alias) { | 683 BitVector* GetKilledSet(intptr_t alias) { |
| 715 return (alias < killed_.length()) ? killed_[alias] : NULL; | 684 return (alias < killed_.length()) ? killed_[alias] : NULL; |
| 716 } | 685 } |
| 717 | 686 |
| 718 intptr_t max_place_id() const { return places().length(); } | 687 intptr_t max_place_id() const { return places().length(); } |
| 719 bool IsEmpty() const { return max_place_id() == 0; } | 688 bool IsEmpty() const { return max_place_id() == 0; } |
| 720 | 689 |
| 721 BitVector* aliased_by_effects() const { return aliased_by_effects_; } | 690 BitVector* aliased_by_effects() const { return aliased_by_effects_; } |
| 722 | 691 |
| 723 const ZoneGrowableArray<Place*>& places() const { | 692 const ZoneGrowableArray<Place*>& places() const { return places_; } |
| 724 return places_; | |
| 725 } | |
| 726 | 693 |
| 727 Place* LookupCanonical(Place* place) const { | 694 Place* LookupCanonical(Place* place) const { |
| 728 return places_map_->LookupValue(place); | 695 return places_map_->LookupValue(place); |
| 729 } | 696 } |
| 730 | 697 |
| 731 void PrintSet(BitVector* set) { | 698 void PrintSet(BitVector* set) { |
| 732 bool comma = false; | 699 bool comma = false; |
| 733 for (BitVector::Iterator it(set); | 700 for (BitVector::Iterator it(set); !it.Done(); it.Advance()) { |
| 734 !it.Done(); | |
| 735 it.Advance()) { | |
| 736 if (comma) { | 701 if (comma) { |
| 737 THR_Print(", "); | 702 THR_Print(", "); |
| 738 } | 703 } |
| 739 THR_Print("%s", places_[it.Current()]->ToCString()); | 704 THR_Print("%s", places_[it.Current()]->ToCString()); |
| 740 comma = true; | 705 comma = true; |
| 741 } | 706 } |
| 742 } | 707 } |
| 743 | 708 |
| 744 const PhiPlaceMoves* phi_moves() const { return phi_moves_; } | 709 const PhiPlaceMoves* phi_moves() const { return phi_moves_; } |
| 745 | 710 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 756 return true; | 721 return true; |
| 757 } | 722 } |
| 758 | 723 |
| 759 if (alloc->Identity().IsUnknown()) { | 724 if (alloc->Identity().IsUnknown()) { |
| 760 ComputeAliasing(alloc); | 725 ComputeAliasing(alloc); |
| 761 } | 726 } |
| 762 | 727 |
| 763 return !alloc->Identity().IsNotAliased(); | 728 return !alloc->Identity().IsNotAliased(); |
| 764 } | 729 } |
| 765 | 730 |
| 766 enum { | 731 enum { kNoAlias = 0 }; |
| 767 kNoAlias = 0 | |
| 768 }; | |
| 769 | 732 |
| 770 private: | 733 private: |
| 771 enum { | 734 enum { |
| 772 // Artificial alias that is used to collect all representatives of the | 735 // Artificial alias that is used to collect all representatives of the |
| 773 // *[C], X[C] aliases for arbitrary C. | 736 // *[C], X[C] aliases for arbitrary C. |
| 774 kAnyConstantIndexedAlias = 1, | 737 kAnyConstantIndexedAlias = 1, |
| 775 | 738 |
| 776 // Artificial alias that is used to collect all representatives of | 739 // Artificial alias that is used to collect all representatives of |
| 777 // *[C] alias for arbitrary C. | 740 // *[C] alias for arbitrary C. |
| 778 kUnknownInstanceConstantIndexedAlias = 2, | 741 kUnknownInstanceConstantIndexedAlias = 2, |
| 779 | 742 |
| 780 // Artificial alias that is used to collect all representatives of | 743 // Artificial alias that is used to collect all representatives of |
| 781 // X[*] alias for all X. | 744 // X[*] alias for all X. |
| 782 kAnyAllocationIndexedAlias = 3, | 745 kAnyAllocationIndexedAlias = 3, |
| 783 | 746 |
| 784 // *[*] alias. | 747 // *[*] alias. |
| 785 kAnyInstanceAnyIndexAlias = 4 | 748 kAnyInstanceAnyIndexAlias = 4 |
| 786 }; | 749 }; |
| 787 | 750 |
| 788 // Compute least generic alias for the place and assign alias id to it. | 751 // Compute least generic alias for the place and assign alias id to it. |
| 789 void AddRepresentative(Place* place) { | 752 void AddRepresentative(Place* place) { |
| 790 if (!place->IsImmutableField()) { | 753 if (!place->IsImmutableField()) { |
| 791 const Place* alias = CanonicalizeAlias(place->ToAlias()); | 754 const Place* alias = CanonicalizeAlias(place->ToAlias()); |
| 792 EnsureSet(&representatives_, alias->id())->Add(place->id()); | 755 EnsureSet(&representatives_, alias->id())->Add(place->id()); |
| 793 | 756 |
| 794 // Update cumulative representative sets that are used during | 757 // Update cumulative representative sets that are used during |
| 795 // killed sets computation. | 758 // killed sets computation. |
| 796 if (alias->kind() == Place::kConstantIndexed) { | 759 if (alias->kind() == Place::kConstantIndexed) { |
| 797 if (CanBeAliased(alias->instance())) { | 760 if (CanBeAliased(alias->instance())) { |
| 798 EnsureSet(&representatives_, kAnyConstantIndexedAlias)-> | 761 EnsureSet(&representatives_, kAnyConstantIndexedAlias) |
| 799 Add(place->id()); | 762 ->Add(place->id()); |
| 800 } | 763 } |
| 801 | 764 |
| 802 if (alias->instance() == NULL) { | 765 if (alias->instance() == NULL) { |
| 803 EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias)-> | 766 EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias) |
| 804 Add(place->id()); | 767 ->Add(place->id()); |
| 805 } | 768 } |
| 806 | 769 |
| 807 // Collect all element sizes used to access TypedData arrays in | 770 // Collect all element sizes used to access TypedData arrays in |
| 808 // the function. This is used to skip sizes without representatives | 771 // the function. This is used to skip sizes without representatives |
| 809 // when computing kill sets. | 772 // when computing kill sets. |
| 810 if (alias->element_size() != Place::kNoSize) { | 773 if (alias->element_size() != Place::kNoSize) { |
| 811 typed_data_access_sizes_.Add(alias->element_size()); | 774 typed_data_access_sizes_.Add(alias->element_size()); |
| 812 } | 775 } |
| 813 } else if ((alias->kind() == Place::kIndexed) && | 776 } else if ((alias->kind() == Place::kIndexed) && |
| 814 CanBeAliased(place->instance())) { | 777 CanBeAliased(place->instance())) { |
| 815 EnsureSet(&representatives_, kAnyAllocationIndexedAlias)-> | 778 EnsureSet(&representatives_, kAnyAllocationIndexedAlias) |
| 816 Add(place->id()); | 779 ->Add(place->id()); |
| 817 } | 780 } |
| 818 | 781 |
| 819 if (!IsIndependentFromEffects(place)) { | 782 if (!IsIndependentFromEffects(place)) { |
| 820 aliased_by_effects_->Add(place->id()); | 783 aliased_by_effects_->Add(place->id()); |
| 821 } | 784 } |
| 822 } | 785 } |
| 823 } | 786 } |
| 824 | 787 |
| 825 void ComputeKillSets() { | 788 void ComputeKillSets() { |
| 826 for (intptr_t i = 0; i < aliases_.length(); ++i) { | 789 for (intptr_t i = 0; i < aliases_.length(); ++i) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 846 } | 809 } |
| 847 | 810 |
| 848 void InsertAlias(const Place* alias) { | 811 void InsertAlias(const Place* alias) { |
| 849 aliases_map_.Insert(alias); | 812 aliases_map_.Insert(alias); |
| 850 aliases_.Add(alias); | 813 aliases_.Add(alias); |
| 851 } | 814 } |
| 852 | 815 |
| 853 const Place* CanonicalizeAlias(const Place& alias) { | 816 const Place* CanonicalizeAlias(const Place& alias) { |
| 854 const Place* canonical = aliases_map_.LookupValue(&alias); | 817 const Place* canonical = aliases_map_.LookupValue(&alias); |
| 855 if (canonical == NULL) { | 818 if (canonical == NULL) { |
| 856 canonical = Place::Wrap(zone_, | 819 canonical = Place::Wrap(zone_, alias, |
| 857 alias, | |
| 858 kAnyInstanceAnyIndexAlias + aliases_.length()); | 820 kAnyInstanceAnyIndexAlias + aliases_.length()); |
| 859 InsertAlias(canonical); | 821 InsertAlias(canonical); |
| 860 } | 822 } |
| 861 ASSERT(aliases_map_.LookupValue(&alias) == canonical); | 823 ASSERT(aliases_map_.LookupValue(&alias) == canonical); |
| 862 return canonical; | 824 return canonical; |
| 863 } | 825 } |
| 864 | 826 |
| 865 BitVector* GetRepresentativesSet(intptr_t alias) { | 827 BitVector* GetRepresentativesSet(intptr_t alias) { |
| 866 return (alias < representatives_.length()) ? representatives_[alias] : NULL; | 828 return (alias < representatives_.length()) ? representatives_[alias] : NULL; |
| 867 } | 829 } |
| 868 | 830 |
| 869 BitVector* EnsureSet(GrowableArray<BitVector*>* sets, | 831 BitVector* EnsureSet(GrowableArray<BitVector*>* sets, intptr_t alias) { |
| 870 intptr_t alias) { | |
| 871 while (sets->length() <= alias) { | 832 while (sets->length() <= alias) { |
| 872 sets->Add(NULL); | 833 sets->Add(NULL); |
| 873 } | 834 } |
| 874 | 835 |
| 875 BitVector* set = (*sets)[alias]; | 836 BitVector* set = (*sets)[alias]; |
| 876 if (set == NULL) { | 837 if (set == NULL) { |
| 877 (*sets)[alias] = set = new(zone_) BitVector(zone_, max_place_id()); | 838 (*sets)[alias] = set = new (zone_) BitVector(zone_, max_place_id()); |
| 878 } | 839 } |
| 879 return set; | 840 return set; |
| 880 } | 841 } |
| 881 | 842 |
| 882 void AddAllRepresentatives(const Place* to, intptr_t from) { | 843 void AddAllRepresentatives(const Place* to, intptr_t from) { |
| 883 AddAllRepresentatives(to->id(), from); | 844 AddAllRepresentatives(to->id(), from); |
| 884 } | 845 } |
| 885 | 846 |
| 886 void AddAllRepresentatives(intptr_t to, intptr_t from) { | 847 void AddAllRepresentatives(intptr_t to, intptr_t from) { |
| 887 BitVector* from_set = GetRepresentativesSet(from); | 848 BitVector* from_set = GetRepresentativesSet(from); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 | 895 |
| 935 // If this is a TypedData access then X[C|S] aliases larger elements | 896 // If this is a TypedData access then X[C|S] aliases larger elements |
| 936 // covering this one X[RoundDown(C, S')|S'] for all S' > S and | 897 // covering this one X[RoundDown(C, S')|S'] for all S' > S and |
| 937 // all smaller elements being covered by this one X[C'|S'] for | 898 // all smaller elements being covered by this one X[C'|S'] for |
| 938 // some S' < S and all C' such that C = RoundDown(C', S). | 899 // some S' < S and all C' such that C = RoundDown(C', S). |
| 939 // In the loop below it's enough to only propagate aliasing to | 900 // In the loop below it's enough to only propagate aliasing to |
| 940 // larger aliases because propagation is symmetric: smaller aliases | 901 // larger aliases because propagation is symmetric: smaller aliases |
| 941 // (if there are any) would update kill set for this alias when they | 902 // (if there are any) would update kill set for this alias when they |
| 942 // are visited. | 903 // are visited. |
| 943 for (intptr_t i = static_cast<intptr_t>(alias->element_size()) + 1; | 904 for (intptr_t i = static_cast<intptr_t>(alias->element_size()) + 1; |
| 944 i <= Place::kLargestElementSize; | 905 i <= Place::kLargestElementSize; i++) { |
| 945 i++) { | |
| 946 // Skip element sizes that a guaranteed to have no representatives. | 906 // Skip element sizes that a guaranteed to have no representatives. |
| 947 if (!typed_data_access_sizes_.Contains(alias->element_size())) { | 907 if (!typed_data_access_sizes_.Contains(alias->element_size())) { |
| 948 continue; | 908 continue; |
| 949 } | 909 } |
| 950 | 910 |
| 951 // X[C|S] aliases with X[RoundDown(C, S')|S'] and likewise | 911 // X[C|S] aliases with X[RoundDown(C, S')|S'] and likewise |
| 952 // *[C|S] aliases with *[RoundDown(C, S')|S']. | 912 // *[C|S] aliases with *[RoundDown(C, S')|S']. |
| 953 const Place larger_alias = | 913 const Place larger_alias = |
| 954 alias->ToLargerElement(static_cast<Place::ElementSize>(i)); | 914 alias->ToLargerElement(static_cast<Place::ElementSize>(i)); |
| 955 CrossAlias(alias, larger_alias); | 915 CrossAlias(alias, larger_alias); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1003 // receiver then they will get the same expression number. However | 963 // receiver then they will get the same expression number. However |
| 1004 // immutability of the length of fixed size list does not mean that | 964 // immutability of the length of fixed size list does not mean that |
| 1005 // growable list also has immutable property. Thus we will make a | 965 // growable list also has immutable property. Thus we will make a |
| 1006 // conservative assumption for the VM-properties. | 966 // conservative assumption for the VM-properties. |
| 1007 // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with | 967 // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with |
| 1008 // the same offset e.g. through recognized kind. | 968 // the same offset e.g. through recognized kind. |
| 1009 return true; | 969 return true; |
| 1010 } | 970 } |
| 1011 | 971 |
| 1012 return ((place->kind() == Place::kField) || | 972 return ((place->kind() == Place::kField) || |
| 1013 (place->kind() == Place::kVMField)) && | 973 (place->kind() == Place::kVMField)) && |
| 1014 !CanBeAliased(place->instance()); | 974 !CanBeAliased(place->instance()); |
| 1015 } | 975 } |
| 1016 | 976 |
| 1017 // Returns true if there are direct loads from the given place. | 977 // Returns true if there are direct loads from the given place. |
| 1018 bool HasLoadsFromPlace(Definition* defn, const Place* place) { | 978 bool HasLoadsFromPlace(Definition* defn, const Place* place) { |
| 1019 ASSERT((place->kind() == Place::kField) || | 979 ASSERT((place->kind() == Place::kField) || |
| 1020 (place->kind() == Place::kVMField)); | 980 (place->kind() == Place::kVMField)); |
| 1021 | 981 |
| 1022 for (Value* use = defn->input_use_list(); | 982 for (Value* use = defn->input_use_list(); use != NULL; |
| 1023 use != NULL; | |
| 1024 use = use->next_use()) { | 983 use = use->next_use()) { |
| 1025 Instruction* instr = use->instruction(); | 984 Instruction* instr = use->instruction(); |
| 1026 if ((instr->IsRedefinition() || | 985 if ((instr->IsRedefinition() || instr->IsAssertAssignable()) && |
| 1027 instr->IsAssertAssignable()) && | |
| 1028 HasLoadsFromPlace(instr->AsDefinition(), place)) { | 986 HasLoadsFromPlace(instr->AsDefinition(), place)) { |
| 1029 return true; | 987 return true; |
| 1030 } | 988 } |
| 1031 bool is_load = false, is_store; | 989 bool is_load = false, is_store; |
| 1032 Place load_place(instr, &is_load, &is_store); | 990 Place load_place(instr, &is_load, &is_store); |
| 1033 | 991 |
| 1034 if (is_load && load_place.Equals(place)) { | 992 if (is_load && load_place.Equals(place)) { |
| 1035 return true; | 993 return true; |
| 1036 } | 994 } |
| 1037 } | 995 } |
| 1038 | 996 |
| 1039 return false; | 997 return false; |
| 1040 } | 998 } |
| 1041 | 999 |
| 1042 // Check if any use of the definition can create an alias. | 1000 // Check if any use of the definition can create an alias. |
| 1043 // Can add more objects into aliasing_worklist_. | 1001 // Can add more objects into aliasing_worklist_. |
| 1044 bool AnyUseCreatesAlias(Definition* defn) { | 1002 bool AnyUseCreatesAlias(Definition* defn) { |
| 1045 for (Value* use = defn->input_use_list(); | 1003 for (Value* use = defn->input_use_list(); use != NULL; |
| 1046 use != NULL; | |
| 1047 use = use->next_use()) { | 1004 use = use->next_use()) { |
| 1048 Instruction* instr = use->instruction(); | 1005 Instruction* instr = use->instruction(); |
| 1049 if (instr->IsPushArgument() || | 1006 if (instr->IsPushArgument() || |
| 1050 (instr->IsStoreIndexed() | 1007 (instr->IsStoreIndexed() && |
| 1051 && (use->use_index() == StoreIndexedInstr::kValuePos)) || | 1008 (use->use_index() == StoreIndexedInstr::kValuePos)) || |
| 1052 instr->IsStoreStaticField() || | 1009 instr->IsStoreStaticField() || instr->IsPhi()) { |
| 1053 instr->IsPhi()) { | |
| 1054 return true; | 1010 return true; |
| 1055 } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) && | 1011 } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) && |
| 1056 AnyUseCreatesAlias(instr->AsDefinition())) { | 1012 AnyUseCreatesAlias(instr->AsDefinition())) { |
| 1057 return true; | 1013 return true; |
| 1058 } else if ((instr->IsStoreInstanceField() | 1014 } else if ((instr->IsStoreInstanceField() && |
| 1059 && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { | 1015 (use->use_index() != |
| 1016 StoreInstanceFieldInstr::kInstancePos))) { |
| 1060 ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); | 1017 ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); |
| 1061 // If we store this value into an object that is not aliased itself | 1018 // If we store this value into an object that is not aliased itself |
| 1062 // and we never load again then the store does not create an alias. | 1019 // and we never load again then the store does not create an alias. |
| 1063 StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); | 1020 StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); |
| 1064 Definition* instance = | 1021 Definition* instance = |
| 1065 store->instance()->definition()->OriginalDefinition(); | 1022 store->instance()->definition()->OriginalDefinition(); |
| 1066 if (Place::IsAllocation(instance) && | 1023 if (Place::IsAllocation(instance) && |
| 1067 !instance->Identity().IsAliased()) { | 1024 !instance->Identity().IsAliased()) { |
| 1068 bool is_load, is_store; | 1025 bool is_load, is_store; |
| 1069 Place store_place(instr, &is_load, &is_store); | 1026 Place store_place(instr, &is_load, &is_store); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1081 } | 1038 } |
| 1082 return true; | 1039 return true; |
| 1083 } | 1040 } |
| 1084 } | 1041 } |
| 1085 return false; | 1042 return false; |
| 1086 } | 1043 } |
| 1087 | 1044 |
| 1088 // Mark any value stored into the given object as potentially aliased. | 1045 // Mark any value stored into the given object as potentially aliased. |
| 1089 void MarkStoredValuesEscaping(Definition* defn) { | 1046 void MarkStoredValuesEscaping(Definition* defn) { |
| 1090 // Find all stores into this object. | 1047 // Find all stores into this object. |
| 1091 for (Value* use = defn->input_use_list(); | 1048 for (Value* use = defn->input_use_list(); use != NULL; |
| 1092 use != NULL; | |
| 1093 use = use->next_use()) { | 1049 use = use->next_use()) { |
| 1094 if (use->instruction()->IsRedefinition() || | 1050 if (use->instruction()->IsRedefinition() || |
| 1095 use->instruction()->IsAssertAssignable()) { | 1051 use->instruction()->IsAssertAssignable()) { |
| 1096 MarkStoredValuesEscaping(use->instruction()->AsDefinition()); | 1052 MarkStoredValuesEscaping(use->instruction()->AsDefinition()); |
| 1097 continue; | 1053 continue; |
| 1098 } | 1054 } |
| 1099 if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && | 1055 if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && |
| 1100 use->instruction()->IsStoreInstanceField()) { | 1056 use->instruction()->IsStoreInstanceField()) { |
| 1101 StoreInstanceFieldInstr* store = | 1057 StoreInstanceFieldInstr* store = |
| 1102 use->instruction()->AsStoreInstanceField(); | 1058 use->instruction()->AsStoreInstanceField(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 } | 1152 } |
| 1197 | 1153 |
| 1198 UNREACHABLE(); // Should only be called for supported store instructions. | 1154 UNREACHABLE(); // Should only be called for supported store instructions. |
| 1199 return NULL; | 1155 return NULL; |
| 1200 } | 1156 } |
| 1201 | 1157 |
| 1202 | 1158 |
| 1203 static bool IsPhiDependentPlace(Place* place) { | 1159 static bool IsPhiDependentPlace(Place* place) { |
| 1204 return ((place->kind() == Place::kField) || | 1160 return ((place->kind() == Place::kField) || |
| 1205 (place->kind() == Place::kVMField)) && | 1161 (place->kind() == Place::kVMField)) && |
| 1206 (place->instance() != NULL) && | 1162 (place->instance() != NULL) && place->instance()->IsPhi(); |
| 1207 place->instance()->IsPhi(); | |
| 1208 } | 1163 } |
| 1209 | 1164 |
| 1210 | 1165 |
| 1211 // For each place that depends on a phi ensure that equivalent places | 1166 // For each place that depends on a phi ensure that equivalent places |
| 1212 // corresponding to phi input are numbered and record outgoing phi moves | 1167 // corresponding to phi input are numbered and record outgoing phi moves |
| 1213 // for each block which establish correspondence between phi dependent place | 1168 // for each block which establish correspondence between phi dependent place |
| 1214 // and phi input's place that is flowing in. | 1169 // and phi input's place that is flowing in. |
| 1215 static PhiPlaceMoves* ComputePhiMoves( | 1170 static PhiPlaceMoves* ComputePhiMoves( |
| 1216 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, | 1171 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, |
| 1217 ZoneGrowableArray<Place*>* places) { | 1172 ZoneGrowableArray<Place*>* places) { |
| 1218 Thread* thread = Thread::Current(); | 1173 Thread* thread = Thread::Current(); |
| 1219 Zone* zone = thread->zone(); | 1174 Zone* zone = thread->zone(); |
| 1220 PhiPlaceMoves* phi_moves = new(zone) PhiPlaceMoves(); | 1175 PhiPlaceMoves* phi_moves = new (zone) PhiPlaceMoves(); |
| 1221 | 1176 |
| 1222 for (intptr_t i = 0; i < places->length(); i++) { | 1177 for (intptr_t i = 0; i < places->length(); i++) { |
| 1223 Place* place = (*places)[i]; | 1178 Place* place = (*places)[i]; |
| 1224 | 1179 |
| 1225 if (IsPhiDependentPlace(place)) { | 1180 if (IsPhiDependentPlace(place)) { |
| 1226 PhiInstr* phi = place->instance()->AsPhi(); | 1181 PhiInstr* phi = place->instance()->AsPhi(); |
| 1227 BlockEntryInstr* block = phi->GetBlock(); | 1182 BlockEntryInstr* block = phi->GetBlock(); |
| 1228 | 1183 |
| 1229 if (FLAG_trace_optimization) { | 1184 if (FLAG_trace_optimization) { |
| 1230 THR_Print("phi dependent place %s\n", place->ToCString()); | 1185 THR_Print("phi dependent place %s\n", place->ToCString()); |
| 1231 } | 1186 } |
| 1232 | 1187 |
| 1233 Place input_place(*place); | 1188 Place input_place(*place); |
| 1234 for (intptr_t j = 0; j < phi->InputCount(); j++) { | 1189 for (intptr_t j = 0; j < phi->InputCount(); j++) { |
| 1235 input_place.set_instance(phi->InputAt(j)->definition()); | 1190 input_place.set_instance(phi->InputAt(j)->definition()); |
| 1236 | 1191 |
| 1237 Place* result = map->LookupValue(&input_place); | 1192 Place* result = map->LookupValue(&input_place); |
| 1238 if (result == NULL) { | 1193 if (result == NULL) { |
| 1239 result = Place::Wrap(zone, input_place, places->length()); | 1194 result = Place::Wrap(zone, input_place, places->length()); |
| 1240 map->Insert(result); | 1195 map->Insert(result); |
| 1241 places->Add(result); | 1196 places->Add(result); |
| 1242 if (FLAG_trace_optimization) { | 1197 if (FLAG_trace_optimization) { |
| 1243 THR_Print(" adding place %s as %" Pd "\n", | 1198 THR_Print(" adding place %s as %" Pd "\n", result->ToCString(), |
| 1244 result->ToCString(), | |
| 1245 result->id()); | 1199 result->id()); |
| 1246 } | 1200 } |
| 1247 } | 1201 } |
| 1248 phi_moves->CreateOutgoingMove(zone, | 1202 phi_moves->CreateOutgoingMove(zone, block->PredecessorAt(j), |
| 1249 block->PredecessorAt(j), | 1203 result->id(), place->id()); |
| 1250 result->id(), | |
| 1251 place->id()); | |
| 1252 } | 1204 } |
| 1253 } | 1205 } |
| 1254 } | 1206 } |
| 1255 | 1207 |
| 1256 return phi_moves; | 1208 return phi_moves; |
| 1257 } | 1209 } |
| 1258 | 1210 |
| 1259 | 1211 |
| 1260 enum CSEMode { | 1212 enum CSEMode { kOptimizeLoads, kOptimizeStores }; |
| 1261 kOptimizeLoads, | |
| 1262 kOptimizeStores | |
| 1263 }; | |
| 1264 | 1213 |
| 1265 | 1214 |
| 1266 static AliasedSet* NumberPlaces( | 1215 static AliasedSet* NumberPlaces( |
| 1267 FlowGraph* graph, | 1216 FlowGraph* graph, |
| 1268 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, | 1217 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map, |
| 1269 CSEMode mode) { | 1218 CSEMode mode) { |
| 1270 // Loads representing different expression ids will be collected and | 1219 // Loads representing different expression ids will be collected and |
| 1271 // used to build per offset kill sets. | 1220 // used to build per offset kill sets. |
| 1272 Zone* zone = graph->zone(); | 1221 Zone* zone = graph->zone(); |
| 1273 ZoneGrowableArray<Place*>* places = | 1222 ZoneGrowableArray<Place*>* places = new (zone) ZoneGrowableArray<Place*>(10); |
| 1274 new(zone) ZoneGrowableArray<Place*>(10); | |
| 1275 | 1223 |
| 1276 bool has_loads = false; | 1224 bool has_loads = false; |
| 1277 bool has_stores = false; | 1225 bool has_stores = false; |
| 1278 for (BlockIterator it = graph->reverse_postorder_iterator(); | 1226 for (BlockIterator it = graph->reverse_postorder_iterator(); !it.Done(); |
| 1279 !it.Done(); | |
| 1280 it.Advance()) { | 1227 it.Advance()) { |
| 1281 BlockEntryInstr* block = it.Current(); | 1228 BlockEntryInstr* block = it.Current(); |
| 1282 | 1229 |
| 1283 for (ForwardInstructionIterator instr_it(block); | 1230 for (ForwardInstructionIterator instr_it(block); !instr_it.Done(); |
| 1284 !instr_it.Done(); | |
| 1285 instr_it.Advance()) { | 1231 instr_it.Advance()) { |
| 1286 Instruction* instr = instr_it.Current(); | 1232 Instruction* instr = instr_it.Current(); |
| 1287 Place place(instr, &has_loads, &has_stores); | 1233 Place place(instr, &has_loads, &has_stores); |
| 1288 if (place.kind() == Place::kNone) { | 1234 if (place.kind() == Place::kNone) { |
| 1289 continue; | 1235 continue; |
| 1290 } | 1236 } |
| 1291 | 1237 |
| 1292 Place* result = map->LookupValue(&place); | 1238 Place* result = map->LookupValue(&place); |
| 1293 if (result == NULL) { | 1239 if (result == NULL) { |
| 1294 result = Place::Wrap(zone, place, places->length()); | 1240 result = Place::Wrap(zone, place, places->length()); |
| 1295 map->Insert(result); | 1241 map->Insert(result); |
| 1296 places->Add(result); | 1242 places->Add(result); |
| 1297 | 1243 |
| 1298 if (FLAG_trace_optimization) { | 1244 if (FLAG_trace_optimization) { |
| 1299 THR_Print("numbering %s as %" Pd "\n", | 1245 THR_Print("numbering %s as %" Pd "\n", result->ToCString(), |
| 1300 result->ToCString(), | |
| 1301 result->id()); | 1246 result->id()); |
| 1302 } | 1247 } |
| 1303 } | 1248 } |
| 1304 | 1249 |
| 1305 instr->set_place_id(result->id()); | 1250 instr->set_place_id(result->id()); |
| 1306 } | 1251 } |
| 1307 } | 1252 } |
| 1308 | 1253 |
| 1309 if ((mode == kOptimizeLoads) && !has_loads) { | 1254 if ((mode == kOptimizeLoads) && !has_loads) { |
| 1310 return NULL; | 1255 return NULL; |
| 1311 } | 1256 } |
| 1312 if ((mode == kOptimizeStores) && !has_stores) { | 1257 if ((mode == kOptimizeStores) && !has_stores) { |
| 1313 return NULL; | 1258 return NULL; |
| 1314 } | 1259 } |
| 1315 | 1260 |
| 1316 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); | 1261 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); |
| 1317 | 1262 |
| 1318 // Build aliasing sets mapping aliases to loads. | 1263 // Build aliasing sets mapping aliases to loads. |
| 1319 return new(zone) AliasedSet(zone, map, places, phi_moves); | 1264 return new (zone) AliasedSet(zone, map, places, phi_moves); |
| 1320 } | 1265 } |
| 1321 | 1266 |
| 1322 | 1267 |
| 1323 // Load instructions handled by load elimination. | 1268 // Load instructions handled by load elimination. |
| 1324 static bool IsLoadEliminationCandidate(Instruction* instr) { | 1269 static bool IsLoadEliminationCandidate(Instruction* instr) { |
| 1325 return instr->IsLoadField() | 1270 return instr->IsLoadField() || instr->IsLoadIndexed() || |
| 1326 || instr->IsLoadIndexed() | 1271 instr->IsLoadStaticField(); |
| 1327 || instr->IsLoadStaticField(); | |
| 1328 } | 1272 } |
| 1329 | 1273 |
| 1330 | 1274 |
| 1331 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, | 1275 static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets, |
| 1332 intptr_t loop_header_index, | 1276 intptr_t loop_header_index, |
| 1333 Instruction* instr) { | 1277 Instruction* instr) { |
| 1334 return IsLoadEliminationCandidate(instr) && | 1278 return IsLoadEliminationCandidate(instr) && (sets != NULL) && |
| 1335 (sets != NULL) && | 1279 instr->HasPlaceId() && ((*sets)[loop_header_index] != NULL) && |
| 1336 instr->HasPlaceId() && | 1280 (*sets)[loop_header_index]->Contains(instr->place_id()); |
| 1337 ((*sets)[loop_header_index] != NULL) && | |
| 1338 (*sets)[loop_header_index]->Contains(instr->place_id()); | |
| 1339 } | 1281 } |
| 1340 | 1282 |
| 1341 | 1283 |
| 1342 LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) { | 1284 LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) { |
| 1343 ASSERT(flow_graph->is_licm_allowed()); | 1285 ASSERT(flow_graph->is_licm_allowed()); |
| 1344 } | 1286 } |
| 1345 | 1287 |
| 1346 | 1288 |
| 1347 void LICM::Hoist(ForwardInstructionIterator* it, | 1289 void LICM::Hoist(ForwardInstructionIterator* it, |
| 1348 BlockEntryInstr* pre_header, | 1290 BlockEntryInstr* pre_header, |
| 1349 Instruction* current) { | 1291 Instruction* current) { |
| 1350 if (current->IsCheckClass()) { | 1292 if (current->IsCheckClass()) { |
| 1351 current->AsCheckClass()->set_licm_hoisted(true); | 1293 current->AsCheckClass()->set_licm_hoisted(true); |
| 1352 } else if (current->IsCheckSmi()) { | 1294 } else if (current->IsCheckSmi()) { |
| 1353 current->AsCheckSmi()->set_licm_hoisted(true); | 1295 current->AsCheckSmi()->set_licm_hoisted(true); |
| 1354 } else if (current->IsCheckEitherNonSmi()) { | 1296 } else if (current->IsCheckEitherNonSmi()) { |
| 1355 current->AsCheckEitherNonSmi()->set_licm_hoisted(true); | 1297 current->AsCheckEitherNonSmi()->set_licm_hoisted(true); |
| 1356 } else if (current->IsCheckArrayBound()) { | 1298 } else if (current->IsCheckArrayBound()) { |
| 1357 current->AsCheckArrayBound()->set_licm_hoisted(true); | 1299 current->AsCheckArrayBound()->set_licm_hoisted(true); |
| 1358 } else if (current->IsTestCids()) { | 1300 } else if (current->IsTestCids()) { |
| 1359 current->AsTestCids()->set_licm_hoisted(true); | 1301 current->AsTestCids()->set_licm_hoisted(true); |
| 1360 } | 1302 } |
| 1361 if (FLAG_trace_optimization) { | 1303 if (FLAG_trace_optimization) { |
| 1362 THR_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n", | 1304 THR_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n", |
| 1363 current->DebugName(), | 1305 current->DebugName(), current->GetDeoptId(), |
| 1364 current->GetDeoptId(), | 1306 current->GetBlock()->block_id(), pre_header->block_id()); |
| 1365 current->GetBlock()->block_id(), | |
| 1366 pre_header->block_id()); | |
| 1367 } | 1307 } |
| 1368 // Move the instruction out of the loop. | 1308 // Move the instruction out of the loop. |
| 1369 current->RemoveEnvironment(); | 1309 current->RemoveEnvironment(); |
| 1370 if (it != NULL) { | 1310 if (it != NULL) { |
| 1371 it->RemoveCurrentFromGraph(); | 1311 it->RemoveCurrentFromGraph(); |
| 1372 } else { | 1312 } else { |
| 1373 current->RemoveFromGraph(); | 1313 current->RemoveFromGraph(); |
| 1374 } | 1314 } |
| 1375 GotoInstr* last = pre_header->last_instruction()->AsGoto(); | 1315 GotoInstr* last = pre_header->last_instruction()->AsGoto(); |
| 1376 // Using kind kEffect will not assign a fresh ssa temporary index. | 1316 // Using kind kEffect will not assign a fresh ssa temporary index. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1403 } | 1343 } |
| 1404 } | 1344 } |
| 1405 } | 1345 } |
| 1406 | 1346 |
| 1407 if ((non_smi_input == kNotFound) || | 1347 if ((non_smi_input == kNotFound) || |
| 1408 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { | 1348 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { |
| 1409 return; | 1349 return; |
| 1410 } | 1350 } |
| 1411 | 1351 |
| 1412 CheckSmiInstr* check = NULL; | 1352 CheckSmiInstr* check = NULL; |
| 1413 for (Value* use = phi->input_use_list(); | 1353 for (Value* use = phi->input_use_list(); (use != NULL) && (check == NULL); |
| 1414 (use != NULL) && (check == NULL); | |
| 1415 use = use->next_use()) { | 1354 use = use->next_use()) { |
| 1416 check = use->instruction()->AsCheckSmi(); | 1355 check = use->instruction()->AsCheckSmi(); |
| 1417 } | 1356 } |
| 1418 | 1357 |
| 1419 if (check == NULL) { | 1358 if (check == NULL) { |
| 1420 return; | 1359 return; |
| 1421 } | 1360 } |
| 1422 | 1361 |
| 1423 // Host CheckSmi instruction and make this phi smi one. | 1362 // Host CheckSmi instruction and make this phi smi one. |
| 1424 Hoist(NULL, pre_header, check); | 1363 Hoist(NULL, pre_header, check); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1468 flow_graph()->loop_invariant_loads(); | 1407 flow_graph()->loop_invariant_loads(); |
| 1469 | 1408 |
| 1470 BlockEffects* block_effects = flow_graph()->block_effects(); | 1409 BlockEffects* block_effects = flow_graph()->block_effects(); |
| 1471 | 1410 |
| 1472 for (intptr_t i = 0; i < loop_headers.length(); ++i) { | 1411 for (intptr_t i = 0; i < loop_headers.length(); ++i) { |
| 1473 BlockEntryInstr* header = loop_headers[i]; | 1412 BlockEntryInstr* header = loop_headers[i]; |
| 1474 // Skip loop that don't have a pre-header block. | 1413 // Skip loop that don't have a pre-header block. |
| 1475 BlockEntryInstr* pre_header = header->ImmediateDominator(); | 1414 BlockEntryInstr* pre_header = header->ImmediateDominator(); |
| 1476 if (pre_header == NULL) continue; | 1415 if (pre_header == NULL) continue; |
| 1477 | 1416 |
| 1478 for (BitVector::Iterator loop_it(header->loop_info()); | 1417 for (BitVector::Iterator loop_it(header->loop_info()); !loop_it.Done(); |
| 1479 !loop_it.Done(); | |
| 1480 loop_it.Advance()) { | 1418 loop_it.Advance()) { |
| 1481 BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()]; | 1419 BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()]; |
| 1482 for (ForwardInstructionIterator it(block); | 1420 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1483 !it.Done(); | |
| 1484 it.Advance()) { | |
| 1485 Instruction* current = it.Current(); | 1421 Instruction* current = it.Current(); |
| 1486 if ((current->AllowsCSE() && | 1422 if ((current->AllowsCSE() && |
| 1487 block_effects->CanBeMovedTo(current, pre_header)) || | 1423 block_effects->CanBeMovedTo(current, pre_header)) || |
| 1488 IsLoopInvariantLoad(loop_invariant_loads, i, current)) { | 1424 IsLoopInvariantLoad(loop_invariant_loads, i, current)) { |
| 1489 bool inputs_loop_invariant = true; | 1425 bool inputs_loop_invariant = true; |
| 1490 for (int i = 0; i < current->InputCount(); ++i) { | 1426 for (int i = 0; i < current->InputCount(); ++i) { |
| 1491 Definition* input_def = current->InputAt(i)->definition(); | 1427 Definition* input_def = current->InputAt(i)->definition(); |
| 1492 if (!input_def->GetBlock()->Dominates(pre_header)) { | 1428 if (!input_def->GetBlock()->Dominates(pre_header)) { |
| 1493 inputs_loop_invariant = false; | 1429 inputs_loop_invariant = false; |
| 1494 break; | 1430 break; |
| 1495 } | 1431 } |
| 1496 } | 1432 } |
| 1497 if (inputs_loop_invariant && | 1433 if (inputs_loop_invariant && !current->IsAssertAssignable() && |
| 1498 !current->IsAssertAssignable() && | |
| 1499 !current->IsAssertBoolean()) { | 1434 !current->IsAssertBoolean()) { |
| 1500 // TODO(fschneider): Enable hoisting of Assert-instructions | 1435 // TODO(fschneider): Enable hoisting of Assert-instructions |
| 1501 // if it safe to do. | 1436 // if it safe to do. |
| 1502 Hoist(&it, pre_header, current); | 1437 Hoist(&it, pre_header, current); |
| 1503 } | 1438 } |
| 1504 } | 1439 } |
| 1505 } | 1440 } |
| 1506 } | 1441 } |
| 1507 } | 1442 } |
| 1508 } | 1443 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1520 exposed_values_(graph_->preorder().length()), | 1455 exposed_values_(graph_->preorder().length()), |
| 1521 out_values_(graph_->preorder().length()), | 1456 out_values_(graph_->preorder().length()), |
| 1522 phis_(5), | 1457 phis_(5), |
| 1523 worklist_(5), | 1458 worklist_(5), |
| 1524 congruency_worklist_(6), | 1459 congruency_worklist_(6), |
| 1525 in_worklist_(NULL), | 1460 in_worklist_(NULL), |
| 1526 forwarded_(false) { | 1461 forwarded_(false) { |
| 1527 const intptr_t num_blocks = graph_->preorder().length(); | 1462 const intptr_t num_blocks = graph_->preorder().length(); |
| 1528 for (intptr_t i = 0; i < num_blocks; i++) { | 1463 for (intptr_t i = 0; i < num_blocks; i++) { |
| 1529 out_.Add(NULL); | 1464 out_.Add(NULL); |
| 1530 gen_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id())); | 1465 gen_.Add(new (Z) BitVector(Z, aliased_set_->max_place_id())); |
| 1531 kill_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id())); | 1466 kill_.Add(new (Z) BitVector(Z, aliased_set_->max_place_id())); |
| 1532 in_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id())); | 1467 in_.Add(new (Z) BitVector(Z, aliased_set_->max_place_id())); |
| 1533 | 1468 |
| 1534 exposed_values_.Add(NULL); | 1469 exposed_values_.Add(NULL); |
| 1535 out_values_.Add(NULL); | 1470 out_values_.Add(NULL); |
| 1536 } | 1471 } |
| 1537 } | 1472 } |
| 1538 | 1473 |
| 1539 ~LoadOptimizer() { | 1474 ~LoadOptimizer() { aliased_set_->RollbackAliasedIdentites(); } |
| 1540 aliased_set_->RollbackAliasedIdentites(); | |
| 1541 } | |
| 1542 | 1475 |
| 1543 Isolate* isolate() const { return graph_->isolate(); } | 1476 Isolate* isolate() const { return graph_->isolate(); } |
| 1544 Zone* zone() const { return graph_->zone(); } | 1477 Zone* zone() const { return graph_->zone(); } |
| 1545 | 1478 |
| 1546 static bool OptimizeGraph(FlowGraph* graph) { | 1479 static bool OptimizeGraph(FlowGraph* graph) { |
| 1547 ASSERT(FLAG_load_cse); | 1480 ASSERT(FLAG_load_cse); |
| 1548 if (FLAG_trace_load_optimization) { | 1481 if (FLAG_trace_load_optimization) { |
| 1549 FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph); | 1482 FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph); |
| 1550 } | 1483 } |
| 1551 | 1484 |
| 1552 // For now, bail out for large functions to avoid OOM situations. | 1485 // For now, bail out for large functions to avoid OOM situations. |
| 1553 // TODO(fschneider): Fix the memory consumption issue. | 1486 // TODO(fschneider): Fix the memory consumption issue. |
| 1554 intptr_t function_length = | 1487 intptr_t function_length = graph->function().end_token_pos().Pos() - |
| 1555 graph->function().end_token_pos().Pos() - | 1488 graph->function().token_pos().Pos(); |
| 1556 graph->function().token_pos().Pos(); | |
| 1557 if (function_length >= FLAG_huge_method_cutoff_in_tokens) { | 1489 if (function_length >= FLAG_huge_method_cutoff_in_tokens) { |
| 1558 return false; | 1490 return false; |
| 1559 } | 1491 } |
| 1560 | 1492 |
| 1561 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; | 1493 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
| 1562 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads); | 1494 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads); |
| 1563 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { | 1495 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
| 1564 // If any loads were forwarded return true from Optimize to run load | 1496 // If any loads were forwarded return true from Optimize to run load |
| 1565 // forwarding again. This will allow to forward chains of loads. | 1497 // forwarding again. This will allow to forward chains of loads. |
| 1566 // This is especially important for context variables as they are built | 1498 // This is especially important for context variables as they are built |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1592 } | 1524 } |
| 1593 | 1525 |
| 1594 // Compute sets of loads generated and killed by each block. | 1526 // Compute sets of loads generated and killed by each block. |
| 1595 // Additionally compute upwards exposed and generated loads for each block. | 1527 // Additionally compute upwards exposed and generated loads for each block. |
| 1596 // Exposed loads are those that can be replaced if a corresponding | 1528 // Exposed loads are those that can be replaced if a corresponding |
| 1597 // reaching load will be found. | 1529 // reaching load will be found. |
| 1598 // Loads that are locally redundant will be replaced as we go through | 1530 // Loads that are locally redundant will be replaced as we go through |
| 1599 // instructions. | 1531 // instructions. |
| 1600 void ComputeInitialSets() { | 1532 void ComputeInitialSets() { |
| 1601 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 1533 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 1602 !block_it.Done(); | 1534 !block_it.Done(); block_it.Advance()) { |
| 1603 block_it.Advance()) { | |
| 1604 BlockEntryInstr* block = block_it.Current(); | 1535 BlockEntryInstr* block = block_it.Current(); |
| 1605 const intptr_t preorder_number = block->preorder_number(); | 1536 const intptr_t preorder_number = block->preorder_number(); |
| 1606 | 1537 |
| 1607 BitVector* kill = kill_[preorder_number]; | 1538 BitVector* kill = kill_[preorder_number]; |
| 1608 BitVector* gen = gen_[preorder_number]; | 1539 BitVector* gen = gen_[preorder_number]; |
| 1609 | 1540 |
| 1610 ZoneGrowableArray<Definition*>* exposed_values = NULL; | 1541 ZoneGrowableArray<Definition*>* exposed_values = NULL; |
| 1611 ZoneGrowableArray<Definition*>* out_values = NULL; | 1542 ZoneGrowableArray<Definition*>* out_values = NULL; |
| 1612 | 1543 |
| 1613 for (ForwardInstructionIterator instr_it(block); | 1544 for (ForwardInstructionIterator instr_it(block); !instr_it.Done(); |
| 1614 !instr_it.Done(); | |
| 1615 instr_it.Advance()) { | 1545 instr_it.Advance()) { |
| 1616 Instruction* instr = instr_it.Current(); | 1546 Instruction* instr = instr_it.Current(); |
| 1617 | 1547 |
| 1618 bool is_load = false, is_store = false; | 1548 bool is_load = false, is_store = false; |
| 1619 Place place(instr, &is_load, &is_store); | 1549 Place place(instr, &is_load, &is_store); |
| 1620 | 1550 |
| 1621 BitVector* killed = NULL; | 1551 BitVector* killed = NULL; |
| 1622 if (is_store) { | 1552 if (is_store) { |
| 1623 const intptr_t alias_id = | 1553 const intptr_t alias_id = |
| 1624 aliased_set_->LookupAliasId(place.ToAlias()); | 1554 aliased_set_->LookupAliasId(place.ToAlias()); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1652 // There is no need to clear out_values when clearing GEN set | 1582 // There is no need to clear out_values when clearing GEN set |
| 1653 // because only those values that are in the GEN set | 1583 // because only those values that are in the GEN set |
| 1654 // will ever be used. | 1584 // will ever be used. |
| 1655 gen->RemoveAll(killed); | 1585 gen->RemoveAll(killed); |
| 1656 } | 1586 } |
| 1657 | 1587 |
| 1658 // Only forward stores to normal arrays, float64, and simd arrays | 1588 // Only forward stores to normal arrays, float64, and simd arrays |
| 1659 // to loads because other array stores (intXX/uintXX/float32) | 1589 // to loads because other array stores (intXX/uintXX/float32) |
| 1660 // may implicitly convert the value stored. | 1590 // may implicitly convert the value stored. |
| 1661 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); | 1591 StoreIndexedInstr* array_store = instr->AsStoreIndexed(); |
| 1662 if ((array_store == NULL) || | 1592 if ((array_store == NULL) || (array_store->class_id() == kArrayCid) || |
| 1663 (array_store->class_id() == kArrayCid) || | |
| 1664 (array_store->class_id() == kTypedDataFloat64ArrayCid) || | 1593 (array_store->class_id() == kTypedDataFloat64ArrayCid) || |
| 1665 (array_store->class_id() == kTypedDataFloat32ArrayCid) || | 1594 (array_store->class_id() == kTypedDataFloat32ArrayCid) || |
| 1666 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { | 1595 (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) { |
| 1667 Place* canonical_place = aliased_set_->LookupCanonical(&place); | 1596 Place* canonical_place = aliased_set_->LookupCanonical(&place); |
| 1668 if (canonical_place != NULL) { | 1597 if (canonical_place != NULL) { |
| 1669 // Store has a corresponding numbered place that might have a | 1598 // Store has a corresponding numbered place that might have a |
| 1670 // load. Try forwarding stored value to it. | 1599 // load. Try forwarding stored value to it. |
| 1671 gen->Add(canonical_place->id()); | 1600 gen->Add(canonical_place->id()); |
| 1672 if (out_values == NULL) out_values = CreateBlockOutValues(); | 1601 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 1673 (*out_values)[canonical_place->id()] = GetStoredValue(instr); | 1602 (*out_values)[canonical_place->id()] = GetStoredValue(instr); |
| 1674 } | 1603 } |
| 1675 } | 1604 } |
| 1676 | 1605 |
| 1677 ASSERT(!instr->IsDefinition() || | 1606 ASSERT(!instr->IsDefinition() || |
| 1678 !IsLoadEliminationCandidate(instr->AsDefinition())); | 1607 !IsLoadEliminationCandidate(instr->AsDefinition())); |
| 1679 continue; | 1608 continue; |
| 1680 } else if (is_load) { | 1609 } else if (is_load) { |
| 1681 // Check if this load needs renumbering because of the intrablock | 1610 // Check if this load needs renumbering because of the intrablock |
| 1682 // load forwarding. | 1611 // load forwarding. |
| 1683 const Place* canonical = aliased_set_->LookupCanonical(&place); | 1612 const Place* canonical = aliased_set_->LookupCanonical(&place); |
| 1684 if ((canonical != NULL) && | 1613 if ((canonical != NULL) && |
| 1685 (canonical->id() != instr->AsDefinition()->place_id())) { | 1614 (canonical->id() != instr->AsDefinition()->place_id())) { |
| 1686 instr->AsDefinition()->set_place_id(canonical->id()); | 1615 instr->AsDefinition()->set_place_id(canonical->id()); |
| 1687 } | 1616 } |
| 1688 } | 1617 } |
| 1689 | 1618 |
| 1690 // If instruction has effects then kill all loads affected. | 1619 // If instruction has effects then kill all loads affected. |
| 1691 if (!instr->Effects().IsNone()) { | 1620 if (!instr->Effects().IsNone()) { |
| 1692 kill->AddAll(aliased_set_->aliased_by_effects()); | 1621 kill->AddAll(aliased_set_->aliased_by_effects()); |
| 1693 // There is no need to clear out_values when removing values from GEN | 1622 // There is no need to clear out_values when removing values from GEN |
| 1694 // set because only those values that are in the GEN set | 1623 // set because only those values that are in the GEN set |
| 1695 // will ever be used. | 1624 // will ever be used. |
| 1696 gen->RemoveAll(aliased_set_->aliased_by_effects()); | 1625 gen->RemoveAll(aliased_set_->aliased_by_effects()); |
| 1697 continue; | 1626 continue; |
| 1698 } | 1627 } |
| 1699 | 1628 |
| 1700 Definition* defn = instr->AsDefinition(); | 1629 Definition* defn = instr->AsDefinition(); |
| 1701 if (defn == NULL) { | 1630 if (defn == NULL) { |
| 1702 continue; | 1631 continue; |
| 1703 } | 1632 } |
| 1704 | 1633 |
| 1705 // For object allocation forward initial values of the fields to | 1634 // For object allocation forward initial values of the fields to |
| 1706 // subsequent loads. For skip final fields. Final fields are | 1635 // subsequent loads. For skip final fields. Final fields are |
| 1707 // initialized in constructor that potentially can be not inlined into | 1636 // initialized in constructor that potentially can be not inlined into |
| 1708 // the function that we are currently optimizing. However at the same | 1637 // the function that we are currently optimizing. However at the same |
| 1709 // time we assume that values of the final fields can be forwarded | 1638 // time we assume that values of the final fields can be forwarded |
| 1710 // across side-effects. If we add 'null' as known values for these | 1639 // across side-effects. If we add 'null' as known values for these |
| 1711 // fields here we will incorrectly propagate this null across | 1640 // fields here we will incorrectly propagate this null across |
| 1712 // constructor invocation. | 1641 // constructor invocation. |
| 1713 AllocateObjectInstr* alloc = instr->AsAllocateObject(); | 1642 AllocateObjectInstr* alloc = instr->AsAllocateObject(); |
| 1714 if ((alloc != NULL)) { | 1643 if ((alloc != NULL)) { |
| 1715 for (Value* use = alloc->input_use_list(); | 1644 for (Value* use = alloc->input_use_list(); use != NULL; |
| 1716 use != NULL; | |
| 1717 use = use->next_use()) { | 1645 use = use->next_use()) { |
| 1718 // Look for all immediate loads from this object. | 1646 // Look for all immediate loads from this object. |
| 1719 if (use->use_index() != 0) { | 1647 if (use->use_index() != 0) { |
| 1720 continue; | 1648 continue; |
| 1721 } | 1649 } |
| 1722 | 1650 |
| 1723 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 1651 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
| 1724 if (load != NULL) { | 1652 if (load != NULL) { |
| 1725 // Found a load. Initialize current value of the field to null for | 1653 // Found a load. Initialize current value of the field to null for |
| 1726 // normal fields, or with type arguments. | 1654 // normal fields, or with type arguments. |
| 1727 | 1655 |
| 1728 // Forward for all fields for non-escaping objects and only | 1656 // Forward for all fields for non-escaping objects and only |
| 1729 // non-final fields and type arguments for escaping ones. | 1657 // non-final fields and type arguments for escaping ones. |
| 1730 if (aliased_set_->CanBeAliased(alloc) && | 1658 if (aliased_set_->CanBeAliased(alloc) && |
| 1731 (load->field() != NULL) && | 1659 (load->field() != NULL) && load->field()->is_final()) { |
| 1732 load->field()->is_final()) { | |
| 1733 continue; | 1660 continue; |
| 1734 } | 1661 } |
| 1735 | 1662 |
| 1736 Definition* forward_def = graph_->constant_null(); | 1663 Definition* forward_def = graph_->constant_null(); |
| 1737 if (alloc->ArgumentCount() > 0) { | 1664 if (alloc->ArgumentCount() > 0) { |
| 1738 ASSERT(alloc->ArgumentCount() == 1); | 1665 ASSERT(alloc->ArgumentCount() == 1); |
| 1739 intptr_t type_args_offset = | 1666 intptr_t type_args_offset = |
| 1740 alloc->cls().type_arguments_field_offset(); | 1667 alloc->cls().type_arguments_field_offset(); |
| 1741 if (load->offset_in_bytes() == type_args_offset) { | 1668 if (load->offset_in_bytes() == type_args_offset) { |
| 1742 forward_def = alloc->PushArgumentAt(0)->value()->definition(); | 1669 forward_def = alloc->PushArgumentAt(0)->value()->definition(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1756 | 1683 |
| 1757 const intptr_t place_id = defn->place_id(); | 1684 const intptr_t place_id = defn->place_id(); |
| 1758 if (gen->Contains(place_id)) { | 1685 if (gen->Contains(place_id)) { |
| 1759 // This is a locally redundant load. | 1686 // This is a locally redundant load. |
| 1760 ASSERT((out_values != NULL) && ((*out_values)[place_id] != NULL)); | 1687 ASSERT((out_values != NULL) && ((*out_values)[place_id] != NULL)); |
| 1761 | 1688 |
| 1762 Definition* replacement = (*out_values)[place_id]; | 1689 Definition* replacement = (*out_values)[place_id]; |
| 1763 graph_->EnsureSSATempIndex(defn, replacement); | 1690 graph_->EnsureSSATempIndex(defn, replacement); |
| 1764 if (FLAG_trace_optimization) { | 1691 if (FLAG_trace_optimization) { |
| 1765 THR_Print("Replacing load v%" Pd " with v%" Pd "\n", | 1692 THR_Print("Replacing load v%" Pd " with v%" Pd "\n", |
| 1766 defn->ssa_temp_index(), | 1693 defn->ssa_temp_index(), replacement->ssa_temp_index()); |
| 1767 replacement->ssa_temp_index()); | |
| 1768 } | 1694 } |
| 1769 | 1695 |
| 1770 defn->ReplaceUsesWith(replacement); | 1696 defn->ReplaceUsesWith(replacement); |
| 1771 instr_it.RemoveCurrentFromGraph(); | 1697 instr_it.RemoveCurrentFromGraph(); |
| 1772 forwarded_ = true; | 1698 forwarded_ = true; |
| 1773 continue; | 1699 continue; |
| 1774 } else if (!kill->Contains(place_id)) { | 1700 } else if (!kill->Contains(place_id)) { |
| 1775 // This is an exposed load: it is the first representative of a | 1701 // This is an exposed load: it is the first representative of a |
| 1776 // given expression id and it is not killed on the path from | 1702 // given expression id and it is not killed on the path from |
| 1777 // the block entry. | 1703 // the block entry. |
| 1778 if (exposed_values == NULL) { | 1704 if (exposed_values == NULL) { |
| 1779 static const intptr_t kMaxExposedValuesInitialSize = 5; | 1705 static const intptr_t kMaxExposedValuesInitialSize = 5; |
| 1780 exposed_values = new(Z) ZoneGrowableArray<Definition*>( | 1706 exposed_values = new (Z) ZoneGrowableArray<Definition*>( |
| 1781 Utils::Minimum(kMaxExposedValuesInitialSize, | 1707 Utils::Minimum(kMaxExposedValuesInitialSize, |
| 1782 aliased_set_->max_place_id())); | 1708 aliased_set_->max_place_id())); |
| 1783 } | 1709 } |
| 1784 | 1710 |
| 1785 exposed_values->Add(defn); | 1711 exposed_values->Add(defn); |
| 1786 } | 1712 } |
| 1787 | 1713 |
| 1788 gen->Add(place_id); | 1714 gen->Add(place_id); |
| 1789 | 1715 |
| 1790 if (out_values == NULL) out_values = CreateBlockOutValues(); | 1716 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1818 | 1744 |
| 1819 out->Remove(to); | 1745 out->Remove(to); |
| 1820 } | 1746 } |
| 1821 | 1747 |
| 1822 out->AddAll(forwarded_loads); | 1748 out->AddAll(forwarded_loads); |
| 1823 } | 1749 } |
| 1824 | 1750 |
| 1825 // Compute OUT sets by propagating them iteratively until fix point | 1751 // Compute OUT sets by propagating them iteratively until fix point |
| 1826 // is reached. | 1752 // is reached. |
| 1827 void ComputeOutSets() { | 1753 void ComputeOutSets() { |
| 1828 BitVector* temp = new(Z) BitVector(Z, aliased_set_->max_place_id()); | 1754 BitVector* temp = new (Z) BitVector(Z, aliased_set_->max_place_id()); |
| 1829 BitVector* forwarded_loads = | 1755 BitVector* forwarded_loads = |
| 1830 new(Z) BitVector(Z, aliased_set_->max_place_id()); | 1756 new (Z) BitVector(Z, aliased_set_->max_place_id()); |
| 1831 BitVector* temp_out = new(Z) BitVector(Z, aliased_set_->max_place_id()); | 1757 BitVector* temp_out = new (Z) BitVector(Z, aliased_set_->max_place_id()); |
| 1832 | 1758 |
| 1833 bool changed = true; | 1759 bool changed = true; |
| 1834 while (changed) { | 1760 while (changed) { |
| 1835 changed = false; | 1761 changed = false; |
| 1836 | 1762 |
| 1837 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 1763 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 1838 !block_it.Done(); | 1764 !block_it.Done(); block_it.Advance()) { |
| 1839 block_it.Advance()) { | |
| 1840 BlockEntryInstr* block = block_it.Current(); | 1765 BlockEntryInstr* block = block_it.Current(); |
| 1841 | 1766 |
| 1842 const intptr_t preorder_number = block->preorder_number(); | 1767 const intptr_t preorder_number = block->preorder_number(); |
| 1843 | 1768 |
| 1844 BitVector* block_in = in_[preorder_number]; | 1769 BitVector* block_in = in_[preorder_number]; |
| 1845 BitVector* block_out = out_[preorder_number]; | 1770 BitVector* block_out = out_[preorder_number]; |
| 1846 BitVector* block_kill = kill_[preorder_number]; | 1771 BitVector* block_kill = kill_[preorder_number]; |
| 1847 BitVector* block_gen = gen_[preorder_number]; | 1772 BitVector* block_gen = gen_[preorder_number]; |
| 1848 | 1773 |
| 1849 // Compute block_in as the intersection of all out(p) where p | 1774 // Compute block_in as the intersection of all out(p) where p |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1873 if (!temp->Equals(*block_in) || (block_out == NULL)) { | 1798 if (!temp->Equals(*block_in) || (block_out == NULL)) { |
| 1874 // If IN set has changed propagate the change to OUT set. | 1799 // If IN set has changed propagate the change to OUT set. |
| 1875 block_in->CopyFrom(temp); | 1800 block_in->CopyFrom(temp); |
| 1876 | 1801 |
| 1877 temp->RemoveAll(block_kill); | 1802 temp->RemoveAll(block_kill); |
| 1878 temp->AddAll(block_gen); | 1803 temp->AddAll(block_gen); |
| 1879 | 1804 |
| 1880 if ((block_out == NULL) || !block_out->Equals(*temp)) { | 1805 if ((block_out == NULL) || !block_out->Equals(*temp)) { |
| 1881 if (block_out == NULL) { | 1806 if (block_out == NULL) { |
| 1882 block_out = out_[preorder_number] = | 1807 block_out = out_[preorder_number] = |
| 1883 new(Z) BitVector(Z, aliased_set_->max_place_id()); | 1808 new (Z) BitVector(Z, aliased_set_->max_place_id()); |
| 1884 } | 1809 } |
| 1885 block_out->CopyFrom(temp); | 1810 block_out->CopyFrom(temp); |
| 1886 changed = true; | 1811 changed = true; |
| 1887 } | 1812 } |
| 1888 } | 1813 } |
| 1889 } | 1814 } |
| 1890 } | 1815 } |
| 1891 } | 1816 } |
| 1892 | 1817 |
| 1893 // Compute out_values mappings by propagating them in reverse postorder once | 1818 // Compute out_values mappings by propagating them in reverse postorder once |
| 1894 // through the graph. Generate phis on back edges where eager merge is | 1819 // through the graph. Generate phis on back edges where eager merge is |
| 1895 // impossible. | 1820 // impossible. |
| 1896 // No replacement is done at this point and thus any out_value[place_id] is | 1821 // No replacement is done at this point and thus any out_value[place_id] is |
| 1897 // changed at most once: from NULL to an actual value. | 1822 // changed at most once: from NULL to an actual value. |
| 1898 // When merging incoming loads we might need to create a phi. | 1823 // When merging incoming loads we might need to create a phi. |
| 1899 // These phis are not inserted at the graph immediately because some of them | 1824 // These phis are not inserted at the graph immediately because some of them |
| 1900 // might become redundant after load forwarding is done. | 1825 // might become redundant after load forwarding is done. |
| 1901 void ComputeOutValues() { | 1826 void ComputeOutValues() { |
| 1902 GrowableArray<PhiInstr*> pending_phis(5); | 1827 GrowableArray<PhiInstr*> pending_phis(5); |
| 1903 ZoneGrowableArray<Definition*>* temp_forwarded_values = NULL; | 1828 ZoneGrowableArray<Definition*>* temp_forwarded_values = NULL; |
| 1904 | 1829 |
| 1905 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 1830 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 1906 !block_it.Done(); | 1831 !block_it.Done(); block_it.Advance()) { |
| 1907 block_it.Advance()) { | |
| 1908 BlockEntryInstr* block = block_it.Current(); | 1832 BlockEntryInstr* block = block_it.Current(); |
| 1909 | 1833 |
| 1910 const bool can_merge_eagerly = CanMergeEagerly(block); | 1834 const bool can_merge_eagerly = CanMergeEagerly(block); |
| 1911 | 1835 |
| 1912 const intptr_t preorder_number = block->preorder_number(); | 1836 const intptr_t preorder_number = block->preorder_number(); |
| 1913 | 1837 |
| 1914 ZoneGrowableArray<Definition*>* block_out_values = | 1838 ZoneGrowableArray<Definition*>* block_out_values = |
| 1915 out_values_[preorder_number]; | 1839 out_values_[preorder_number]; |
| 1916 | 1840 |
| 1917 | 1841 |
| 1918 // If OUT set has changed then we have new values available out of | 1842 // If OUT set has changed then we have new values available out of |
| 1919 // the block. Compute these values creating phi where necessary. | 1843 // the block. Compute these values creating phi where necessary. |
| 1920 for (BitVector::Iterator it(out_[preorder_number]); | 1844 for (BitVector::Iterator it(out_[preorder_number]); !it.Done(); |
| 1921 !it.Done(); | |
| 1922 it.Advance()) { | 1845 it.Advance()) { |
| 1923 const intptr_t place_id = it.Current(); | 1846 const intptr_t place_id = it.Current(); |
| 1924 | 1847 |
| 1925 if (block_out_values == NULL) { | 1848 if (block_out_values == NULL) { |
| 1926 out_values_[preorder_number] = block_out_values = | 1849 out_values_[preorder_number] = block_out_values = |
| 1927 CreateBlockOutValues(); | 1850 CreateBlockOutValues(); |
| 1928 } | 1851 } |
| 1929 | 1852 |
| 1930 if ((*block_out_values)[place_id] == NULL) { | 1853 if ((*block_out_values)[place_id] == NULL) { |
| 1931 ASSERT(block->PredecessorCount() > 0); | 1854 ASSERT(block->PredecessorCount() > 0); |
| 1932 Definition* in_value = can_merge_eagerly ? | 1855 Definition* in_value = |
| 1933 MergeIncomingValues(block, place_id) : NULL; | 1856 can_merge_eagerly ? MergeIncomingValues(block, place_id) : NULL; |
| 1934 if ((in_value == NULL) && | 1857 if ((in_value == NULL) && |
| 1935 (in_[preorder_number]->Contains(place_id))) { | 1858 (in_[preorder_number]->Contains(place_id))) { |
| 1936 PhiInstr* phi = new(Z) PhiInstr(block->AsJoinEntry(), | 1859 PhiInstr* phi = new (Z) |
| 1937 block->PredecessorCount()); | 1860 PhiInstr(block->AsJoinEntry(), block->PredecessorCount()); |
| 1938 phi->set_place_id(place_id); | 1861 phi->set_place_id(place_id); |
| 1939 pending_phis.Add(phi); | 1862 pending_phis.Add(phi); |
| 1940 in_value = phi; | 1863 in_value = phi; |
| 1941 } | 1864 } |
| 1942 (*block_out_values)[place_id] = in_value; | 1865 (*block_out_values)[place_id] = in_value; |
| 1943 } | 1866 } |
| 1944 } | 1867 } |
| 1945 | 1868 |
| 1946 // If the block has outgoing phi moves perform them. Use temporary list | 1869 // If the block has outgoing phi moves perform them. Use temporary list |
| 1947 // of values to ensure that cyclic moves are performed correctly. | 1870 // of values to ensure that cyclic moves are performed correctly. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2000 } | 1923 } |
| 2001 } | 1924 } |
| 2002 return true; | 1925 return true; |
| 2003 } | 1926 } |
| 2004 | 1927 |
| 2005 void MarkLoopInvariantLoads() { | 1928 void MarkLoopInvariantLoads() { |
| 2006 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = | 1929 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = |
| 2007 graph_->LoopHeaders(); | 1930 graph_->LoopHeaders(); |
| 2008 | 1931 |
| 2009 ZoneGrowableArray<BitVector*>* invariant_loads = | 1932 ZoneGrowableArray<BitVector*>* invariant_loads = |
| 2010 new(Z) ZoneGrowableArray<BitVector*>(loop_headers.length()); | 1933 new (Z) ZoneGrowableArray<BitVector*>(loop_headers.length()); |
| 2011 | 1934 |
| 2012 for (intptr_t i = 0; i < loop_headers.length(); i++) { | 1935 for (intptr_t i = 0; i < loop_headers.length(); i++) { |
| 2013 BlockEntryInstr* header = loop_headers[i]; | 1936 BlockEntryInstr* header = loop_headers[i]; |
| 2014 BlockEntryInstr* pre_header = header->ImmediateDominator(); | 1937 BlockEntryInstr* pre_header = header->ImmediateDominator(); |
| 2015 if (pre_header == NULL) { | 1938 if (pre_header == NULL) { |
| 2016 invariant_loads->Add(NULL); | 1939 invariant_loads->Add(NULL); |
| 2017 continue; | 1940 continue; |
| 2018 } | 1941 } |
| 2019 | 1942 |
| 2020 BitVector* loop_gen = new(Z) BitVector(Z, aliased_set_->max_place_id()); | 1943 BitVector* loop_gen = new (Z) BitVector(Z, aliased_set_->max_place_id()); |
| 2021 for (BitVector::Iterator loop_it(header->loop_info()); | 1944 for (BitVector::Iterator loop_it(header->loop_info()); !loop_it.Done(); |
| 2022 !loop_it.Done(); | |
| 2023 loop_it.Advance()) { | 1945 loop_it.Advance()) { |
| 2024 const intptr_t preorder_number = loop_it.Current(); | 1946 const intptr_t preorder_number = loop_it.Current(); |
| 2025 loop_gen->AddAll(gen_[preorder_number]); | 1947 loop_gen->AddAll(gen_[preorder_number]); |
| 2026 } | 1948 } |
| 2027 | 1949 |
| 2028 for (BitVector::Iterator loop_it(header->loop_info()); | 1950 for (BitVector::Iterator loop_it(header->loop_info()); !loop_it.Done(); |
| 2029 !loop_it.Done(); | |
| 2030 loop_it.Advance()) { | 1951 loop_it.Advance()) { |
| 2031 const intptr_t preorder_number = loop_it.Current(); | 1952 const intptr_t preorder_number = loop_it.Current(); |
| 2032 loop_gen->RemoveAll(kill_[preorder_number]); | 1953 loop_gen->RemoveAll(kill_[preorder_number]); |
| 2033 } | 1954 } |
| 2034 | 1955 |
| 2035 if (FLAG_trace_optimization) { | 1956 if (FLAG_trace_optimization) { |
| 2036 for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) { | 1957 for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) { |
| 2037 THR_Print("place %s is loop invariant for B%" Pd "\n", | 1958 THR_Print("place %s is loop invariant for B%" Pd "\n", |
| 2038 aliased_set_->places()[it.Current()]->ToCString(), | 1959 aliased_set_->places()[it.Current()]->ToCString(), |
| 2039 header->block_id()); | 1960 header->block_id()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2066 incoming = kDifferentValuesMarker; | 1987 incoming = kDifferentValuesMarker; |
| 2067 } | 1988 } |
| 2068 } | 1989 } |
| 2069 | 1990 |
| 2070 if (incoming != kDifferentValuesMarker) { | 1991 if (incoming != kDifferentValuesMarker) { |
| 2071 ASSERT(incoming != NULL); | 1992 ASSERT(incoming != NULL); |
| 2072 return incoming; | 1993 return incoming; |
| 2073 } | 1994 } |
| 2074 | 1995 |
| 2075 // Incoming values are different. Phi is required to merge. | 1996 // Incoming values are different. Phi is required to merge. |
| 2076 PhiInstr* phi = new(Z) PhiInstr( | 1997 PhiInstr* phi = |
| 2077 block->AsJoinEntry(), block->PredecessorCount()); | 1998 new (Z) PhiInstr(block->AsJoinEntry(), block->PredecessorCount()); |
| 2078 phi->set_place_id(place_id); | 1999 phi->set_place_id(place_id); |
| 2079 FillPhiInputs(phi); | 2000 FillPhiInputs(phi); |
| 2080 return phi; | 2001 return phi; |
| 2081 } | 2002 } |
| 2082 | 2003 |
| 2083 void FillPhiInputs(PhiInstr* phi) { | 2004 void FillPhiInputs(PhiInstr* phi) { |
| 2084 BlockEntryInstr* block = phi->GetBlock(); | 2005 BlockEntryInstr* block = phi->GetBlock(); |
| 2085 const intptr_t place_id = phi->place_id(); | 2006 const intptr_t place_id = phi->place_id(); |
| 2086 | 2007 |
| 2087 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 2008 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 2088 BlockEntryInstr* pred = block->PredecessorAt(i); | 2009 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 2089 ZoneGrowableArray<Definition*>* pred_out_values = | 2010 ZoneGrowableArray<Definition*>* pred_out_values = |
| 2090 out_values_[pred->preorder_number()]; | 2011 out_values_[pred->preorder_number()]; |
| 2091 ASSERT((*pred_out_values)[place_id] != NULL); | 2012 ASSERT((*pred_out_values)[place_id] != NULL); |
| 2092 | 2013 |
| 2093 // Sets of outgoing values are not linked into use lists so | 2014 // Sets of outgoing values are not linked into use lists so |
| 2094 // they might contain values that were replaced and removed | 2015 // they might contain values that were replaced and removed |
| 2095 // from the graph by this iteration. | 2016 // from the graph by this iteration. |
| 2096 // To prevent using them we additionally mark definitions themselves | 2017 // To prevent using them we additionally mark definitions themselves |
| 2097 // as replaced and store a pointer to the replacement. | 2018 // as replaced and store a pointer to the replacement. |
| 2098 Definition* replacement = (*pred_out_values)[place_id]->Replacement(); | 2019 Definition* replacement = (*pred_out_values)[place_id]->Replacement(); |
| 2099 Value* input = new(Z) Value(replacement); | 2020 Value* input = new (Z) Value(replacement); |
| 2100 phi->SetInputAt(i, input); | 2021 phi->SetInputAt(i, input); |
| 2101 replacement->AddInputUse(input); | 2022 replacement->AddInputUse(input); |
| 2102 } | 2023 } |
| 2103 | 2024 |
| 2104 graph_->AllocateSSAIndexes(phi); | 2025 graph_->AllocateSSAIndexes(phi); |
| 2105 phis_.Add(phi); // Postpone phi insertion until after load forwarding. | 2026 phis_.Add(phi); // Postpone phi insertion until after load forwarding. |
| 2106 | 2027 |
| 2107 if (FLAG_support_il_printer && FLAG_trace_load_optimization) { | 2028 if (FLAG_support_il_printer && FLAG_trace_load_optimization) { |
| 2108 THR_Print("created pending phi %s for %s at B%" Pd "\n", | 2029 THR_Print("created pending phi %s for %s at B%" Pd "\n", phi->ToCString(), |
| 2109 phi->ToCString(), | |
| 2110 aliased_set_->places()[place_id]->ToCString(), | 2030 aliased_set_->places()[place_id]->ToCString(), |
| 2111 block->block_id()); | 2031 block->block_id()); |
| 2112 } | 2032 } |
| 2113 } | 2033 } |
| 2114 | 2034 |
| 2115 // Iterate over basic blocks and replace exposed loads with incoming | 2035 // Iterate over basic blocks and replace exposed loads with incoming |
| 2116 // values. | 2036 // values. |
| 2117 void ForwardLoads() { | 2037 void ForwardLoads() { |
| 2118 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); | 2038 for (BlockIterator block_it = graph_->reverse_postorder_iterator(); |
| 2119 !block_it.Done(); | 2039 !block_it.Done(); block_it.Advance()) { |
| 2120 block_it.Advance()) { | |
| 2121 BlockEntryInstr* block = block_it.Current(); | 2040 BlockEntryInstr* block = block_it.Current(); |
| 2122 | 2041 |
| 2123 ZoneGrowableArray<Definition*>* loads = | 2042 ZoneGrowableArray<Definition*>* loads = |
| 2124 exposed_values_[block->preorder_number()]; | 2043 exposed_values_[block->preorder_number()]; |
| 2125 if (loads == NULL) continue; // No exposed loads. | 2044 if (loads == NULL) continue; // No exposed loads. |
| 2126 | 2045 |
| 2127 BitVector* in = in_[block->preorder_number()]; | 2046 BitVector* in = in_[block->preorder_number()]; |
| 2128 | 2047 |
| 2129 for (intptr_t i = 0; i < loads->length(); i++) { | 2048 for (intptr_t i = 0; i < loads->length(); i++) { |
| 2130 Definition* load = (*loads)[i]; | 2049 Definition* load = (*loads)[i]; |
| 2131 if (!in->Contains(load->place_id())) continue; // No incoming value. | 2050 if (!in->Contains(load->place_id())) continue; // No incoming value. |
| 2132 | 2051 |
| 2133 Definition* replacement = MergeIncomingValues(block, load->place_id()); | 2052 Definition* replacement = MergeIncomingValues(block, load->place_id()); |
| 2134 ASSERT(replacement != NULL); | 2053 ASSERT(replacement != NULL); |
| 2135 | 2054 |
| 2136 // Sets of outgoing values are not linked into use lists so | 2055 // Sets of outgoing values are not linked into use lists so |
| 2137 // they might contain values that were replace and removed | 2056 // they might contain values that were replace and removed |
| 2138 // from the graph by this iteration. | 2057 // from the graph by this iteration. |
| 2139 // To prevent using them we additionally mark definitions themselves | 2058 // To prevent using them we additionally mark definitions themselves |
| 2140 // as replaced and store a pointer to the replacement. | 2059 // as replaced and store a pointer to the replacement. |
| 2141 replacement = replacement->Replacement(); | 2060 replacement = replacement->Replacement(); |
| 2142 | 2061 |
| 2143 if (load != replacement) { | 2062 if (load != replacement) { |
| 2144 graph_->EnsureSSATempIndex(load, replacement); | 2063 graph_->EnsureSSATempIndex(load, replacement); |
| 2145 | 2064 |
| 2146 if (FLAG_trace_optimization) { | 2065 if (FLAG_trace_optimization) { |
| 2147 THR_Print("Replacing load v%" Pd " with v%" Pd "\n", | 2066 THR_Print("Replacing load v%" Pd " with v%" Pd "\n", |
| 2148 load->ssa_temp_index(), | 2067 load->ssa_temp_index(), replacement->ssa_temp_index()); |
| 2149 replacement->ssa_temp_index()); | |
| 2150 } | 2068 } |
| 2151 | 2069 |
| 2152 load->ReplaceUsesWith(replacement); | 2070 load->ReplaceUsesWith(replacement); |
| 2153 load->RemoveFromGraph(); | 2071 load->RemoveFromGraph(); |
| 2154 load->SetReplacement(replacement); | 2072 load->SetReplacement(replacement); |
| 2155 forwarded_ = true; | 2073 forwarded_ = true; |
| 2156 } | 2074 } |
| 2157 } | 2075 } |
| 2158 } | 2076 } |
| 2159 } | 2077 } |
| 2160 | 2078 |
| 2161 // Check if the given phi take the same value on all code paths. | 2079 // Check if the given phi take the same value on all code paths. |
| 2162 // Eliminate it as redundant if this is the case. | 2080 // Eliminate it as redundant if this is the case. |
| 2163 // When analyzing phi operands assumes that only generated during | 2081 // When analyzing phi operands assumes that only generated during |
| 2164 // this load phase can be redundant. They can be distinguished because | 2082 // this load phase can be redundant. They can be distinguished because |
| 2165 // they are not marked alive. | 2083 // they are not marked alive. |
| 2166 // TODO(vegorov): move this into a separate phase over all phis. | 2084 // TODO(vegorov): move this into a separate phase over all phis. |
| 2167 bool EliminateRedundantPhi(PhiInstr* phi) { | 2085 bool EliminateRedundantPhi(PhiInstr* phi) { |
| 2168 Definition* value = NULL; // Possible value of this phi. | 2086 Definition* value = NULL; // Possible value of this phi. |
| 2169 | 2087 |
| 2170 worklist_.Clear(); | 2088 worklist_.Clear(); |
| 2171 if (in_worklist_ == NULL) { | 2089 if (in_worklist_ == NULL) { |
| 2172 in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index()); | 2090 in_worklist_ = new (Z) BitVector(Z, graph_->current_ssa_temp_index()); |
| 2173 } else { | 2091 } else { |
| 2174 in_worklist_->Clear(); | 2092 in_worklist_->Clear(); |
| 2175 } | 2093 } |
| 2176 | 2094 |
| 2177 worklist_.Add(phi); | 2095 worklist_.Add(phi); |
| 2178 in_worklist_->Add(phi->ssa_temp_index()); | 2096 in_worklist_->Add(phi->ssa_temp_index()); |
| 2179 | 2097 |
| 2180 for (intptr_t i = 0; i < worklist_.length(); i++) { | 2098 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 2181 PhiInstr* phi = worklist_[i]; | 2099 PhiInstr* phi = worklist_[i]; |
| 2182 | 2100 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2208 worklist_[i]->ReplaceUsesWith(value); | 2126 worklist_[i]->ReplaceUsesWith(value); |
| 2209 } | 2127 } |
| 2210 | 2128 |
| 2211 return true; | 2129 return true; |
| 2212 } | 2130 } |
| 2213 | 2131 |
| 2214 // Returns true if definitions are congruent assuming their inputs | 2132 // Returns true if definitions are congruent assuming their inputs |
| 2215 // are congruent. | 2133 // are congruent. |
| 2216 bool CanBeCongruent(Definition* a, Definition* b) { | 2134 bool CanBeCongruent(Definition* a, Definition* b) { |
| 2217 return (a->tag() == b->tag()) && | 2135 return (a->tag() == b->tag()) && |
| 2218 ((a->IsPhi() && (a->GetBlock() == b->GetBlock())) || | 2136 ((a->IsPhi() && (a->GetBlock() == b->GetBlock())) || |
| 2219 (a->AllowsCSE() && a->Dependencies().IsNone() && | 2137 (a->AllowsCSE() && a->Dependencies().IsNone() && |
| 2220 a->AttributesEqual(b))); | 2138 a->AttributesEqual(b))); |
| 2221 } | 2139 } |
| 2222 | 2140 |
| 2223 // Given two definitions check if they are congruent under assumption that | 2141 // Given two definitions check if they are congruent under assumption that |
| 2224 // their inputs will be proven congruent. If they are - add them to the | 2142 // their inputs will be proven congruent. If they are - add them to the |
| 2225 // worklist to check their inputs' congruency. | 2143 // worklist to check their inputs' congruency. |
| 2226 // Returns true if pair was added to the worklist or is already in the | 2144 // Returns true if pair was added to the worklist or is already in the |
| 2227 // worklist and false if a and b are not congruent. | 2145 // worklist and false if a and b are not congruent. |
| 2228 bool AddPairToCongruencyWorklist(Definition* a, Definition* b) { | 2146 bool AddPairToCongruencyWorklist(Definition* a, Definition* b) { |
| 2229 if (!CanBeCongruent(a, b)) { | 2147 if (!CanBeCongruent(a, b)) { |
| 2230 return false; | 2148 return false; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2264 } | 2182 } |
| 2265 return true; | 2183 return true; |
| 2266 } | 2184 } |
| 2267 | 2185 |
| 2268 // Returns true if instruction dom dominates instruction other. | 2186 // Returns true if instruction dom dominates instruction other. |
| 2269 static bool Dominates(Instruction* dom, Instruction* other) { | 2187 static bool Dominates(Instruction* dom, Instruction* other) { |
| 2270 BlockEntryInstr* dom_block = dom->GetBlock(); | 2188 BlockEntryInstr* dom_block = dom->GetBlock(); |
| 2271 BlockEntryInstr* other_block = other->GetBlock(); | 2189 BlockEntryInstr* other_block = other->GetBlock(); |
| 2272 | 2190 |
| 2273 if (dom_block == other_block) { | 2191 if (dom_block == other_block) { |
| 2274 for (Instruction* current = dom->next(); | 2192 for (Instruction* current = dom->next(); current != NULL; |
| 2275 current != NULL; | |
| 2276 current = current->next()) { | 2193 current = current->next()) { |
| 2277 if (current == other) { | 2194 if (current == other) { |
| 2278 return true; | 2195 return true; |
| 2279 } | 2196 } |
| 2280 } | 2197 } |
| 2281 return false; | 2198 return false; |
| 2282 } | 2199 } |
| 2283 | 2200 |
| 2284 return dom_block->Dominates(other_block); | 2201 return dom_block->Dominates(other_block); |
| 2285 } | 2202 } |
| 2286 | 2203 |
| 2287 // Replace the given phi with another if they are congruent. | 2204 // Replace the given phi with another if they are congruent. |
| 2288 // Returns true if succeeds. | 2205 // Returns true if succeeds. |
| 2289 bool ReplacePhiWith(PhiInstr* phi, PhiInstr* replacement) { | 2206 bool ReplacePhiWith(PhiInstr* phi, PhiInstr* replacement) { |
| 2290 ASSERT(phi->InputCount() == replacement->InputCount()); | 2207 ASSERT(phi->InputCount() == replacement->InputCount()); |
| 2291 ASSERT(phi->block() == replacement->block()); | 2208 ASSERT(phi->block() == replacement->block()); |
| 2292 | 2209 |
| 2293 congruency_worklist_.Clear(); | 2210 congruency_worklist_.Clear(); |
| 2294 if (in_worklist_ == NULL) { | 2211 if (in_worklist_ == NULL) { |
| 2295 in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index()); | 2212 in_worklist_ = new (Z) BitVector(Z, graph_->current_ssa_temp_index()); |
| 2296 } else { | 2213 } else { |
| 2297 in_worklist_->Clear(); | 2214 in_worklist_->Clear(); |
| 2298 } | 2215 } |
| 2299 | 2216 |
| 2300 // During the comparison worklist contains pairs of definitions to be | 2217 // During the comparison worklist contains pairs of definitions to be |
| 2301 // compared. | 2218 // compared. |
| 2302 if (!AddPairToCongruencyWorklist(phi, replacement)) { | 2219 if (!AddPairToCongruencyWorklist(phi, replacement)) { |
| 2303 return false; | 2220 return false; |
| 2304 } | 2221 } |
| 2305 | 2222 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2326 if (!a->IsPhi()) { | 2243 if (!a->IsPhi()) { |
| 2327 if (Dominates(a, b)) { | 2244 if (Dominates(a, b)) { |
| 2328 Definition* t = a; | 2245 Definition* t = a; |
| 2329 a = b; | 2246 a = b; |
| 2330 b = t; | 2247 b = t; |
| 2331 } | 2248 } |
| 2332 ASSERT(Dominates(b, a)); | 2249 ASSERT(Dominates(b, a)); |
| 2333 } | 2250 } |
| 2334 | 2251 |
| 2335 if (FLAG_support_il_printer && FLAG_trace_load_optimization) { | 2252 if (FLAG_support_il_printer && FLAG_trace_load_optimization) { |
| 2336 THR_Print("Replacing %s with congruent %s\n", | 2253 THR_Print("Replacing %s with congruent %s\n", a->ToCString(), |
| 2337 a->ToCString(), | |
| 2338 b->ToCString()); | 2254 b->ToCString()); |
| 2339 } | 2255 } |
| 2340 | 2256 |
| 2341 a->ReplaceUsesWith(b); | 2257 a->ReplaceUsesWith(b); |
| 2342 if (a->IsPhi()) { | 2258 if (a->IsPhi()) { |
| 2343 // We might be replacing a phi introduced by the load forwarding | 2259 // We might be replacing a phi introduced by the load forwarding |
| 2344 // that is not inserted in the graph yet. | 2260 // that is not inserted in the graph yet. |
| 2345 ASSERT(b->IsPhi()); | 2261 ASSERT(b->IsPhi()); |
| 2346 PhiInstr* phi_a = a->AsPhi(); | 2262 PhiInstr* phi_a = a->AsPhi(); |
| 2347 if (phi_a->is_alive()) { | 2263 if (phi_a->is_alive()) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 for (intptr_t i = 0; i < phis_.length(); i++) { | 2306 for (intptr_t i = 0; i < phis_.length(); i++) { |
| 2391 PhiInstr* phi = phis_[i]; | 2307 PhiInstr* phi = phis_[i]; |
| 2392 if ((phi != NULL) && (!phi->HasUses() || !EmitPhi(phi))) { | 2308 if ((phi != NULL) && (!phi->HasUses() || !EmitPhi(phi))) { |
| 2393 phi->UnuseAllInputs(); | 2309 phi->UnuseAllInputs(); |
| 2394 } | 2310 } |
| 2395 } | 2311 } |
| 2396 } | 2312 } |
| 2397 | 2313 |
| 2398 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { | 2314 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { |
| 2399 ZoneGrowableArray<Definition*>* out = | 2315 ZoneGrowableArray<Definition*>* out = |
| 2400 new(Z) ZoneGrowableArray<Definition*>(aliased_set_->max_place_id()); | 2316 new (Z) ZoneGrowableArray<Definition*>(aliased_set_->max_place_id()); |
| 2401 for (intptr_t i = 0; i < aliased_set_->max_place_id(); i++) { | 2317 for (intptr_t i = 0; i < aliased_set_->max_place_id(); i++) { |
| 2402 out->Add(NULL); | 2318 out->Add(NULL); |
| 2403 } | 2319 } |
| 2404 return out; | 2320 return out; |
| 2405 } | 2321 } |
| 2406 | 2322 |
| 2407 FlowGraph* graph_; | 2323 FlowGraph* graph_; |
| 2408 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_; | 2324 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_; |
| 2409 | 2325 |
| 2410 // Mapping between field offsets in words and expression ids of loads from | 2326 // Mapping between field offsets in words and expression ids of loads from |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2449 changed = LoadOptimizer::OptimizeGraph(graph) || changed; | 2365 changed = LoadOptimizer::OptimizeGraph(graph) || changed; |
| 2450 } | 2366 } |
| 2451 | 2367 |
| 2452 CSEInstructionMap map; | 2368 CSEInstructionMap map; |
| 2453 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; | 2369 changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed; |
| 2454 | 2370 |
| 2455 return changed; | 2371 return changed; |
| 2456 } | 2372 } |
| 2457 | 2373 |
| 2458 | 2374 |
| 2459 bool DominatorBasedCSE::OptimizeRecursive( | 2375 bool DominatorBasedCSE::OptimizeRecursive(FlowGraph* graph, |
| 2460 FlowGraph* graph, | 2376 BlockEntryInstr* block, |
| 2461 BlockEntryInstr* block, | 2377 CSEInstructionMap* map) { |
| 2462 CSEInstructionMap* map) { | |
| 2463 bool changed = false; | 2378 bool changed = false; |
| 2464 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2379 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 2465 Instruction* current = it.Current(); | 2380 Instruction* current = it.Current(); |
| 2466 if (current->AllowsCSE()) { | 2381 if (current->AllowsCSE()) { |
| 2467 Instruction* replacement = map->Lookup(current); | 2382 Instruction* replacement = map->Lookup(current); |
| 2468 if ((replacement != NULL) && | 2383 if ((replacement != NULL) && |
| 2469 graph->block_effects()->IsAvailableAt(replacement, block)) { | 2384 graph->block_effects()->IsAvailableAt(replacement, block)) { |
| 2470 // Replace current with lookup result. | 2385 // Replace current with lookup result. |
| 2471 graph->ReplaceCurrentInstruction(&it, current, replacement); | 2386 graph->ReplaceCurrentInstruction(&it, current, replacement); |
| 2472 changed = true; | 2387 changed = true; |
| 2473 continue; | 2388 continue; |
| 2474 } | 2389 } |
| 2475 | 2390 |
| 2476 // For simplicity we assume that instruction either does not depend on | 2391 // For simplicity we assume that instruction either does not depend on |
| 2477 // anything or does not affect anything. If this is not the case then | 2392 // anything or does not affect anything. If this is not the case then |
| 2478 // we should first remove affected instructions from the map and | 2393 // we should first remove affected instructions from the map and |
| 2479 // then add instruction to the map so that it does not kill itself. | 2394 // then add instruction to the map so that it does not kill itself. |
| 2480 ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); | 2395 ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone()); |
| 2481 map->Insert(current); | 2396 map->Insert(current); |
| 2482 } | 2397 } |
| 2483 | 2398 |
| 2484 map->RemoveAffected(current->Effects()); | 2399 map->RemoveAffected(current->Effects()); |
| 2485 } | 2400 } |
| 2486 | 2401 |
| 2487 // Process children in the dominator tree recursively. | 2402 // Process children in the dominator tree recursively. |
| 2488 intptr_t num_children = block->dominated_blocks().length(); | 2403 intptr_t num_children = block->dominated_blocks().length(); |
| 2489 for (intptr_t i = 0; i < num_children; ++i) { | 2404 for (intptr_t i = 0; i < num_children; ++i) { |
| 2490 BlockEntryInstr* child = block->dominated_blocks()[i]; | 2405 BlockEntryInstr* child = block->dominated_blocks()[i]; |
| 2491 if (i < num_children - 1) { | 2406 if (i < num_children - 1) { |
| 2492 // Copy map. | 2407 // Copy map. |
| 2493 CSEInstructionMap child_map(*map); | 2408 CSEInstructionMap child_map(*map); |
| 2494 changed = OptimizeRecursive(graph, child, &child_map) || changed; | 2409 changed = OptimizeRecursive(graph, child, &child_map) || changed; |
| 2495 } else { | 2410 } else { |
| 2496 // Reuse map for the last child. | 2411 // Reuse map for the last child. |
| 2497 changed = OptimizeRecursive(graph, child, map) || changed; | 2412 changed = OptimizeRecursive(graph, child, map) || changed; |
| 2498 } | 2413 } |
| 2499 } | 2414 } |
| 2500 return changed; | 2415 return changed; |
| 2501 } | 2416 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2518 } | 2433 } |
| 2519 | 2434 |
| 2520 static void OptimizeGraph(FlowGraph* graph) { | 2435 static void OptimizeGraph(FlowGraph* graph) { |
| 2521 ASSERT(FLAG_load_cse); | 2436 ASSERT(FLAG_load_cse); |
| 2522 if (FLAG_trace_load_optimization) { | 2437 if (FLAG_trace_load_optimization) { |
| 2523 FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph); | 2438 FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph); |
| 2524 } | 2439 } |
| 2525 | 2440 |
| 2526 // For now, bail out for large functions to avoid OOM situations. | 2441 // For now, bail out for large functions to avoid OOM situations. |
| 2527 // TODO(fschneider): Fix the memory consumption issue. | 2442 // TODO(fschneider): Fix the memory consumption issue. |
| 2528 intptr_t function_length = | 2443 intptr_t function_length = graph->function().end_token_pos().Pos() - |
| 2529 graph->function().end_token_pos().Pos() - | 2444 graph->function().token_pos().Pos(); |
| 2530 graph->function().token_pos().Pos(); | |
| 2531 if (function_length >= FLAG_huge_method_cutoff_in_tokens) { | 2445 if (function_length >= FLAG_huge_method_cutoff_in_tokens) { |
| 2532 return; | 2446 return; |
| 2533 } | 2447 } |
| 2534 | 2448 |
| 2535 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; | 2449 DirectChainedHashMap<PointerKeyValueTrait<Place> > map; |
| 2536 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores); | 2450 AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores); |
| 2537 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { | 2451 if ((aliased_set != NULL) && !aliased_set->IsEmpty()) { |
| 2538 StoreOptimizer store_optimizer(graph, aliased_set, &map); | 2452 StoreOptimizer store_optimizer(graph, aliased_set, &map); |
| 2539 store_optimizer.Optimize(); | 2453 store_optimizer.Optimize(); |
| 2540 } | 2454 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2563 case Instruction::kStoreStaticField: | 2477 case Instruction::kStoreStaticField: |
| 2564 return true; | 2478 return true; |
| 2565 default: | 2479 default: |
| 2566 UNREACHABLE(); | 2480 UNREACHABLE(); |
| 2567 return false; | 2481 return false; |
| 2568 } | 2482 } |
| 2569 } | 2483 } |
| 2570 | 2484 |
| 2571 virtual void ComputeInitialSets() { | 2485 virtual void ComputeInitialSets() { |
| 2572 Zone* zone = graph_->zone(); | 2486 Zone* zone = graph_->zone(); |
| 2573 BitVector* all_places = new(zone) BitVector(zone, | 2487 BitVector* all_places = |
| 2574 aliased_set_->max_place_id()); | 2488 new (zone) BitVector(zone, aliased_set_->max_place_id()); |
| 2575 all_places->SetAll(); | 2489 all_places->SetAll(); |
| 2576 for (BlockIterator block_it = graph_->postorder_iterator(); | 2490 for (BlockIterator block_it = graph_->postorder_iterator(); |
| 2577 !block_it.Done(); | 2491 !block_it.Done(); block_it.Advance()) { |
| 2578 block_it.Advance()) { | |
| 2579 BlockEntryInstr* block = block_it.Current(); | 2492 BlockEntryInstr* block = block_it.Current(); |
| 2580 const intptr_t postorder_number = block->postorder_number(); | 2493 const intptr_t postorder_number = block->postorder_number(); |
| 2581 | 2494 |
| 2582 BitVector* kill = kill_[postorder_number]; | 2495 BitVector* kill = kill_[postorder_number]; |
| 2583 BitVector* live_in = live_in_[postorder_number]; | 2496 BitVector* live_in = live_in_[postorder_number]; |
| 2584 BitVector* live_out = live_out_[postorder_number]; | 2497 BitVector* live_out = live_out_[postorder_number]; |
| 2585 | 2498 |
| 2586 ZoneGrowableArray<Instruction*>* exposed_stores = NULL; | 2499 ZoneGrowableArray<Instruction*>* exposed_stores = NULL; |
| 2587 | 2500 |
| 2588 // Iterate backwards starting at the last instruction. | 2501 // Iterate backwards starting at the last instruction. |
| 2589 for (BackwardInstructionIterator instr_it(block); | 2502 for (BackwardInstructionIterator instr_it(block); !instr_it.Done(); |
| 2590 !instr_it.Done(); | |
| 2591 instr_it.Advance()) { | 2503 instr_it.Advance()) { |
| 2592 Instruction* instr = instr_it.Current(); | 2504 Instruction* instr = instr_it.Current(); |
| 2593 | 2505 |
| 2594 bool is_load = false; | 2506 bool is_load = false; |
| 2595 bool is_store = false; | 2507 bool is_store = false; |
| 2596 Place place(instr, &is_load, &is_store); | 2508 Place place(instr, &is_load, &is_store); |
| 2597 if (place.IsImmutableField()) { | 2509 if (place.IsImmutableField()) { |
| 2598 // Loads/stores of final fields do not participate. | 2510 // Loads/stores of final fields do not participate. |
| 2599 continue; | 2511 continue; |
| 2600 } | 2512 } |
| 2601 | 2513 |
| 2602 // Handle stores. | 2514 // Handle stores. |
| 2603 if (is_store) { | 2515 if (is_store) { |
| 2604 if (kill->Contains(instr->place_id())) { | 2516 if (kill->Contains(instr->place_id())) { |
| 2605 if (!live_in->Contains(instr->place_id()) && | 2517 if (!live_in->Contains(instr->place_id()) && |
| 2606 CanEliminateStore(instr)) { | 2518 CanEliminateStore(instr)) { |
| 2607 if (FLAG_trace_optimization) { | 2519 if (FLAG_trace_optimization) { |
| 2608 THR_Print( | 2520 THR_Print("Removing dead store to place %" Pd " in block B%" Pd |
| 2609 "Removing dead store to place %" Pd " in block B%" Pd "\n", | 2521 "\n", |
| 2610 instr->place_id(), block->block_id()); | 2522 instr->place_id(), block->block_id()); |
| 2611 } | 2523 } |
| 2612 instr_it.RemoveCurrentFromGraph(); | 2524 instr_it.RemoveCurrentFromGraph(); |
| 2613 } | 2525 } |
| 2614 } else if (!live_in->Contains(instr->place_id())) { | 2526 } else if (!live_in->Contains(instr->place_id())) { |
| 2615 // Mark this store as down-ward exposed: They are the only | 2527 // Mark this store as down-ward exposed: They are the only |
| 2616 // candidates for the global store elimination. | 2528 // candidates for the global store elimination. |
| 2617 if (exposed_stores == NULL) { | 2529 if (exposed_stores == NULL) { |
| 2618 const intptr_t kMaxExposedStoresInitialSize = 5; | 2530 const intptr_t kMaxExposedStoresInitialSize = 5; |
| 2619 exposed_stores = new(zone) ZoneGrowableArray<Instruction*>( | 2531 exposed_stores = new (zone) ZoneGrowableArray<Instruction*>( |
| 2620 Utils::Minimum(kMaxExposedStoresInitialSize, | 2532 Utils::Minimum(kMaxExposedStoresInitialSize, |
| 2621 aliased_set_->max_place_id())); | 2533 aliased_set_->max_place_id())); |
| 2622 } | 2534 } |
| 2623 exposed_stores->Add(instr); | 2535 exposed_stores->Add(instr); |
| 2624 } | 2536 } |
| 2625 // Interfering stores kill only loads from the same place. | 2537 // Interfering stores kill only loads from the same place. |
| 2626 kill->Add(instr->place_id()); | 2538 kill->Add(instr->place_id()); |
| 2627 live_in->Remove(instr->place_id()); | 2539 live_in->Remove(instr->place_id()); |
| 2628 continue; | 2540 continue; |
| 2629 } | 2541 } |
| 2630 | 2542 |
| 2631 // Handle side effects, deoptimization and function return. | 2543 // Handle side effects, deoptimization and function return. |
| 2632 if (!instr->Effects().IsNone() || | 2544 if (!instr->Effects().IsNone() || instr->CanDeoptimize() || |
| 2633 instr->CanDeoptimize() || | 2545 instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { |
| 2634 instr->IsThrow() || | |
| 2635 instr->IsReThrow() || | |
| 2636 instr->IsReturn()) { | |
| 2637 // Instructions that return from the function, instructions with side | 2546 // Instructions that return from the function, instructions with side |
| 2638 // effects and instructions that can deoptimize are considered as | 2547 // effects and instructions that can deoptimize are considered as |
| 2639 // loads from all places. | 2548 // loads from all places. |
| 2640 live_in->CopyFrom(all_places); | 2549 live_in->CopyFrom(all_places); |
| 2641 if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { | 2550 if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) { |
| 2642 // Initialize live-out for exit blocks since it won't be computed | 2551 // Initialize live-out for exit blocks since it won't be computed |
| 2643 // otherwise during the fixed point iteration. | 2552 // otherwise during the fixed point iteration. |
| 2644 live_out->CopyFrom(all_places); | 2553 live_out->CopyFrom(all_places); |
| 2645 } | 2554 } |
| 2646 continue; | 2555 continue; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2658 } | 2567 } |
| 2659 if (FLAG_trace_load_optimization) { | 2568 if (FLAG_trace_load_optimization) { |
| 2660 Dump(); | 2569 Dump(); |
| 2661 THR_Print("---\n"); | 2570 THR_Print("---\n"); |
| 2662 } | 2571 } |
| 2663 } | 2572 } |
| 2664 | 2573 |
| 2665 void EliminateDeadStores() { | 2574 void EliminateDeadStores() { |
| 2666 // Iteration order does not matter here. | 2575 // Iteration order does not matter here. |
| 2667 for (BlockIterator block_it = graph_->postorder_iterator(); | 2576 for (BlockIterator block_it = graph_->postorder_iterator(); |
| 2668 !block_it.Done(); | 2577 !block_it.Done(); block_it.Advance()) { |
| 2669 block_it.Advance()) { | |
| 2670 BlockEntryInstr* block = block_it.Current(); | 2578 BlockEntryInstr* block = block_it.Current(); |
| 2671 const intptr_t postorder_number = block->postorder_number(); | 2579 const intptr_t postorder_number = block->postorder_number(); |
| 2672 | 2580 |
| 2673 BitVector* live_out = live_out_[postorder_number]; | 2581 BitVector* live_out = live_out_[postorder_number]; |
| 2674 | 2582 |
| 2675 ZoneGrowableArray<Instruction*>* exposed_stores = | 2583 ZoneGrowableArray<Instruction*>* exposed_stores = |
| 2676 exposed_stores_[postorder_number]; | 2584 exposed_stores_[postorder_number]; |
| 2677 if (exposed_stores == NULL) continue; // No exposed stores. | 2585 if (exposed_stores == NULL) continue; // No exposed stores. |
| 2678 | 2586 |
| 2679 // Iterate over candidate stores. | 2587 // Iterate over candidate stores. |
| 2680 for (intptr_t i = 0; i < exposed_stores->length(); ++i) { | 2588 for (intptr_t i = 0; i < exposed_stores->length(); ++i) { |
| 2681 Instruction* instr = (*exposed_stores)[i]; | 2589 Instruction* instr = (*exposed_stores)[i]; |
| 2682 bool is_load = false; | 2590 bool is_load = false; |
| 2683 bool is_store = false; | 2591 bool is_store = false; |
| 2684 Place place(instr, &is_load, &is_store); | 2592 Place place(instr, &is_load, &is_store); |
| 2685 ASSERT(!is_load && is_store); | 2593 ASSERT(!is_load && is_store); |
| 2686 if (place.IsImmutableField()) { | 2594 if (place.IsImmutableField()) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2747 static bool IsSafeUse(Value* use, SafeUseCheck check_type) { | 2655 static bool IsSafeUse(Value* use, SafeUseCheck check_type) { |
| 2748 if (use->instruction()->IsMaterializeObject()) { | 2656 if (use->instruction()->IsMaterializeObject()) { |
| 2749 return true; | 2657 return true; |
| 2750 } | 2658 } |
| 2751 | 2659 |
| 2752 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); | 2660 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); |
| 2753 if (store != NULL) { | 2661 if (store != NULL) { |
| 2754 if (use == store->value()) { | 2662 if (use == store->value()) { |
| 2755 Definition* instance = store->instance()->definition(); | 2663 Definition* instance = store->instance()->definition(); |
| 2756 return instance->IsAllocateObject() && | 2664 return instance->IsAllocateObject() && |
| 2757 ((check_type == kOptimisticCheck) || | 2665 ((check_type == kOptimisticCheck) || |
| 2758 instance->Identity().IsAllocationSinkingCandidate()); | 2666 instance->Identity().IsAllocationSinkingCandidate()); |
| 2759 } | 2667 } |
| 2760 return true; | 2668 return true; |
| 2761 } | 2669 } |
| 2762 | 2670 |
| 2763 return false; | 2671 return false; |
| 2764 } | 2672 } |
| 2765 | 2673 |
| 2766 | 2674 |
| 2767 // Right now we are attempting to sink allocation only into | 2675 // Right now we are attempting to sink allocation only into |
| 2768 // deoptimization exit. So candidate should only be used in StoreInstanceField | 2676 // deoptimization exit. So candidate should only be used in StoreInstanceField |
| 2769 // instructions that write into fields of the allocated object. | 2677 // instructions that write into fields of the allocated object. |
| 2770 // We do not support materialization of the object that has type arguments. | 2678 // We do not support materialization of the object that has type arguments. |
| 2771 static bool IsAllocationSinkingCandidate(Definition* alloc, | 2679 static bool IsAllocationSinkingCandidate(Definition* alloc, |
| 2772 SafeUseCheck check_type) { | 2680 SafeUseCheck check_type) { |
| 2773 for (Value* use = alloc->input_use_list(); | 2681 for (Value* use = alloc->input_use_list(); use != NULL; |
| 2774 use != NULL; | |
| 2775 use = use->next_use()) { | 2682 use = use->next_use()) { |
| 2776 if (!IsSafeUse(use, check_type)) { | 2683 if (!IsSafeUse(use, check_type)) { |
| 2777 if (FLAG_support_il_printer && FLAG_trace_optimization) { | 2684 if (FLAG_support_il_printer && FLAG_trace_optimization) { |
| 2778 THR_Print("use of %s at %s is unsafe for allocation sinking\n", | 2685 THR_Print("use of %s at %s is unsafe for allocation sinking\n", |
| 2779 alloc->ToCString(), | 2686 alloc->ToCString(), use->instruction()->ToCString()); |
| 2780 use->instruction()->ToCString()); | |
| 2781 } | 2687 } |
| 2782 return false; | 2688 return false; |
| 2783 } | 2689 } |
| 2784 } | 2690 } |
| 2785 | 2691 |
| 2786 return true; | 2692 return true; |
| 2787 } | 2693 } |
| 2788 | 2694 |
| 2789 | 2695 |
| 2790 // If the given use is a store into an object then return an object we are | 2696 // If the given use is a store into an object then return an object we are |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2804 void AllocationSinking::EliminateAllocation(Definition* alloc) { | 2710 void AllocationSinking::EliminateAllocation(Definition* alloc) { |
| 2805 ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); | 2711 ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); |
| 2806 | 2712 |
| 2807 if (FLAG_trace_optimization) { | 2713 if (FLAG_trace_optimization) { |
| 2808 THR_Print("removing allocation from the graph: v%" Pd "\n", | 2714 THR_Print("removing allocation from the graph: v%" Pd "\n", |
| 2809 alloc->ssa_temp_index()); | 2715 alloc->ssa_temp_index()); |
| 2810 } | 2716 } |
| 2811 | 2717 |
| 2812 // As an allocation sinking candidate it is only used in stores to its own | 2718 // As an allocation sinking candidate it is only used in stores to its own |
| 2813 // fields. Remove these stores. | 2719 // fields. Remove these stores. |
| 2814 for (Value* use = alloc->input_use_list(); | 2720 for (Value* use = alloc->input_use_list(); use != NULL; |
| 2815 use != NULL; | |
| 2816 use = alloc->input_use_list()) { | 2721 use = alloc->input_use_list()) { |
| 2817 use->instruction()->RemoveFromGraph(); | 2722 use->instruction()->RemoveFromGraph(); |
| 2818 } | 2723 } |
| 2819 | 2724 |
| 2820 // There should be no environment uses. The pass replaced them with | 2725 // There should be no environment uses. The pass replaced them with |
| 2821 // MaterializeObject instructions. | 2726 // MaterializeObject instructions. |
| 2822 #ifdef DEBUG | 2727 #ifdef DEBUG |
| 2823 for (Value* use = alloc->env_use_list(); | 2728 for (Value* use = alloc->env_use_list(); use != NULL; use = use->next_use()) { |
| 2824 use != NULL; | |
| 2825 use = use->next_use()) { | |
| 2826 ASSERT(use->instruction()->IsMaterializeObject()); | 2729 ASSERT(use->instruction()->IsMaterializeObject()); |
| 2827 } | 2730 } |
| 2828 #endif | 2731 #endif |
| 2829 ASSERT(alloc->input_use_list() == NULL); | 2732 ASSERT(alloc->input_use_list() == NULL); |
| 2830 alloc->RemoveFromGraph(); | 2733 alloc->RemoveFromGraph(); |
| 2831 if (alloc->ArgumentCount() > 0) { | 2734 if (alloc->ArgumentCount() > 0) { |
| 2832 ASSERT(alloc->ArgumentCount() == 1); | 2735 ASSERT(alloc->ArgumentCount() == 1); |
| 2833 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { | 2736 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { |
| 2834 alloc->PushArgumentAt(i)->RemoveFromGraph(); | 2737 alloc->PushArgumentAt(i)->RemoveFromGraph(); |
| 2835 } | 2738 } |
| 2836 } | 2739 } |
| 2837 } | 2740 } |
| 2838 | 2741 |
| 2839 | 2742 |
| 2840 // Find allocation instructions that can be potentially eliminated and | 2743 // Find allocation instructions that can be potentially eliminated and |
| 2841 // rematerialized at deoptimization exits if needed. See IsSafeUse | 2744 // rematerialized at deoptimization exits if needed. See IsSafeUse |
| 2842 // for the description of algorithm used below. | 2745 // for the description of algorithm used below. |
| 2843 void AllocationSinking::CollectCandidates() { | 2746 void AllocationSinking::CollectCandidates() { |
| 2844 // Optimistically collect all potential candidates. | 2747 // Optimistically collect all potential candidates. |
| 2845 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 2748 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 2846 !block_it.Done(); | 2749 !block_it.Done(); block_it.Advance()) { |
| 2847 block_it.Advance()) { | |
| 2848 BlockEntryInstr* block = block_it.Current(); | 2750 BlockEntryInstr* block = block_it.Current(); |
| 2849 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2751 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 2850 { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); | 2752 { |
| 2753 AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); |
| 2851 if ((alloc != NULL) && | 2754 if ((alloc != NULL) && |
| 2852 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 2755 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
| 2853 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 2756 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
| 2854 candidates_.Add(alloc); | 2757 candidates_.Add(alloc); |
| 2855 } | 2758 } |
| 2856 } | 2759 } |
| 2857 { AllocateUninitializedContextInstr* alloc = | 2760 { |
| 2761 AllocateUninitializedContextInstr* alloc = |
| 2858 it.Current()->AsAllocateUninitializedContext(); | 2762 it.Current()->AsAllocateUninitializedContext(); |
| 2859 if ((alloc != NULL) && | 2763 if ((alloc != NULL) && |
| 2860 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 2764 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
| 2861 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 2765 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
| 2862 candidates_.Add(alloc); | 2766 candidates_.Add(alloc); |
| 2863 } | 2767 } |
| 2864 } | 2768 } |
| 2865 } | 2769 } |
| 2866 } | 2770 } |
| 2867 | 2771 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2901 | 2805 |
| 2902 | 2806 |
| 2903 // If materialization references an allocation sinking candidate then replace | 2807 // If materialization references an allocation sinking candidate then replace |
| 2904 // this reference with a materialization which should have been computed for | 2808 // this reference with a materialization which should have been computed for |
| 2905 // this side-exit. CollectAllExits should have collected this exit. | 2809 // this side-exit. CollectAllExits should have collected this exit. |
| 2906 void AllocationSinking::NormalizeMaterializations() { | 2810 void AllocationSinking::NormalizeMaterializations() { |
| 2907 for (intptr_t i = 0; i < candidates_.length(); i++) { | 2811 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 2908 Definition* alloc = candidates_[i]; | 2812 Definition* alloc = candidates_[i]; |
| 2909 | 2813 |
| 2910 Value* next_use; | 2814 Value* next_use; |
| 2911 for (Value* use = alloc->input_use_list(); | 2815 for (Value* use = alloc->input_use_list(); use != NULL; use = next_use) { |
| 2912 use != NULL; | |
| 2913 use = next_use) { | |
| 2914 next_use = use->next_use(); | 2816 next_use = use->next_use(); |
| 2915 if (use->instruction()->IsMaterializeObject()) { | 2817 if (use->instruction()->IsMaterializeObject()) { |
| 2916 use->BindTo(MaterializationFor(alloc, use->instruction())); | 2818 use->BindTo(MaterializationFor(alloc, use->instruction())); |
| 2917 } | 2819 } |
| 2918 } | 2820 } |
| 2919 } | 2821 } |
| 2920 } | 2822 } |
| 2921 | 2823 |
| 2922 | 2824 |
| 2923 // We transitively insert materializations at each deoptimization exit that | 2825 // We transitively insert materializations at each deoptimization exit that |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2979 intptr_t j = 0; | 2881 intptr_t j = 0; |
| 2980 for (intptr_t i = 0; i < candidates_.length(); i++) { | 2882 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 2981 Definition* alloc = candidates_[i]; | 2883 Definition* alloc = candidates_[i]; |
| 2982 if (!alloc->Identity().IsAllocationSinkingCandidate()) { | 2884 if (!alloc->Identity().IsAllocationSinkingCandidate()) { |
| 2983 if (FLAG_trace_optimization) { | 2885 if (FLAG_trace_optimization) { |
| 2984 THR_Print("allocation v%" Pd " can't be eliminated\n", | 2886 THR_Print("allocation v%" Pd " can't be eliminated\n", |
| 2985 alloc->ssa_temp_index()); | 2887 alloc->ssa_temp_index()); |
| 2986 } | 2888 } |
| 2987 | 2889 |
| 2988 #ifdef DEBUG | 2890 #ifdef DEBUG |
| 2989 for (Value* use = alloc->env_use_list(); | 2891 for (Value* use = alloc->env_use_list(); use != NULL; |
| 2990 use != NULL; | |
| 2991 use = use->next_use()) { | 2892 use = use->next_use()) { |
| 2992 ASSERT(use->instruction()->IsMaterializeObject()); | 2893 ASSERT(use->instruction()->IsMaterializeObject()); |
| 2993 } | 2894 } |
| 2994 #endif | 2895 #endif |
| 2995 | 2896 |
| 2996 // All materializations will be removed from the graph. Remove inserted | 2897 // All materializations will be removed from the graph. Remove inserted |
| 2997 // loads first and detach materializations from allocation's environment | 2898 // loads first and detach materializations from allocation's environment |
| 2998 // use list: we will reconstruct it when we start removing | 2899 // use list: we will reconstruct it when we start removing |
| 2999 // materializations. | 2900 // materializations. |
| 3000 alloc->set_env_use_list(NULL); | 2901 alloc->set_env_use_list(NULL); |
| 3001 for (Value* use = alloc->input_use_list(); | 2902 for (Value* use = alloc->input_use_list(); use != NULL; |
| 3002 use != NULL; | |
| 3003 use = use->next_use()) { | 2903 use = use->next_use()) { |
| 3004 if (use->instruction()->IsLoadField()) { | 2904 if (use->instruction()->IsLoadField()) { |
| 3005 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 2905 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
| 3006 load->ReplaceUsesWith(flow_graph_->constant_null()); | 2906 load->ReplaceUsesWith(flow_graph_->constant_null()); |
| 3007 load->RemoveFromGraph(); | 2907 load->RemoveFromGraph(); |
| 3008 } else { | 2908 } else { |
| 3009 ASSERT(use->instruction()->IsMaterializeObject() || | 2909 ASSERT(use->instruction()->IsMaterializeObject() || |
| 3010 use->instruction()->IsPhi() || | 2910 use->instruction()->IsPhi() || |
| 3011 use->instruction()->IsStoreInstanceField()); | 2911 use->instruction()->IsStoreInstanceField()); |
| 3012 } | 2912 } |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3136 while (exit->previous()->IsMaterializeObject()) { | 3036 while (exit->previous()->IsMaterializeObject()) { |
| 3137 exit = exit->previous(); | 3037 exit = exit->previous(); |
| 3138 } | 3038 } |
| 3139 return exit; | 3039 return exit; |
| 3140 } | 3040 } |
| 3141 | 3041 |
| 3142 | 3042 |
| 3143 // Given the allocation and deoptimization exit try to find MaterializeObject | 3043 // Given the allocation and deoptimization exit try to find MaterializeObject |
| 3144 // instruction corresponding to this allocation at this exit. | 3044 // instruction corresponding to this allocation at this exit. |
| 3145 MaterializeObjectInstr* AllocationSinking::MaterializationFor( | 3045 MaterializeObjectInstr* AllocationSinking::MaterializationFor( |
| 3146 Definition* alloc, Instruction* exit) { | 3046 Definition* alloc, |
| 3047 Instruction* exit) { |
| 3147 if (exit->IsMaterializeObject()) { | 3048 if (exit->IsMaterializeObject()) { |
| 3148 exit = ExitForMaterialization(exit->AsMaterializeObject()); | 3049 exit = ExitForMaterialization(exit->AsMaterializeObject()); |
| 3149 } | 3050 } |
| 3150 | 3051 |
| 3151 for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject(); | 3052 for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject(); |
| 3152 mat != NULL; | 3053 mat != NULL; mat = mat->previous()->AsMaterializeObject()) { |
| 3153 mat = mat->previous()->AsMaterializeObject()) { | |
| 3154 if (mat->allocation() == alloc) { | 3054 if (mat->allocation() == alloc) { |
| 3155 return mat; | 3055 return mat; |
| 3156 } | 3056 } |
| 3157 } | 3057 } |
| 3158 | 3058 |
| 3159 return NULL; | 3059 return NULL; |
| 3160 } | 3060 } |
| 3161 | 3061 |
| 3162 | 3062 |
| 3163 // Insert MaterializeObject instruction for the given allocation before | 3063 // Insert MaterializeObject instruction for the given allocation before |
| 3164 // the given instruction that can deoptimize. | 3064 // the given instruction that can deoptimize. |
| 3165 void AllocationSinking::CreateMaterializationAt( | 3065 void AllocationSinking::CreateMaterializationAt( |
| 3166 Instruction* exit, | 3066 Instruction* exit, |
| 3167 Definition* alloc, | 3067 Definition* alloc, |
| 3168 const ZoneGrowableArray<const Object*>& slots) { | 3068 const ZoneGrowableArray<const Object*>& slots) { |
| 3169 ZoneGrowableArray<Value*>* values = | 3069 ZoneGrowableArray<Value*>* values = |
| 3170 new(Z) ZoneGrowableArray<Value*>(slots.length()); | 3070 new (Z) ZoneGrowableArray<Value*>(slots.length()); |
| 3171 | 3071 |
| 3172 // All loads should be inserted before the first materialization so that | 3072 // All loads should be inserted before the first materialization so that |
| 3173 // IR follows the following pattern: loads, materializations, deoptimizing | 3073 // IR follows the following pattern: loads, materializations, deoptimizing |
| 3174 // instruction. | 3074 // instruction. |
| 3175 Instruction* load_point = FirstMaterializationAt(exit); | 3075 Instruction* load_point = FirstMaterializationAt(exit); |
| 3176 | 3076 |
| 3177 // Insert load instruction for every field. | 3077 // Insert load instruction for every field. |
| 3178 for (intptr_t i = 0; i < slots.length(); i++) { | 3078 for (intptr_t i = 0; i < slots.length(); i++) { |
| 3179 LoadFieldInstr* load = slots[i]->IsField() | 3079 LoadFieldInstr* load = |
| 3180 ? new(Z) LoadFieldInstr( | 3080 slots[i]->IsField() |
| 3181 new(Z) Value(alloc), | 3081 ? new (Z) LoadFieldInstr( |
| 3182 &Field::Cast(*slots[i]), | 3082 new (Z) Value(alloc), &Field::Cast(*slots[i]), |
| 3183 AbstractType::ZoneHandle(Z), | 3083 AbstractType::ZoneHandle(Z), alloc->token_pos()) |
| 3184 alloc->token_pos()) | 3084 : new (Z) LoadFieldInstr( |
| 3185 : new(Z) LoadFieldInstr( | 3085 new (Z) Value(alloc), Smi::Cast(*slots[i]).Value(), |
| 3186 new(Z) Value(alloc), | 3086 AbstractType::ZoneHandle(Z), alloc->token_pos()); |
| 3187 Smi::Cast(*slots[i]).Value(), | 3087 flow_graph_->InsertBefore(load_point, load, NULL, FlowGraph::kValue); |
| 3188 AbstractType::ZoneHandle(Z), | 3088 values->Add(new (Z) Value(load)); |
| 3189 alloc->token_pos()); | |
| 3190 flow_graph_->InsertBefore( | |
| 3191 load_point, load, NULL, FlowGraph::kValue); | |
| 3192 values->Add(new(Z) Value(load)); | |
| 3193 } | 3089 } |
| 3194 | 3090 |
| 3195 MaterializeObjectInstr* mat = NULL; | 3091 MaterializeObjectInstr* mat = NULL; |
| 3196 if (alloc->IsAllocateObject()) { | 3092 if (alloc->IsAllocateObject()) { |
| 3197 mat = new(Z) MaterializeObjectInstr( | 3093 mat = new (Z) |
| 3198 alloc->AsAllocateObject(), slots, values); | 3094 MaterializeObjectInstr(alloc->AsAllocateObject(), slots, values); |
| 3199 } else { | 3095 } else { |
| 3200 ASSERT(alloc->IsAllocateUninitializedContext()); | 3096 ASSERT(alloc->IsAllocateUninitializedContext()); |
| 3201 mat = new(Z) MaterializeObjectInstr( | 3097 mat = new (Z) MaterializeObjectInstr( |
| 3202 alloc->AsAllocateUninitializedContext(), slots, values); | 3098 alloc->AsAllocateUninitializedContext(), slots, values); |
| 3203 } | 3099 } |
| 3204 | 3100 |
| 3205 flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); | 3101 flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); |
| 3206 | 3102 |
| 3207 // Replace all mentions of this allocation with a newly inserted | 3103 // Replace all mentions of this allocation with a newly inserted |
| 3208 // MaterializeObject instruction. | 3104 // MaterializeObject instruction. |
| 3209 // We must preserve the identity: all mentions are replaced by the same | 3105 // We must preserve the identity: all mentions are replaced by the same |
| 3210 // materialization. | 3106 // materialization. |
| 3211 for (Environment::DeepIterator env_it(exit->env()); | 3107 for (Environment::DeepIterator env_it(exit->env()); !env_it.Done(); |
| 3212 !env_it.Done(); | |
| 3213 env_it.Advance()) { | 3108 env_it.Advance()) { |
| 3214 Value* use = env_it.CurrentValue(); | 3109 Value* use = env_it.CurrentValue(); |
| 3215 if (use->definition() == alloc) { | 3110 if (use->definition() == alloc) { |
| 3216 use->RemoveFromUseList(); | 3111 use->RemoveFromUseList(); |
| 3217 use->set_definition(mat); | 3112 use->set_definition(mat); |
| 3218 mat->AddEnvUse(use); | 3113 mat->AddEnvUse(use); |
| 3219 } | 3114 } |
| 3220 } | 3115 } |
| 3221 | 3116 |
| 3222 // Mark MaterializeObject as an environment use of this allocation. | 3117 // Mark MaterializeObject as an environment use of this allocation. |
| 3223 // This will allow us to discover it when we are looking for deoptimization | 3118 // This will allow us to discover it when we are looking for deoptimization |
| 3224 // exits for another allocation that potentially flows into this one. | 3119 // exits for another allocation that potentially flows into this one. |
| 3225 Value* val = new(Z) Value(alloc); | 3120 Value* val = new (Z) Value(alloc); |
| 3226 val->set_instruction(mat); | 3121 val->set_instruction(mat); |
| 3227 alloc->AddEnvUse(val); | 3122 alloc->AddEnvUse(val); |
| 3228 | 3123 |
| 3229 // Record inserted materialization. | 3124 // Record inserted materialization. |
| 3230 materializations_.Add(mat); | 3125 materializations_.Add(mat); |
| 3231 } | 3126 } |
| 3232 | 3127 |
| 3233 | 3128 |
| 3234 // Add given instruction to the list of the instructions if it is not yet | 3129 // Add given instruction to the list of the instructions if it is not yet |
| 3235 // present there. | 3130 // present there. |
| 3236 template<typename T> | 3131 template <typename T> |
| 3237 void AddInstruction(GrowableArray<T*>* list, T* value) { | 3132 void AddInstruction(GrowableArray<T*>* list, T* value) { |
| 3238 ASSERT(!value->IsGraphEntry()); | 3133 ASSERT(!value->IsGraphEntry()); |
| 3239 for (intptr_t i = 0; i < list->length(); i++) { | 3134 for (intptr_t i = 0; i < list->length(); i++) { |
| 3240 if ((*list)[i] == value) { | 3135 if ((*list)[i] == value) { |
| 3241 return; | 3136 return; |
| 3242 } | 3137 } |
| 3243 } | 3138 } |
| 3244 list->Add(value); | 3139 list->Add(value); |
| 3245 } | 3140 } |
| 3246 | 3141 |
| 3247 | 3142 |
| 3248 // Transitively collect all deoptimization exits that might need this allocation | 3143 // Transitively collect all deoptimization exits that might need this allocation |
| 3249 // rematerialized. It is not enough to collect only environment uses of this | 3144 // rematerialized. It is not enough to collect only environment uses of this |
| 3250 // allocation because it can flow into other objects that will be | 3145 // allocation because it can flow into other objects that will be |
| 3251 // dematerialized and that are referenced by deopt environments that | 3146 // dematerialized and that are referenced by deopt environments that |
| 3252 // don't contain this allocation explicitly. | 3147 // don't contain this allocation explicitly. |
| 3253 void AllocationSinking::ExitsCollector::Collect(Definition* alloc) { | 3148 void AllocationSinking::ExitsCollector::Collect(Definition* alloc) { |
| 3254 for (Value* use = alloc->env_use_list(); | 3149 for (Value* use = alloc->env_use_list(); use != NULL; use = use->next_use()) { |
| 3255 use != NULL; | |
| 3256 use = use->next_use()) { | |
| 3257 if (use->instruction()->IsMaterializeObject()) { | 3150 if (use->instruction()->IsMaterializeObject()) { |
| 3258 AddInstruction(&exits_, ExitForMaterialization( | 3151 AddInstruction(&exits_, ExitForMaterialization( |
| 3259 use->instruction()->AsMaterializeObject())); | 3152 use->instruction()->AsMaterializeObject())); |
| 3260 } else { | 3153 } else { |
| 3261 AddInstruction(&exits_, use->instruction()); | 3154 AddInstruction(&exits_, use->instruction()); |
| 3262 } | 3155 } |
| 3263 } | 3156 } |
| 3264 | 3157 |
| 3265 // Check if this allocation is stored into any other allocation sinking | 3158 // Check if this allocation is stored into any other allocation sinking |
| 3266 // candidate and put it on worklist so that we conservatively collect all | 3159 // candidate and put it on worklist so that we conservatively collect all |
| 3267 // exits for that candidate as well because they potentially might see | 3160 // exits for that candidate as well because they potentially might see |
| 3268 // this object. | 3161 // this object. |
| 3269 for (Value* use = alloc->input_use_list(); | 3162 for (Value* use = alloc->input_use_list(); use != NULL; |
| 3270 use != NULL; | |
| 3271 use = use->next_use()) { | 3163 use = use->next_use()) { |
| 3272 Definition* obj = StoreInto(use); | 3164 Definition* obj = StoreInto(use); |
| 3273 if ((obj != NULL) && (obj != alloc)) { | 3165 if ((obj != NULL) && (obj != alloc)) { |
| 3274 AddInstruction(&worklist_, obj); | 3166 AddInstruction(&worklist_, obj); |
| 3275 } | 3167 } |
| 3276 } | 3168 } |
| 3277 } | 3169 } |
| 3278 | 3170 |
| 3279 | 3171 |
| 3280 void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) { | 3172 void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) { |
| 3281 exits_.TruncateTo(0); | 3173 exits_.TruncateTo(0); |
| 3282 worklist_.TruncateTo(0); | 3174 worklist_.TruncateTo(0); |
| 3283 | 3175 |
| 3284 worklist_.Add(alloc); | 3176 worklist_.Add(alloc); |
| 3285 | 3177 |
| 3286 // Note: worklist potentially will grow while we are iterating over it. | 3178 // Note: worklist potentially will grow while we are iterating over it. |
| 3287 // We are not removing allocations from the worklist not to waste space on | 3179 // We are not removing allocations from the worklist not to waste space on |
| 3288 // the side maintaining BitVector of already processed allocations: worklist | 3180 // the side maintaining BitVector of already processed allocations: worklist |
| 3289 // is expected to be very small thus linear search in it is just as effecient | 3181 // is expected to be very small thus linear search in it is just as effecient |
| 3290 // as a bitvector. | 3182 // as a bitvector. |
| 3291 for (intptr_t i = 0; i < worklist_.length(); i++) { | 3183 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 3292 Collect(worklist_[i]); | 3184 Collect(worklist_[i]); |
| 3293 } | 3185 } |
| 3294 } | 3186 } |
| 3295 | 3187 |
| 3296 | 3188 |
| 3297 void AllocationSinking::InsertMaterializations(Definition* alloc) { | 3189 void AllocationSinking::InsertMaterializations(Definition* alloc) { |
| 3298 // Collect all fields that are written for this instance. | 3190 // Collect all fields that are written for this instance. |
| 3299 ZoneGrowableArray<const Object*>* slots = | 3191 ZoneGrowableArray<const Object*>* slots = |
| 3300 new(Z) ZoneGrowableArray<const Object*>(5); | 3192 new (Z) ZoneGrowableArray<const Object*>(5); |
| 3301 | 3193 |
| 3302 for (Value* use = alloc->input_use_list(); | 3194 for (Value* use = alloc->input_use_list(); use != NULL; |
| 3303 use != NULL; | |
| 3304 use = use->next_use()) { | 3195 use = use->next_use()) { |
| 3305 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); | 3196 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); |
| 3306 if ((store != NULL) && (store->instance()->definition() == alloc)) { | 3197 if ((store != NULL) && (store->instance()->definition() == alloc)) { |
| 3307 if (!store->field().IsNull()) { | 3198 if (!store->field().IsNull()) { |
| 3308 AddSlot(slots, Field::ZoneHandle(Z, store->field().Original())); | 3199 AddSlot(slots, Field::ZoneHandle(Z, store->field().Original())); |
| 3309 } else { | 3200 } else { |
| 3310 AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes()))); | 3201 AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes()))); |
| 3311 } | 3202 } |
| 3312 } | 3203 } |
| 3313 } | 3204 } |
| 3314 | 3205 |
| 3315 if (alloc->ArgumentCount() > 0) { | 3206 if (alloc->ArgumentCount() > 0) { |
| 3316 AllocateObjectInstr* alloc_object = alloc->AsAllocateObject(); | 3207 AllocateObjectInstr* alloc_object = alloc->AsAllocateObject(); |
| 3317 ASSERT(alloc_object->ArgumentCount() == 1); | 3208 ASSERT(alloc_object->ArgumentCount() == 1); |
| 3318 intptr_t type_args_offset = | 3209 intptr_t type_args_offset = |
| 3319 alloc_object->cls().type_arguments_field_offset(); | 3210 alloc_object->cls().type_arguments_field_offset(); |
| 3320 AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(type_args_offset))); | 3211 AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(type_args_offset))); |
| 3321 } | 3212 } |
| 3322 | 3213 |
| 3323 // Collect all instructions that mention this object in the environment. | 3214 // Collect all instructions that mention this object in the environment. |
| 3324 exits_collector_.CollectTransitively(alloc); | 3215 exits_collector_.CollectTransitively(alloc); |
| 3325 | 3216 |
| 3326 // Insert materializations at environment uses. | 3217 // Insert materializations at environment uses. |
| 3327 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 3218 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 3328 CreateMaterializationAt( | 3219 CreateMaterializationAt(exits_collector_.exits()[i], alloc, *slots); |
| 3329 exits_collector_.exits()[i], alloc, *slots); | |
| 3330 } | 3220 } |
| 3331 } | 3221 } |
| 3332 | 3222 |
| 3333 | 3223 |
| 3334 void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) { | 3224 void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) { |
| 3335 // For every catch-block: Iterate over all call instructions inside the | 3225 // For every catch-block: Iterate over all call instructions inside the |
| 3336 // corresponding try-block and figure out for each environment value if it | 3226 // corresponding try-block and figure out for each environment value if it |
| 3337 // is the same constant at all calls. If yes, replace the initial definition | 3227 // is the same constant at all calls. If yes, replace the initial definition |
| 3338 // at the catch-entry with this constant. | 3228 // at the catch-entry with this constant. |
| 3339 const GrowableArray<CatchBlockEntryInstr*>& catch_entries = | 3229 const GrowableArray<CatchBlockEntryInstr*>& catch_entries = |
| 3340 flow_graph->graph_entry()->catch_entries(); | 3230 flow_graph->graph_entry()->catch_entries(); |
| 3341 intptr_t base = kFirstLocalSlotFromFp + flow_graph->num_non_copied_params(); | 3231 intptr_t base = kFirstLocalSlotFromFp + flow_graph->num_non_copied_params(); |
| 3342 for (intptr_t catch_idx = 0; | 3232 for (intptr_t catch_idx = 0; catch_idx < catch_entries.length(); |
| 3343 catch_idx < catch_entries.length(); | |
| 3344 ++catch_idx) { | 3233 ++catch_idx) { |
| 3345 CatchBlockEntryInstr* catch_entry = catch_entries[catch_idx]; | 3234 CatchBlockEntryInstr* catch_entry = catch_entries[catch_idx]; |
| 3346 | 3235 |
| 3347 // Initialize cdefs with the original initial definitions (ParameterInstr). | 3236 // Initialize cdefs with the original initial definitions (ParameterInstr). |
| 3348 // The following representation is used: | 3237 // The following representation is used: |
| 3349 // ParameterInstr => unknown | 3238 // ParameterInstr => unknown |
| 3350 // ConstantInstr => known constant | 3239 // ConstantInstr => known constant |
| 3351 // NULL => non-constant | 3240 // NULL => non-constant |
| 3352 GrowableArray<Definition*>* idefs = catch_entry->initial_definitions(); | 3241 GrowableArray<Definition*>* idefs = catch_entry->initial_definitions(); |
| 3353 GrowableArray<Definition*> cdefs(idefs->length()); | 3242 GrowableArray<Definition*> cdefs(idefs->length()); |
| 3354 cdefs.AddArray(*idefs); | 3243 cdefs.AddArray(*idefs); |
| 3355 | 3244 |
| 3356 // exception_var and stacktrace_var are never constant. In asynchronous or | 3245 // exception_var and stacktrace_var are never constant. In asynchronous or |
| 3357 // generator functions they may be context-allocated in which case they are | 3246 // generator functions they may be context-allocated in which case they are |
| 3358 // not tracked in the environment anyway. | 3247 // not tracked in the environment anyway. |
| 3359 if (!catch_entry->exception_var().is_captured()) { | 3248 if (!catch_entry->exception_var().is_captured()) { |
| 3360 cdefs[base - catch_entry->exception_var().index()] = NULL; | 3249 cdefs[base - catch_entry->exception_var().index()] = NULL; |
| 3361 } | 3250 } |
| 3362 if (!catch_entry->stacktrace_var().is_captured()) { | 3251 if (!catch_entry->stacktrace_var().is_captured()) { |
| 3363 cdefs[base - catch_entry->stacktrace_var().index()] = NULL; | 3252 cdefs[base - catch_entry->stacktrace_var().index()] = NULL; |
| 3364 } | 3253 } |
| 3365 | 3254 |
| 3366 for (BlockIterator block_it = flow_graph->reverse_postorder_iterator(); | 3255 for (BlockIterator block_it = flow_graph->reverse_postorder_iterator(); |
| 3367 !block_it.Done(); | 3256 !block_it.Done(); block_it.Advance()) { |
| 3368 block_it.Advance()) { | |
| 3369 BlockEntryInstr* block = block_it.Current(); | 3257 BlockEntryInstr* block = block_it.Current(); |
| 3370 if (block->try_index() == catch_entry->catch_try_index()) { | 3258 if (block->try_index() == catch_entry->catch_try_index()) { |
| 3371 for (ForwardInstructionIterator instr_it(block); | 3259 for (ForwardInstructionIterator instr_it(block); !instr_it.Done(); |
| 3372 !instr_it.Done(); | |
| 3373 instr_it.Advance()) { | 3260 instr_it.Advance()) { |
| 3374 Instruction* current = instr_it.Current(); | 3261 Instruction* current = instr_it.Current(); |
| 3375 if (current->MayThrow()) { | 3262 if (current->MayThrow()) { |
| 3376 Environment* env = current->env()->Outermost(); | 3263 Environment* env = current->env()->Outermost(); |
| 3377 ASSERT(env != NULL); | 3264 ASSERT(env != NULL); |
| 3378 for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) { | 3265 for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) { |
| 3379 if (cdefs[env_idx] != NULL && | 3266 if (cdefs[env_idx] != NULL && !cdefs[env_idx]->IsConstant() && |
| 3380 !cdefs[env_idx]->IsConstant() && | |
| 3381 env->ValueAt(env_idx)->BindsToConstant()) { | 3267 env->ValueAt(env_idx)->BindsToConstant()) { |
| 3382 // If the recorded definition is not a constant, record this | 3268 // If the recorded definition is not a constant, record this |
| 3383 // definition as the current constant definition. | 3269 // definition as the current constant definition. |
| 3384 cdefs[env_idx] = env->ValueAt(env_idx)->definition(); | 3270 cdefs[env_idx] = env->ValueAt(env_idx)->definition(); |
| 3385 } | 3271 } |
| 3386 if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) { | 3272 if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) { |
| 3387 // Non-constant definitions are reset to NULL. | 3273 // Non-constant definitions are reset to NULL. |
| 3388 cdefs[env_idx] = NULL; | 3274 cdefs[env_idx] = NULL; |
| 3389 } | 3275 } |
| 3390 } | 3276 } |
| 3391 } | 3277 } |
| 3392 } | 3278 } |
| 3393 } | 3279 } |
| 3394 } | 3280 } |
| 3395 for (intptr_t j = 0; j < idefs->length(); ++j) { | 3281 for (intptr_t j = 0; j < idefs->length(); ++j) { |
| 3396 if (cdefs[j] != NULL && cdefs[j]->IsConstant()) { | 3282 if (cdefs[j] != NULL && cdefs[j]->IsConstant()) { |
| 3397 // TODO(fschneider): Use constants from the constant pool. | 3283 // TODO(fschneider): Use constants from the constant pool. |
| 3398 Definition* old = (*idefs)[j]; | 3284 Definition* old = (*idefs)[j]; |
| 3399 ConstantInstr* orig = cdefs[j]->AsConstant(); | 3285 ConstantInstr* orig = cdefs[j]->AsConstant(); |
| 3400 ConstantInstr* copy = | 3286 ConstantInstr* copy = |
| 3401 new(flow_graph->zone()) ConstantInstr(orig->value()); | 3287 new (flow_graph->zone()) ConstantInstr(orig->value()); |
| 3402 copy->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); | 3288 copy->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); |
| 3403 old->ReplaceUsesWith(copy); | 3289 old->ReplaceUsesWith(copy); |
| 3404 (*idefs)[j] = copy; | 3290 (*idefs)[j] = copy; |
| 3405 } | 3291 } |
| 3406 } | 3292 } |
| 3407 } | 3293 } |
| 3408 } | 3294 } |
| 3409 | 3295 |
| 3410 | 3296 |
| 3411 // Returns true iff this definition is used in a non-phi instruction. | 3297 // Returns true iff this definition is used in a non-phi instruction. |
| 3412 static bool HasRealUse(Definition* def) { | 3298 static bool HasRealUse(Definition* def) { |
| 3413 // Environment uses are real (non-phi) uses. | 3299 // Environment uses are real (non-phi) uses. |
| 3414 if (def->env_use_list() != NULL) return true; | 3300 if (def->env_use_list() != NULL) return true; |
| 3415 | 3301 |
| 3416 for (Value::Iterator it(def->input_use_list()); | 3302 for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) { |
| 3417 !it.Done(); | |
| 3418 it.Advance()) { | |
| 3419 if (!it.Current()->instruction()->IsPhi()) return true; | 3303 if (!it.Current()->instruction()->IsPhi()) return true; |
| 3420 } | 3304 } |
| 3421 return false; | 3305 return false; |
| 3422 } | 3306 } |
| 3423 | 3307 |
| 3424 | 3308 |
| 3425 void DeadCodeElimination::EliminateDeadPhis(FlowGraph* flow_graph) { | 3309 void DeadCodeElimination::EliminateDeadPhis(FlowGraph* flow_graph) { |
| 3426 GrowableArray<PhiInstr*> live_phis; | 3310 GrowableArray<PhiInstr*> live_phis; |
| 3427 for (BlockIterator b = flow_graph->postorder_iterator(); | 3311 for (BlockIterator b = flow_graph->postorder_iterator(); !b.Done(); |
| 3428 !b.Done(); | |
| 3429 b.Advance()) { | 3312 b.Advance()) { |
| 3430 JoinEntryInstr* join = b.Current()->AsJoinEntry(); | 3313 JoinEntryInstr* join = b.Current()->AsJoinEntry(); |
| 3431 if (join != NULL) { | 3314 if (join != NULL) { |
| 3432 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 3315 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 3433 PhiInstr* phi = it.Current(); | 3316 PhiInstr* phi = it.Current(); |
| 3434 // Phis that have uses and phis inside try blocks are | 3317 // Phis that have uses and phis inside try blocks are |
| 3435 // marked as live. | 3318 // marked as live. |
| 3436 if (HasRealUse(phi) || join->InsideTryBlock()) { | 3319 if (HasRealUse(phi) || join->InsideTryBlock()) { |
| 3437 live_phis.Add(phi); | 3320 live_phis.Add(phi); |
| 3438 phi->mark_alive(); | 3321 phi->mark_alive(); |
| 3439 } else { | 3322 } else { |
| 3440 phi->mark_dead(); | 3323 phi->mark_dead(); |
| 3441 } | 3324 } |
| 3442 } | 3325 } |
| 3443 } | 3326 } |
| 3444 } | 3327 } |
| 3445 | 3328 |
| 3446 while (!live_phis.is_empty()) { | 3329 while (!live_phis.is_empty()) { |
| 3447 PhiInstr* phi = live_phis.RemoveLast(); | 3330 PhiInstr* phi = live_phis.RemoveLast(); |
| 3448 for (intptr_t i = 0; i < phi->InputCount(); i++) { | 3331 for (intptr_t i = 0; i < phi->InputCount(); i++) { |
| 3449 Value* val = phi->InputAt(i); | 3332 Value* val = phi->InputAt(i); |
| 3450 PhiInstr* used_phi = val->definition()->AsPhi(); | 3333 PhiInstr* used_phi = val->definition()->AsPhi(); |
| 3451 if ((used_phi != NULL) && !used_phi->is_alive()) { | 3334 if ((used_phi != NULL) && !used_phi->is_alive()) { |
| 3452 used_phi->mark_alive(); | 3335 used_phi->mark_alive(); |
| 3453 live_phis.Add(used_phi); | 3336 live_phis.Add(used_phi); |
| 3454 } | 3337 } |
| 3455 } | 3338 } |
| 3456 } | 3339 } |
| 3457 | 3340 |
| 3458 for (BlockIterator it(flow_graph->postorder_iterator()); | 3341 for (BlockIterator it(flow_graph->postorder_iterator()); !it.Done(); |
| 3459 !it.Done(); | |
| 3460 it.Advance()) { | 3342 it.Advance()) { |
| 3461 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 3343 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
| 3462 if (join != NULL) { | 3344 if (join != NULL) { |
| 3463 if (join->phis_ == NULL) continue; | 3345 if (join->phis_ == NULL) continue; |
| 3464 | 3346 |
| 3465 // Eliminate dead phis and compact the phis_ array of the block. | 3347 // Eliminate dead phis and compact the phis_ array of the block. |
| 3466 intptr_t to_index = 0; | 3348 intptr_t to_index = 0; |
| 3467 for (intptr_t i = 0; i < join->phis_->length(); ++i) { | 3349 for (intptr_t i = 0; i < join->phis_->length(); ++i) { |
| 3468 PhiInstr* phi = (*join->phis_)[i]; | 3350 PhiInstr* phi = (*join->phis_)[i]; |
| 3469 if (phi != NULL) { | 3351 if (phi != NULL) { |
| 3470 if (!phi->is_alive()) { | 3352 if (!phi->is_alive()) { |
| 3471 phi->ReplaceUsesWith(flow_graph->constant_null()); | 3353 phi->ReplaceUsesWith(flow_graph->constant_null()); |
| 3472 phi->UnuseAllInputs(); | 3354 phi->UnuseAllInputs(); |
| 3473 (*join->phis_)[i] = NULL; | 3355 (*join->phis_)[i] = NULL; |
| 3474 if (FLAG_trace_optimization) { | 3356 if (FLAG_trace_optimization) { |
| 3475 THR_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index()); | 3357 THR_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index()); |
| 3476 } | 3358 } |
| 3477 } else if (phi->IsRedundant()) { | 3359 } else if (phi->IsRedundant()) { |
| 3478 phi->ReplaceUsesWith(phi->InputAt(0)->definition()); | 3360 phi->ReplaceUsesWith(phi->InputAt(0)->definition()); |
| 3479 phi->UnuseAllInputs(); | 3361 phi->UnuseAllInputs(); |
| 3480 (*join->phis_)[i] = NULL; | 3362 (*join->phis_)[i] = NULL; |
| 3481 if (FLAG_trace_optimization) { | 3363 if (FLAG_trace_optimization) { |
| 3482 THR_Print("Removing redundant phi v%" Pd "\n", | 3364 THR_Print("Removing redundant phi v%" Pd "\n", |
| 3483 phi->ssa_temp_index()); | 3365 phi->ssa_temp_index()); |
| 3484 } | 3366 } |
| 3485 } else { | 3367 } else { |
| 3486 (*join->phis_)[to_index++] = phi; | 3368 (*join->phis_)[to_index++] = phi; |
| 3487 } | 3369 } |
| 3488 } | 3370 } |
| 3489 } | 3371 } |
| 3490 if (to_index == 0) { | 3372 if (to_index == 0) { |
| 3491 join->phis_ = NULL; | 3373 join->phis_ = NULL; |
| 3492 } else { | 3374 } else { |
| 3493 join->phis_->TruncateTo(to_index); | 3375 join->phis_->TruncateTo(to_index); |
| 3494 } | 3376 } |
| 3495 } | 3377 } |
| 3496 } | 3378 } |
| 3497 } | 3379 } |
| 3498 | 3380 |
| 3499 | 3381 |
| 3500 } // namespace dart | 3382 } // namespace dart |
| OLD | NEW |