| Index: src/compiler/graph-reducer.cc
|
| diff --git a/src/compiler/graph-reducer.cc b/src/compiler/graph-reducer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f062d4bea9af58f342f06ab5e4bd18dcdc45d204
|
| --- /dev/null
|
| +++ b/src/compiler/graph-reducer.cc
|
| @@ -0,0 +1,94 @@
|
| +// 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 {
|
| +
|
| +GraphReducer::GraphReducer(Graph* graph)
|
| + : graph_(graph), reducers_(Reducers::allocator_type(graph->zone())) {}
|
| +
|
| +
|
| +static bool NodeIdIsLessThan(const Node* node, NodeId id) {
|
| + return node->id() < id;
|
| +}
|
| +
|
| +
|
| +void GraphReducer::ReduceNode(Node* node) {
|
| + Reducers::iterator skip = reducers_.end();
|
| + 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 (Reducers::iterator i = reducers_.begin(); i != reducers_.end(); ++i) {
|
| + if (i == skip) continue; // Skip this reducer.
|
| + Reduction reduction = (*i)->Reduce(node);
|
| + Node* replacement = reduction.replacement();
|
| + if (replacement == NULL) {
|
| + // No change from this reducer.
|
| + } else if (replacement == node) {
|
| + // {replacement == node} represents an in-place reduction.
|
| + // Rerun all the reducers except the current one for this node,
|
| + // as now there may be more opportunities for reduction.
|
| + reduce = true;
|
| + skip = i;
|
| + break;
|
| + } else {
|
| + 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->RemoveAllInputs();
|
| + node->ReplaceUses(replacement);
|
| + return;
|
| + }
|
| + // Otherwise, {node} was replaced by a new node. Replace all old uses of
|
| + // {node} with {replacement}. New nodes created by this reduction can
|
| + // use {node}.
|
| + node->ReplaceUsesIf(
|
| + std::bind2nd(std::ptr_fun(&NodeIdIsLessThan), before), replacement);
|
| + // Unlink {node} if it's no longer used.
|
| + if (node->uses().empty()) node->RemoveAllInputs();
|
| + // Rerun all the reductions on the {replacement}.
|
| + skip = reducers_.end();
|
| + node = replacement;
|
| + reduce = true;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +// A helper class to reuse the node traversal algorithm.
|
| +struct GraphReducerVisitor V8_FINAL : public NullNodeVisitor {
|
| + explicit GraphReducerVisitor(GraphReducer* reducer) : reducer_(reducer) {}
|
| + GenericGraphVisit::Control Post(Node* node) {
|
| + reducer_->ReduceNode(node);
|
| + return GenericGraphVisit::CONTINUE;
|
| + }
|
| + GraphReducer* reducer_;
|
| +};
|
| +
|
| +
|
| +void GraphReducer::ReduceGraph() {
|
| + GraphReducerVisitor visitor(this);
|
| + // Perform a post-order reduction of all nodes starting from the end.
|
| + graph()->VisitNodeInputsFromEnd(&visitor);
|
| +}
|
| +
|
| +
|
| +// TODO(titzer): partial graph reductions.
|
| +}
|
| +}
|
| +} // namespace v8::internal::compiler
|
|
|