Commit 7b33409b authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add support for advanced reducers.

An AdvancedReducer is basically a regular Reducer with an editor
that can perform graph editing operations beyond changing or
replacing the node that is currently being reduced. The GraphReducer
is the default implementation of the AdvancedReducer::Editor interface.

The ControlReducerImpl is now just an AdvancedReducer, which
temporarily requires a Finish method in the reducer to implement
the dead node trimming until we move that to the GraphReducer
(which in turn requires that all loops are connected to End).

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

Cr-Commit-Position: refs/heads/master@{#28251}
parent a5de69f4
This diff is collapsed.
...@@ -23,22 +23,18 @@ class ControlReducer { ...@@ -23,22 +23,18 @@ class ControlReducer {
public: public:
// Perform branch folding and dead code elimination on the graph. // Perform branch folding and dead code elimination on the graph.
static void ReduceGraph(Zone* zone, JSGraph* graph, static void ReduceGraph(Zone* zone, JSGraph* graph,
CommonOperatorBuilder* builder,
int max_phis_for_select = 0); int max_phis_for_select = 0);
// Trim nodes in the graph that are not reachable from end. // Trim nodes in the graph that are not reachable from end.
static void TrimGraph(Zone* zone, JSGraph* graph); static void TrimGraph(Zone* zone, JSGraph* graph);
// Reduces a single merge node and attached phis. // Reduces a single merge node and attached phis.
static Node* ReduceMerge(JSGraph* graph, CommonOperatorBuilder* builder, static Node* ReduceMerge(JSGraph* graph, Node* node,
Node* node, int max_phis_for_select = 0); int max_phis_for_select = 0);
// Testing interface. // Testing interface.
static Node* ReducePhiForTesting(JSGraph* graph, static Node* ReducePhiForTesting(JSGraph* graph, Node* node);
CommonOperatorBuilder* builder, Node* node); static Node* ReduceIfNodeForTesting(JSGraph* graph, Node* node);
static Node* ReduceIfNodeForTesting(JSGraph* graph,
CommonOperatorBuilder* builder,
Node* node);
}; };
} }
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include <functional> #include <functional>
#include <limits>
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
...@@ -12,6 +13,9 @@ namespace v8 { ...@@ -12,6 +13,9 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
bool Reducer::Finish() { return true; }
enum class GraphReducer::State : uint8_t { enum class GraphReducer::State : uint8_t {
kUnvisited, kUnvisited,
kRevisit, kRevisit,
...@@ -28,6 +32,9 @@ GraphReducer::GraphReducer(Graph* graph, Zone* zone) ...@@ -28,6 +32,9 @@ GraphReducer::GraphReducer(Graph* graph, Zone* zone)
stack_(zone) {} stack_(zone) {}
GraphReducer::~GraphReducer() {}
void GraphReducer::AddReducer(Reducer* reducer) { void GraphReducer::AddReducer(Reducer* reducer) {
reducers_.push_back(reducer); reducers_.push_back(reducer);
} }
...@@ -59,7 +66,23 @@ void GraphReducer::ReduceNode(Node* node) { ...@@ -59,7 +66,23 @@ void GraphReducer::ReduceNode(Node* node) {
} }
void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); } void GraphReducer::ReduceGraph() {
for (;;) {
ReduceNode(graph()->end());
// TODO(turbofan): Remove this once the dead node trimming is in the
// GraphReducer.
bool done = true;
for (Reducer* const reducer : reducers_) {
if (!reducer->Finish()) {
done = false;
break;
}
}
if (done) break;
// Reset all marks on the graph in preparation to re-reduce the graph.
state_.Reset(graph());
}
}
Reduction GraphReducer::Reduce(Node* const node) { Reduction GraphReducer::Reduce(Node* const node) {
...@@ -112,8 +135,8 @@ void GraphReducer::ReduceTop() { ...@@ -112,8 +135,8 @@ void GraphReducer::ReduceTop() {
if (input != node && Recurse(input)) return; if (input != node && Recurse(input)) return;
} }
// Remember the node count before reduction. // Remember the max node id before reduction.
const int node_count = graph()->NodeCount(); NodeId const max_id = graph()->NodeCount() - 1;
// All inputs should be visited or on stack. Apply reductions to node. // All inputs should be visited or on stack. Apply reductions to node.
Reduction reduction = Reduce(node); Reduction reduction = Reduce(node);
...@@ -135,39 +158,54 @@ void GraphReducer::ReduceTop() { ...@@ -135,39 +158,54 @@ void GraphReducer::ReduceTop() {
// After reducing the node, pop it off the stack. // After reducing the node, pop it off the stack.
Pop(); Pop();
// Check if we have a new replacement.
if (replacement != node) {
Replace(node, replacement, max_id);
} else {
// Revisit all uses of the node. // Revisit all uses of the node.
for (Node* const use : node->uses()) { for (Node* const user : node->uses()) {
// Don't revisit this node if it refers to itself. // Don't revisit this node if it refers to itself.
if (use != node) Revisit(use); if (user != node) Revisit(user);
}
} }
}
// Check if we have a new replacement.
if (replacement != node) { void GraphReducer::Replace(Node* node, Node* replacement) {
Replace(node, replacement, std::numeric_limits<NodeId>::max());
}
void GraphReducer::Replace(Node* node, Node* replacement, NodeId max_id) {
if (node == graph()->start()) graph()->SetStart(replacement); if (node == graph()->start()) graph()->SetStart(replacement);
if (node == graph()->end()) graph()->SetEnd(replacement); if (node == graph()->end()) graph()->SetEnd(replacement);
// If {node} was replaced by an old node, unlink {node} and assume that if (replacement->id() <= max_id) {
// {replacement} is an old node, so unlink {node} and assume that
// {replacement} was already reduced and finish. // {replacement} was already reduced and finish.
if (replacement->id() < node_count) { for (Edge edge : node->use_edges()) {
node->ReplaceUses(replacement); Node* const user = edge.from();
edge.UpdateTo(replacement);
// Don't revisit this node if it refers to itself.
if (user != node) Revisit(user);
}
node->Kill(); node->Kill();
} else { } else {
// Otherwise {node} was replaced by a new node. Replace all old uses of // Replace all old uses of {node} with {replacement}, but allow new nodes
// {node} with {replacement}. New nodes created by this reduction can // created by this reduction to use {node}.
// use {node}.
for (Edge edge : node->use_edges()) { for (Edge edge : node->use_edges()) {
if (edge.from()->id() < node_count) { Node* const user = edge.from();
if (user->id() <= max_id) {
edge.UpdateTo(replacement); edge.UpdateTo(replacement);
// Don't revisit this node if it refers to itself.
if (user != node) Revisit(user);
} }
} }
// Unlink {node} if it's no longer used. // Unlink {node} if it's no longer used.
if (node->uses().empty()) { if (node->uses().empty()) node->Kill();
node->Kill();
}
// If there was a replacement, reduce it after popping {node}. // If there was a replacement, reduce it after popping {node}.
Recurse(replacement); Recurse(replacement);
} }
}
} }
......
...@@ -17,13 +17,18 @@ class Graph; ...@@ -17,13 +17,18 @@ class Graph;
class Node; class Node;
// NodeIds are identifying numbers for nodes that can be used to index auxiliary
// out-of-line data associated with each node.
typedef int32_t NodeId;
// Represents the result of trying to reduce a node in the graph. // Represents the result of trying to reduce a node in the graph.
class Reduction final { class Reduction final {
public: public:
explicit Reduction(Node* replacement = NULL) : replacement_(replacement) {} explicit Reduction(Node* replacement = nullptr) : replacement_(replacement) {}
Node* replacement() const { return replacement_; } Node* replacement() const { return replacement_; }
bool Changed() const { return replacement() != NULL; } bool Changed() const { return replacement() != nullptr; }
private: private:
Node* replacement_; Node* replacement_;
...@@ -37,26 +42,66 @@ class Reduction final { ...@@ -37,26 +42,66 @@ class Reduction final {
// phase. // phase.
class Reducer { class Reducer {
public: public:
Reducer() {}
virtual ~Reducer() {} virtual ~Reducer() {}
// Try to reduce a node if possible. // Try to reduce a node if possible.
virtual Reduction Reduce(Node* node) = 0; virtual Reduction Reduce(Node* node) = 0;
// Ask this reducer to finish operation, returns {true} if the reducer is
// done, while {false} indicates that the graph might need to be reduced
// again.
// TODO(turbofan): Remove this once the dead node trimming is in the
// GraphReducer.
virtual bool Finish();
// Helper functions for subclasses to produce reductions for a node. // Helper functions for subclasses to produce reductions for a node.
static Reduction NoChange() { return Reduction(); } static Reduction NoChange() { return Reduction(); }
static Reduction Replace(Node* node) { return Reduction(node); } static Reduction Replace(Node* node) { return Reduction(node); }
static Reduction Changed(Node* node) { return Reduction(node); } static Reduction Changed(Node* node) { return Reduction(node); }
};
// An advanced reducer can also edit the graphs by changing and replacing nodes
// other than the one currently being reduced.
class AdvancedReducer : public Reducer {
public:
// Observe the actions of this reducer.
class Editor {
public:
virtual ~Editor() {}
// Replace {node} with {replacement}.
virtual void Replace(Node* node, Node* replacement) = 0;
// Revisit the {node} again later.
virtual void Revisit(Node* node) = 0;
};
explicit AdvancedReducer(Editor* editor) : editor_(editor) {}
protected:
// Helper functions for subclasses to produce reductions for a node.
static Reduction Replace(Node* node) { return Reducer::Replace(node); }
// Helper functions for subclasses to edit the graph.
void Replace(Node* node, Node* replacement) {
DCHECK_NOT_NULL(editor_);
editor_->Replace(node, replacement);
}
void Revisit(Node* node) {
DCHECK_NOT_NULL(editor_);
editor_->Revisit(node);
}
private: private:
DISALLOW_COPY_AND_ASSIGN(Reducer); Editor* const editor_;
}; };
// Performs an iterative reduction of a node graph. // Performs an iterative reduction of a node graph.
class GraphReducer final { class GraphReducer final : public AdvancedReducer::Editor {
public: public:
GraphReducer(Graph* graph, Zone* zone); GraphReducer(Graph* graph, Zone* zone);
~GraphReducer() final;
Graph* graph() const { return graph_; } Graph* graph() const { return graph_; }
...@@ -79,15 +124,22 @@ class GraphReducer final { ...@@ -79,15 +124,22 @@ class GraphReducer final {
// Reduce the node on top of the stack. // Reduce the node on top of the stack.
void ReduceTop(); void ReduceTop();
// Replace {node} with {replacement}.
void Replace(Node* node, Node* replacement) final;
// Replace all uses of {node} with {replacement} if the id of {replacement} is
// less than or equal to {max_id}. Otherwise, replace all uses of {node} whose
// id is less than or equal to {max_id} with the {replacement}.
void Replace(Node* node, Node* replacement, NodeId max_id);
// Node stack operations. // Node stack operations.
void Pop(); void Pop();
void Push(Node* node); void Push(Node* node);
// Revisit queue operations. // Revisit queue operations.
bool Recurse(Node* node); bool Recurse(Node* node);
void Revisit(Node* node); void Revisit(Node* node) final;
Graph* graph_; Graph* const graph_;
NodeMarker<State> state_; NodeMarker<State> state_;
ZoneVector<Reducer*> reducers_; ZoneVector<Reducer*> reducers_;
ZoneStack<Node*> revisit_; ZoneStack<Node*> revisit_;
......
...@@ -13,8 +13,8 @@ namespace compiler { ...@@ -13,8 +13,8 @@ namespace compiler {
NodeMarkerBase::NodeMarkerBase(Graph* graph, uint32_t num_states) NodeMarkerBase::NodeMarkerBase(Graph* graph, uint32_t num_states)
: mark_min_(graph->mark_max_), mark_max_(graph->mark_max_ += num_states) { : mark_min_(graph->mark_max_), mark_max_(graph->mark_max_ += num_states) {
DCHECK(num_states > 0); // user error! DCHECK_NE(0u, num_states); // user error!
DCHECK(mark_max_ > mark_min_); // check for wraparound. DCHECK_LT(mark_min_, mark_max_); // check for wraparound.
} }
...@@ -35,6 +35,14 @@ void NodeMarkerBase::Set(Node* node, Mark mark) { ...@@ -35,6 +35,14 @@ void NodeMarkerBase::Set(Node* node, Mark mark) {
node->set_mark(mark + mark_min_); node->set_mark(mark + mark_min_);
} }
void NodeMarkerBase::Reset(Graph* graph) {
uint32_t const num_states = mark_max_ - mark_min_;
mark_min_ = graph->mark_max_;
mark_max_ = graph->mark_max_ += num_states;
DCHECK_LT(mark_min_, mark_max_); // check for wraparound.
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -29,6 +29,7 @@ class NodeMarkerBase { ...@@ -29,6 +29,7 @@ class NodeMarkerBase {
Mark Get(Node* node); Mark Get(Node* node);
void Set(Node* node, Mark mark); void Set(Node* node, Mark mark);
void Reset(Graph* graph);
private: private:
Mark mark_min_; Mark mark_min_;
......
...@@ -339,12 +339,12 @@ void OsrHelper::Deconstruct(JSGraph* jsgraph, CommonOperatorBuilder* common, ...@@ -339,12 +339,12 @@ void OsrHelper::Deconstruct(JSGraph* jsgraph, CommonOperatorBuilder* common,
// but we need to avoid that because the osr_loop is reachable through // but we need to avoid that because the osr_loop is reachable through
// the second input, so reduce it and its phis manually. // the second input, so reduce it and its phis manually.
osr_loop->ReplaceInput(0, dead); osr_loop->ReplaceInput(0, dead);
Node* node = ControlReducer::ReduceMerge(jsgraph, common, osr_loop); Node* node = ControlReducer::ReduceMerge(jsgraph, osr_loop);
if (node != osr_loop) osr_loop->ReplaceUses(node); if (node != osr_loop) osr_loop->ReplaceUses(node);
// Run the normal control reduction, which naturally trims away the dead // Run the normal control reduction, which naturally trims away the dead
// parts of the graph. // parts of the graph.
ControlReducer::ReduceGraph(tmp_zone, jsgraph, common); ControlReducer::ReduceGraph(tmp_zone, jsgraph);
} }
......
...@@ -647,8 +647,7 @@ struct EarlyControlReductionPhase { ...@@ -647,8 +647,7 @@ struct EarlyControlReductionPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
SourcePositionTable::Scope pos(data->source_positions(), SourcePositionTable::Scope pos(data->source_positions(),
SourcePosition::Unknown()); SourcePosition::Unknown());
// TODO(turbofan): enable select matching in early control reduction. ControlReducer::ReduceGraph(temp_zone, data->jsgraph(), 0);
ControlReducer::ReduceGraph(temp_zone, data->jsgraph(), data->common(), 0);
} }
}; };
...@@ -658,7 +657,7 @@ struct LateControlReductionPhase { ...@@ -658,7 +657,7 @@ struct LateControlReductionPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
SourcePositionTable::Scope pos(data->source_positions(), SourcePositionTable::Scope pos(data->source_positions(),
SourcePosition::Unknown()); SourcePosition::Unknown());
ControlReducer::ReduceGraph(temp_zone, data->jsgraph(), data->common(), 0); ControlReducer::ReduceGraph(temp_zone, data->jsgraph(), 0);
} }
}; };
......
...@@ -41,8 +41,7 @@ class ControlReducerTest : public TypedGraphTest { ...@@ -41,8 +41,7 @@ class ControlReducerTest : public TypedGraphTest {
os << "-- Graph before control reduction" << std::endl; os << "-- Graph before control reduction" << std::endl;
os << AsRPO(*graph()); os << AsRPO(*graph());
} }
ControlReducer::ReduceGraph(zone(), jsgraph(), common(), ControlReducer::ReduceGraph(zone(), jsgraph(), max_phis_for_select);
max_phis_for_select);
if (FLAG_trace_turbo_graph) { if (FLAG_trace_turbo_graph) {
OFStream os(stdout); OFStream os(stdout);
os << "-- Graph after control reduction" << std::endl; os << "-- Graph after control reduction" << std::endl;
......
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "test/unittests/compiler/graph-reducer-unittest.h"
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_; using testing::_;
using testing::DefaultValue; using testing::DefaultValue;
...@@ -55,9 +54,9 @@ struct MockReducer : public Reducer { ...@@ -55,9 +54,9 @@ struct MockReducer : public Reducer {
// Replaces all "A" operators with "B" operators without creating new nodes. // Replaces all "A" operators with "B" operators without creating new nodes.
class InPlaceABReducer : public Reducer { class InPlaceABReducer final : public Reducer {
public: public:
virtual Reduction Reduce(Node* node) { Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeA0: case kOpcodeA0:
EXPECT_EQ(0, node->InputCount()); EXPECT_EQ(0, node->InputCount());
...@@ -78,10 +77,11 @@ class InPlaceABReducer : public Reducer { ...@@ -78,10 +77,11 @@ class InPlaceABReducer : public Reducer {
// Replaces all "A" operators with "B" operators by allocating new nodes. // Replaces all "A" operators with "B" operators by allocating new nodes.
class NewABReducer : public Reducer { class NewABReducer final : public Reducer {
public: public:
explicit NewABReducer(Graph* graph) : graph_(graph) {} explicit NewABReducer(Graph* graph) : graph_(graph) {}
virtual Reduction Reduce(Node* node) {
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeA0: case kOpcodeA0:
EXPECT_EQ(0, node->InputCount()); EXPECT_EQ(0, node->InputCount());
...@@ -96,7 +96,9 @@ class NewABReducer : public Reducer { ...@@ -96,7 +96,9 @@ class NewABReducer : public Reducer {
} }
return NoChange(); return NoChange();
} }
Graph* graph_;
private:
Graph* const graph_;
}; };
...@@ -104,7 +106,8 @@ class NewABReducer : public Reducer { ...@@ -104,7 +106,8 @@ class NewABReducer : public Reducer {
class A0Wrapper final : public Reducer { class A0Wrapper final : public Reducer {
public: public:
explicit A0Wrapper(Graph* graph) : graph_(graph) {} explicit A0Wrapper(Graph* graph) : graph_(graph) {}
virtual Reduction Reduce(Node* node) override {
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeA0: case kOpcodeA0:
EXPECT_EQ(0, node->InputCount()); EXPECT_EQ(0, node->InputCount());
...@@ -112,7 +115,9 @@ class A0Wrapper final : public Reducer { ...@@ -112,7 +115,9 @@ class A0Wrapper final : public Reducer {
} }
return NoChange(); return NoChange();
} }
Graph* graph_;
private:
Graph* const graph_;
}; };
...@@ -120,7 +125,8 @@ class A0Wrapper final : public Reducer { ...@@ -120,7 +125,8 @@ class A0Wrapper final : public Reducer {
class B0Wrapper final : public Reducer { class B0Wrapper final : public Reducer {
public: public:
explicit B0Wrapper(Graph* graph) : graph_(graph) {} explicit B0Wrapper(Graph* graph) : graph_(graph) {}
virtual Reduction Reduce(Node* node) override {
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeB0: case kOpcodeB0:
EXPECT_EQ(0, node->InputCount()); EXPECT_EQ(0, node->InputCount());
...@@ -128,13 +134,16 @@ class B0Wrapper final : public Reducer { ...@@ -128,13 +134,16 @@ class B0Wrapper final : public Reducer {
} }
return NoChange(); return NoChange();
} }
Graph* graph_;
private:
Graph* const graph_;
}; };
// Replaces all "kOpA1" nodes with the first input. // Replaces all "kOpA1" nodes with the first input.
class A1Forwarder : public Reducer { class A1Forwarder final : public Reducer {
virtual Reduction Reduce(Node* node) { public:
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeA1: case kOpcodeA1:
EXPECT_EQ(1, node->InputCount()); EXPECT_EQ(1, node->InputCount());
...@@ -146,8 +155,9 @@ class A1Forwarder : public Reducer { ...@@ -146,8 +155,9 @@ class A1Forwarder : public Reducer {
// Replaces all "kOpB1" nodes with the first input. // Replaces all "kOpB1" nodes with the first input.
class B1Forwarder : public Reducer { class B1Forwarder final : public Reducer {
virtual Reduction Reduce(Node* node) { public:
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeB1: case kOpcodeB1:
EXPECT_EQ(1, node->InputCount()); EXPECT_EQ(1, node->InputCount());
...@@ -159,9 +169,9 @@ class B1Forwarder : public Reducer { ...@@ -159,9 +169,9 @@ class B1Forwarder : public Reducer {
// Replaces all "B" operators with "C" operators without creating new nodes. // Replaces all "B" operators with "C" operators without creating new nodes.
class InPlaceBCReducer : public Reducer { class InPlaceBCReducer final : public Reducer {
public: public:
virtual Reduction Reduce(Node* node) { Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeB0: case kOpcodeB0:
EXPECT_EQ(0, node->InputCount()); EXPECT_EQ(0, node->InputCount());
...@@ -182,8 +192,9 @@ class InPlaceBCReducer : public Reducer { ...@@ -182,8 +192,9 @@ class InPlaceBCReducer : public Reducer {
// Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids. // Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids.
class AB2Sorter : public Reducer { class AB2Sorter final : public Reducer {
virtual Reduction Reduce(Node* node) { public:
Reduction Reduce(Node* node) final {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
case kOpcodeA2: case kOpcodeA2:
case kOpcodeB2: case kOpcodeB2:
...@@ -200,10 +211,59 @@ class AB2Sorter : public Reducer { ...@@ -200,10 +211,59 @@ class AB2Sorter : public Reducer {
} }
}; };
} // namespace } // namespace
class AdvancedReducerTest : public TestWithZone {
public:
AdvancedReducerTest() : graph_(zone()) {}
protected:
Graph* graph() { return &graph_; }
private:
Graph graph_;
};
TEST_F(AdvancedReducerTest, Replace) {
struct DummyReducer final : public AdvancedReducer {
explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {}
Reduction Reduce(Node* node) final {
Replace(node, node);
return NoChange();
}
};
StrictMock<MockAdvancedReducerEditor> e;
DummyReducer r(&e);
Node* node0 = graph()->NewNode(&kOpA0);
Node* node1 = graph()->NewNode(&kOpA1, node0);
EXPECT_CALL(e, Replace(node0, node0));
EXPECT_CALL(e, Replace(node1, node1));
EXPECT_FALSE(r.Reduce(node0).Changed());
EXPECT_FALSE(r.Reduce(node1).Changed());
}
TEST_F(AdvancedReducerTest, Revisit) {
struct DummyReducer final : public AdvancedReducer {
explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {}
Reduction Reduce(Node* node) final {
Revisit(node);
return NoChange();
}
};
StrictMock<MockAdvancedReducerEditor> e;
DummyReducer r(&e);
Node* node0 = graph()->NewNode(&kOpA0);
Node* node1 = graph()->NewNode(&kOpA1, node0);
EXPECT_CALL(e, Revisit(node0));
EXPECT_CALL(e, Revisit(node1));
EXPECT_FALSE(r.Reduce(node0).Changed());
EXPECT_FALSE(r.Reduce(node1).Changed());
}
class GraphReducerTest : public TestWithZone { class GraphReducerTest : public TestWithZone {
public: public:
GraphReducerTest() : graph_(zone()) {} GraphReducerTest() : graph_(zone()) {}
...@@ -573,6 +633,8 @@ TEST_F(GraphReducerTest, Sorter1) { ...@@ -573,6 +633,8 @@ TEST_F(GraphReducerTest, Sorter1) {
} }
namespace {
// Generate a node graph with the given permutations. // Generate a node graph with the given permutations.
void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { void GenDAG(Graph* graph, int* p3, int* p2, int* p1) {
Node* level4 = graph->NewNode(&kOpA0); Node* level4 = graph->NewNode(&kOpA0);
...@@ -591,6 +653,8 @@ void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { ...@@ -591,6 +653,8 @@ void GenDAG(Graph* graph, int* p3, int* p2, int* p1) {
graph->SetEnd(end); graph->SetEnd(end);
} }
} // namespace
TEST_F(GraphReducerTest, SortForwardReduce) { TEST_F(GraphReducerTest, SortForwardReduce) {
// Tests combined reductions on a series of DAGs. // Tests combined reductions on a series of DAGs.
...@@ -667,7 +731,6 @@ TEST_F(GraphReducerTest, Order) { ...@@ -667,7 +731,6 @@ TEST_F(GraphReducerTest, Order) {
} }
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
// Copyright 2015 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.
#ifndef V8_UNITTESTS_COMPILER_GRAPH_REDUCER_UNITTEST_H_
#define V8_UNITTESTS_COMPILER_GRAPH_REDUCER_UNITTEST_H_
#include "src/compiler/graph-reducer.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace v8 {
namespace internal {
namespace compiler {
struct MockAdvancedReducerEditor : public AdvancedReducer::Editor {
MOCK_METHOD1(Revisit, void(Node*));
MOCK_METHOD2(Replace, void(Node*, Node*));
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_COMPILER_GRAPH_REDUCER_UNITTEST_H_
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
'compiler/control-reducer-unittest.cc', 'compiler/control-reducer-unittest.cc',
'compiler/diamond-unittest.cc', 'compiler/diamond-unittest.cc',
'compiler/graph-reducer-unittest.cc', 'compiler/graph-reducer-unittest.cc',
'compiler/graph-reducer-unittest.h',
'compiler/graph-unittest.cc', 'compiler/graph-unittest.cc',
'compiler/graph-unittest.h', 'compiler/graph-unittest.h',
'compiler/instruction-selector-unittest.cc', 'compiler/instruction-selector-unittest.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment