Index: src/hydrogen-check-elimination.cc |
diff --git a/src/hydrogen-check-elimination.cc b/src/hydrogen-check-elimination.cc |
index cd002a1d5c80a5d9a76ee4eded2f889461958dc6..2d240b22690cb2b2aa46eb2f6a9d2aeeda8aa860 100644 |
--- a/src/hydrogen-check-elimination.cc |
+++ b/src/hydrogen-check-elimination.cc |
@@ -48,12 +48,12 @@ typedef UniqueSet<Map>* MapSet; |
struct HCheckTableEntry { |
HValue* object_; // The object being approximated. NULL => invalid entry. |
- HValue* check_; // The last check instruction. |
- MapSet maps_; // The set of known maps for the object. |
+ HInstruction* check_; // The last check instruction. |
+ MapSet maps_; // The set of known maps for the object. |
}; |
-// The main datastructure used during check elimination, which stores a |
+// The main data structure used during check elimination, which stores a |
// set of known maps for each object. |
class HCheckTable : public ZoneObject { |
public: |
@@ -130,6 +130,8 @@ class HCheckTable : public ZoneObject { |
copy->cursor_ = cursor_; |
copy->size_ = size_; |
+ copy->InheritPhiOperands(succ, this, from_block, COPY, zone); |
+ |
// Branch-sensitive analysis for certain comparisons may add more facts |
// to the state for the successor on the true branch. |
bool learned = false; |
@@ -192,13 +194,19 @@ class HCheckTable : public ZoneObject { |
size_ = 0; |
cursor_ = 0; |
} else { |
+ InheritPhiOperands(succ, that, that_block, MERGE, zone); |
titzer
2014/02/04 13:12:26
Why don't you process the phis after first merging
Igor Sheludko
2014/02/05 11:28:01
Good idea!
|
+ |
bool compact = false; |
for (int i = 0; i < size_; i++) { |
HCheckTableEntry* this_entry = &entries_[i]; |
titzer
2014/02/04 13:12:26
Using the above suggestion, you can simply retain
Igor Sheludko
2014/02/05 11:28:01
Done.
|
HCheckTableEntry* that_entry = that->Find(this_entry->object_); |
+ // Keep those phis in the table that dominate succ block. |
if (that_entry == NULL) { |
- this_entry->object_ = NULL; |
- compact = true; |
+ if (!this_entry->object_->IsPhi() || |
+ !this_entry->object_->block()->EqualToOrDominates(succ)) { |
+ this_entry->object_ = NULL; |
+ compact = true; |
+ } |
} else { |
this_entry->maps_ = |
this_entry->maps_->Union(that_entry->maps_, phase_->zone()); |
@@ -219,6 +227,43 @@ class HCheckTable : public ZoneObject { |
return this; |
} |
+ enum InheritPhiOperandsMode { COPY, MERGE }; |
+ void InheritPhiOperands(HBasicBlock* succ, HCheckTable* that, |
+ HBasicBlock* that_block, InheritPhiOperandsMode mode, |
+ Zone* zone) { |
+ if (succ->predecessors()->length() == 1) return; |
titzer
2014/02/04 13:12:26
I think you want to check succ->phis()->length() =
Igor Sheludko
2014/02/05 11:28:01
Done.
|
+ |
+ int pred_index = succ->PredecessorIndexOf(that_block); |
+ |
+ for (int i = 0; i < that->size_; i++) { |
+ HCheckTableEntry* that_entry = &that->entries_[i]; |
+ if (that_entry->object_ != NULL) { |
+ HPhi* phi = NULL; |
+ for (int phi_index = 0; |
+ phi_index < succ->phis()->length(); |
+ ++phi_index) { |
+ HPhi* tmp_phi = succ->phis()->at(phi_index); |
+ if (tmp_phi->OperandAt(pred_index) == that_entry->object_) { |
+ phi = tmp_phi; |
+ break; |
+ } |
+ } |
+ |
+ if (phi != NULL) { |
+ // Found a |phi| with operand equal to |that_entry->object_|. |
+ HCheckTableEntry* phi_entry = (mode == MERGE) ? Find(phi) : NULL; |
+ if (phi_entry == NULL) { |
+ // Create an entry for a phi in the table. |
+ Insert(phi, NULL, that_entry->maps_); |
+ } else { |
+ phi_entry->maps_ = |
+ phi_entry->maps_->Union(that_entry->maps_, phase_->zone()); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
void ReduceCheckMaps(HCheckMaps* instr) { |
HValue* object = instr->value()->ActualValue(); |
HCheckTableEntry* entry = Find(object); |
@@ -244,14 +289,42 @@ class HCheckTable : public ZoneObject { |
} |
return; |
} |
- i = i->Intersect(a, phase_->zone()); |
- if (i->size() == 0) { |
+ MapSet intersection = i->Intersect(a, phase_->zone()); |
+ if (intersection->size() == 0) { |
// Intersection is empty; probably megamorphic, which is likely to |
// deopt anyway, so just leave things as they are. |
INC_STAT(empty_); |
} else { |
- // TODO(titzer): replace the first check with a more strict check |
- INC_STAT(narrowed_); |
+ // Update set of maps in the entry. |
+ entry->maps_ = intersection; |
+ if (intersection->size() != i->size()) { |
+ // Narrow set of maps in the second check maps instruction. |
+ HGraph* graph = instr->block()->graph(); |
+ HCheckMaps* new_check_maps = |
+ HCheckMaps::New(graph->zone(), NULL, instr->value(), |
+ intersection, instr->typecheck()); |
+ if (entry->check_ != NULL && |
+ entry->check_->block() == instr->block()) { |
+ // There is a check in the same block so replace it with a more |
+ // strict check and eliminate the second check entirely. |
+ new_check_maps->InsertBefore(entry->check_); |
+ entry->check_->DeleteAndReplaceWith(new_check_maps); |
+ TRACE(("Check #%d narrowed to #%d\n", |
+ entry->check_->id(), new_check_maps->id())); |
+ |
+ } else { |
+ new_check_maps->InsertBefore(instr); |
+ } |
+ TRACE(("CheckMaps #%d for #%d narrowed to #%d:\n", |
+ instr->id(), instr->value()->id(), new_check_maps->id())); |
+ instr->DeleteAndReplaceWith(new_check_maps); |
+ entry->check_ = new_check_maps; |
+ |
+ if (FLAG_trace_check_elimination) { |
+ Print(); |
+ } |
+ INC_STAT(narrowed_); |
+ } |
} |
} else { |
// No entry; insert a new one. |