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

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

Issue 2481873005: clang-format runtime/vm (Closed)
Patch Set: Merge Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/redundancy_elimination.h ('k') | runtime/vm/regexp.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/redundancy_elimination.h ('k') | runtime/vm/regexp.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698