2014-07-30 13:54:45 +00:00
|
|
|
// Copyright 2014 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/compiler/graph-reducer.h"
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
#include "src/compiler/graph-inl.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
2014-11-13 14:06:49 +00:00
|
|
|
GraphReducer::GraphReducer(Graph* graph)
|
|
|
|
: graph_(graph), reducers_(graph->zone()) {}
|
2014-07-30 13:54:45 +00:00
|
|
|
|
|
|
|
|
2014-11-13 14:06:49 +00:00
|
|
|
static bool NodeIdIsLessThan(const Node* node, NodeId id) {
|
|
|
|
return node->id() < id;
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphReducer::ReduceNode(Node* node) {
|
2014-11-13 14:06:49 +00:00
|
|
|
static const unsigned kMaxAttempts = 16;
|
|
|
|
bool reduce = true;
|
|
|
|
for (unsigned attempts = 0; attempts <= kMaxAttempts; ++attempts) {
|
|
|
|
if (!reduce) return;
|
|
|
|
reduce = false; // Assume we don't need to rerun any reducers.
|
|
|
|
int before = graph_->NodeCount();
|
|
|
|
for (ZoneVector<Reducer*>::iterator i = reducers_.begin();
|
|
|
|
i != reducers_.end(); ++i) {
|
2014-07-30 13:54:45 +00:00
|
|
|
Reduction reduction = (*i)->Reduce(node);
|
2014-11-13 14:06:49 +00:00
|
|
|
Node* replacement = reduction.replacement();
|
|
|
|
if (replacement == NULL) {
|
2014-07-30 13:54:45 +00:00
|
|
|
// No change from this reducer.
|
2014-11-13 14:06:49 +00:00
|
|
|
} else if (replacement == node) {
|
|
|
|
// {replacement == node} represents an in-place reduction.
|
|
|
|
// Rerun all the reducers for this node, as now there may be more
|
2014-09-26 06:40:07 +00:00
|
|
|
// opportunities for reduction.
|
2014-11-13 14:06:49 +00:00
|
|
|
reduce = true;
|
|
|
|
break;
|
2014-07-30 13:54:45 +00:00
|
|
|
} else {
|
2014-11-13 14:06:49 +00:00
|
|
|
if (node == graph_->start()) graph_->SetStart(replacement);
|
|
|
|
if (node == graph_->end()) graph_->SetEnd(replacement);
|
|
|
|
// If {node} was replaced by an old node, unlink {node} and assume that
|
|
|
|
// {replacement} was already reduced and finish.
|
|
|
|
if (replacement->id() < before) {
|
|
|
|
node->ReplaceUses(replacement);
|
|
|
|
node->Kill();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Otherwise, {node} was replaced by a new node. Replace all old uses of
|
2014-07-30 13:54:45 +00:00
|
|
|
// {node} with {replacement}. New nodes created by this reduction can
|
|
|
|
// use {node}.
|
2014-11-13 14:06:49 +00:00
|
|
|
node->ReplaceUsesIf(
|
|
|
|
std::bind2nd(std::ptr_fun(&NodeIdIsLessThan), before), replacement);
|
2014-07-30 13:54:45 +00:00
|
|
|
// Unlink {node} if it's no longer used.
|
2014-09-04 09:22:10 +00:00
|
|
|
if (node->uses().empty()) {
|
|
|
|
node->Kill();
|
|
|
|
}
|
2014-11-13 14:06:49 +00:00
|
|
|
// Rerun all the reductions on the {replacement}.
|
|
|
|
node = replacement;
|
|
|
|
reduce = true;
|
|
|
|
break;
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-13 14:06:49 +00:00
|
|
|
// A helper class to reuse the node traversal algorithm.
|
|
|
|
struct GraphReducerVisitor FINAL : public NullNodeVisitor {
|
|
|
|
explicit GraphReducerVisitor(GraphReducer* reducer) : reducer_(reducer) {}
|
|
|
|
void Post(Node* node) { reducer_->ReduceNode(node); }
|
|
|
|
GraphReducer* reducer_;
|
|
|
|
};
|
2014-11-13 11:34:06 +00:00
|
|
|
|
|
|
|
|
2014-11-13 14:06:49 +00:00
|
|
|
void GraphReducer::ReduceGraph() {
|
|
|
|
GraphReducerVisitor visitor(this);
|
|
|
|
// Perform a post-order reduction of all nodes starting from the end.
|
|
|
|
graph()->VisitNodeInputsFromEnd(&visitor);
|
2014-11-13 11:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-13 14:06:49 +00:00
|
|
|
// TODO(titzer): partial graph reductions.
|
2014-09-04 09:22:10 +00:00
|
|
|
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|