[turbofan] Do not use the generic graph algorithm for widening in the typer.

This change uses an explicit queue for type-widening instead of the
generic algorithm. The trouble with the generic algorithm was that it
called the visitor on the same phi many times in a row (and thus caused
unnecessary retyping). I also think that the queue-based fixpoint is
more readable.

The CL cuts running time of the nbody-java benchmark from ~19s to ~15s,
the time spent in the typer goes from 4.5s to 1s. This is still a lot
- the root cause appears to be slow handling of union subtyping
(m*n for unions of sizes m and n). I see a re-typing of a
single phi node taking > 100ms. I will work on a fix with Andreas,
hopefully we can come up with some canonical representation
of unions at least for the common cases (union of Smi constants).

I have also changed the initial typer run to always compute a type, even
if we already had a type for the node. This fixes one assert failure
where context specialization updates a node without updating the type,
which confuses the typer when widening (as some types suddenly narrow).

BUG=
R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/689403002

Cr-Commit-Position: refs/heads/master@{#25053}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25053 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jarin@chromium.org 2014-11-03 06:09:51 +00:00
parent 8c5fdd0575
commit 2d07d76244

View File

@ -252,7 +252,7 @@ class Typer::RunVisitor : public Typer::Visitor {
redo(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {} redo(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {}
GenericGraphVisit::Control Post(Node* node) { GenericGraphVisit::Control Post(Node* node) {
if (node->op()->ValueOutputCount() > 0 && !NodeProperties::IsTyped(node)) { if (node->op()->ValueOutputCount() > 0) {
Bounds bounds = TypeNode(node); Bounds bounds = TypeNode(node);
NodeProperties::SetBounds(node, bounds); NodeProperties::SetBounds(node, bounds);
// Remember incompletely typed nodes for least fixpoint iteration. // Remember incompletely typed nodes for least fixpoint iteration.
@ -291,33 +291,64 @@ class Typer::NarrowVisitor : public Typer::Visitor {
class Typer::WidenVisitor : public Typer::Visitor { class Typer::WidenVisitor : public Typer::Visitor {
public: public:
explicit WidenVisitor(Typer* typer) : Visitor(typer) {} explicit WidenVisitor(Typer* typer)
: Visitor(typer),
local_zone_(zone()->isolate()),
enabled_(graph()->NodeCount(), true, &local_zone_),
queue_(&local_zone_) {}
GenericGraphVisit::Control Pre(Node* node) { void Run(NodeSet* nodes) {
if (node->op()->ValueOutputCount() > 0) { // Queue all the roots.
Bounds previous = BoundsOrNone(node); for (Node* node : *nodes) {
Bounds current = TypeNode(node); Queue(node);
}
// Speed up termination in the presence of range types: while (!queue_.empty()) {
current.upper = Weaken(current.upper, previous.upper); Node* node = queue_.front();
current.lower = Weaken(current.lower, previous.lower); queue_.pop();
DCHECK(previous.lower->Is(current.lower)); if (node->op()->ValueOutputCount() > 0) {
DCHECK(previous.upper->Is(current.upper)); // Enable future queuing (and thus re-typing) of this node.
enabled_[node->id()] = true;
NodeProperties::SetBounds(node, current); // Compute the new type.
// Stop when nothing changed (but allow re-entry in case it does later). Bounds previous = BoundsOrNone(node);
return previous.Narrows(current) && current.Narrows(previous) Bounds current = TypeNode(node);
? GenericGraphVisit::DEFER
: GenericGraphVisit::REENTER; // Speed up termination in the presence of range types:
} else { current.upper = Weaken(current.upper, previous.upper);
return GenericGraphVisit::SKIP; current.lower = Weaken(current.lower, previous.lower);
// Types should not get less precise.
DCHECK(previous.lower->Is(current.lower));
DCHECK(previous.upper->Is(current.upper));
NodeProperties::SetBounds(node, current);
// If something changed, push all uses into the queue.
if (!(previous.Narrows(current) && current.Narrows(previous))) {
for (Node* use : node->uses()) {
Queue(use);
}
}
}
// If there is no value output, we deliberately leave the node disabled
// for queuing - there is no need to type it.
} }
} }
GenericGraphVisit::Control Post(Node* node) { void Queue(Node* node) {
return GenericGraphVisit::REENTER; // If the node is enabled for queuing, push it to the queue and disable it
// (to avoid queuing it multiple times).
if (enabled_[node->id()]) {
queue_.push(node);
enabled_[node->id()] = false;
}
} }
private:
Zone local_zone_;
BoolVector enabled_;
ZoneQueue<Node*> queue_;
}; };
@ -326,9 +357,7 @@ void Typer::Run() {
graph_->VisitNodeInputsFromEnd(&typing); graph_->VisitNodeInputsFromEnd(&typing);
// Find least fixpoint. // Find least fixpoint.
WidenVisitor widen(this); WidenVisitor widen(this);
for (NodeSetIter it = typing.redo.begin(); it != typing.redo.end(); ++it) { widen.Run(&typing.redo);
graph_->VisitNodeUsesFrom(*it, &widen);
}
} }