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 |