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

Unified Diff: src/hydrogen-check-elimination.cc

Issue 141653009: Check elimination improvement: propagation of state through phis is supported, CheckMap narrowing i… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-flow-engine.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen-check-elimination.cc
diff --git a/src/hydrogen-check-elimination.cc b/src/hydrogen-check-elimination.cc
index ae11042ba1e449b3c33b2d036ca36477165142d6..627a1adc61fe6c1a6dddc4fa7399aaadbe64fdca 100644
--- a/src/hydrogen-check-elimination.cc
+++ b/src/hydrogen-check-elimination.cc
@@ -117,7 +117,7 @@ class HCheckTable : public ZoneObject {
}
// Global analysis: Copy state to successor block.
- HCheckTable* Copy(HBasicBlock* succ, Zone* zone) {
+ HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) {
HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_);
for (int i = 0; i < size_; i++) {
HCheckTableEntry* old_entry = &entries_[i];
@@ -130,8 +130,11 @@ 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;
HControlInstruction* end = succ->predecessors()->at(0)->end();
if (succ->predecessors()->length() == 1 && end->SuccessorAt(0) == succ) {
if (end->IsCompareMap()) {
@@ -146,6 +149,7 @@ class HCheckTable : public ZoneObject {
list->Add(cmp->map(), phase_->zone());
entry->maps_ = list;
}
+ learned = true;
} else if (end->IsCompareObjectEqAndBranch()) {
// Learn on the true branch of if(CmpObjectEq(x, y)).
HCompareObjectEqAndBranch* cmp =
@@ -165,37 +169,99 @@ class HCheckTable : public ZoneObject {
le->maps_ = intersect;
re->maps_ = intersect->Copy(zone);
}
+ learned = true;
}
// Learning on false branches requires storing negative facts.
}
+ if (FLAG_trace_check_elimination) {
+ PrintF("B%d checkmaps-table %s from B%d:\n",
+ succ->block_id(),
+ learned ? "learned" : "copied",
+ from_block->block_id());
+ copy->Print();
+ }
+
return copy;
}
// Global analysis: Merge this state with the other incoming state.
- HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, Zone* zone) {
- if (that->size_ == 0) {
- // If the other state is empty, simply reset.
- size_ = 0;
- cursor_ = 0;
- return this;
- }
- bool compact = false;
- for (int i = 0; i < size_; i++) {
- HCheckTableEntry* this_entry = &entries_[i];
- HCheckTableEntry* that_entry = that->Find(this_entry->object_);
- if (that_entry == NULL) {
- this_entry->object_ = NULL;
- compact = true;
+ void Merge(HBasicBlock* succ, HCheckTable* that,
+ HBasicBlock* that_block, Zone* zone) {
+ if (that_block->IsReachable()) {
+ if (that->size_ == 0) {
+ // If the other state is empty, simply reset.
+ size_ = 0;
+ cursor_ = 0;
} else {
- this_entry->maps_ = this_entry->maps_->Union(
- that_entry->maps_, phase_->zone());
- if (this_entry->check_ != that_entry->check_) this_entry->check_ = NULL;
- ASSERT(this_entry->maps_->size() > 0);
+ InheritPhiOperands(succ, that, that_block, MERGE, zone);
+
+ bool compact = false;
+ for (int i = 0; i < size_; i++) {
+ HCheckTableEntry* this_entry = &entries_[i];
+ HCheckTableEntry* that_entry = that->Find(this_entry->object_);
+ // Keep those phis in the table that dominate succ block.
+ if (that_entry == NULL) {
+ 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());
+ if (this_entry->check_ != that_entry->check_) {
+ this_entry->check_ = NULL;
+ }
+ ASSERT(this_entry->maps_->size() > 0);
+ }
+ }
+ if (compact) Compact();
+ }
+ }
+
+ if (FLAG_trace_check_elimination) {
+ PrintF("B%d checkmaps-table merged with B%d table:\n",
+ succ->block_id(), that_block->block_id());
+ Print();
+ }
+ }
+
+ enum InheritPhiOperandsMode { COPY, MERGE };
+ void InheritPhiOperands(HBasicBlock* succ, HCheckTable* that,
+ HBasicBlock* that_block, InheritPhiOperandsMode mode,
+ Zone* zone) {
+ if (succ->predecessors()->length() == 1) return;
+
+ 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());
+ }
+ }
}
}
- if (compact) Compact();
- return this;
}
void ReduceCheckMaps(HCheckMaps* instr) {
@@ -208,21 +274,49 @@ class HCheckTable : public ZoneObject {
if (a->IsSubset(i)) {
// The first check is more strict; the second is redundant.
if (entry->check_ != NULL) {
+ TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
+ instr->id(), instr->block()->block_id(), entry->check_->id()));
instr->DeleteAndReplaceWith(entry->check_);
INC_STAT(redundant_);
} else {
- instr->DeleteAndReplaceWith(instr->value());
+ TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n",
+ instr->id(), instr->block()->block_id()));
+ // Mark check as dead but leave it in the graph as a checkpoint for
+ // subsequent checks.
+ instr->SetFlag(HValue::kIsDead);
+ entry->check_ = instr;
INC_STAT(removed_);
}
return;
}
- i = i->Intersect(a, phase_->zone());
- if (i->size() == 0) {
+ MapSet narrowed_maps = i->Intersect(a, phase_->zone());
titzer 2014/01/23 18:40:55 Would prefer the name "intersection" instead of na
Igor Sheludko 2014/01/29 12:27:13 Done.
+ if (narrowed_maps->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
+ // Narrow set of maps in the second check and replace the first
+ // check with a more strict one.
+ entry->maps_ = narrowed_maps;
+ if (narrowed_maps->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(),
+ narrowed_maps, instr->typecheck());
+ 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);
titzer 2014/01/23 18:40:55 I think you want to replace both entry->check_ (if
Igor Sheludko 2014/01/29 12:27:13 Done.
+ entry->check_ = new_check_maps;
+ } else {
+ TRACE(("CheckMaps #%d for #%d narrowed:\n",
+ instr->id(), instr->value()->id()));
titzer 2014/01/23 18:40:55 In this case, you haven't actually changed anythin
Igor Sheludko 2014/01/29 12:27:13 Done.
+ entry->check_ = instr;
+ }
+ if (FLAG_trace_check_elimination) {
+ Print();
+ }
INC_STAT(narrowed_);
}
} else {
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-flow-engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698