| Index: test/unittests/compiler/control-equivalence-unittest.cc
|
| diff --git a/test/unittests/compiler/control-equivalence-unittest.cc b/test/unittests/compiler/control-equivalence-unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b44f671a3d0c33549841a7248da8bd1e893af2c0
|
| --- /dev/null
|
| +++ b/test/unittests/compiler/control-equivalence-unittest.cc
|
| @@ -0,0 +1,254 @@
|
| +// 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/control-equivalence.h"
|
| +#include "src/compiler/graph-visualizer.h"
|
| +#include "src/compiler/node-properties-inl.h"
|
| +#include "src/zone-containers.h"
|
| +#include "test/unittests/compiler/graph-unittest.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace compiler {
|
| +
|
| +#define ASSERT_EQUIVALENCE(...) \
|
| + do { \
|
| + Node* __n[] = {__VA_ARGS__}; \
|
| + ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \
|
| + } while (false);
|
| +
|
| +class ControlEquivalenceTest : public GraphTest {
|
| + public:
|
| + ControlEquivalenceTest() : all_nodes_(zone()), classes_(zone()) {
|
| + Store(graph()->start());
|
| + }
|
| +
|
| + protected:
|
| + void ComputeEquivalence(Node* node) {
|
| + graph()->SetEnd(graph()->NewNode(common()->End(), node));
|
| + if (FLAG_trace_turbo) {
|
| + OFStream os(stdout);
|
| + os << AsDOT(*graph());
|
| + }
|
| + ControlEquivalence equivalence(zone(), graph());
|
| + equivalence.Run(node);
|
| + classes_.resize(graph()->NodeCount());
|
| + for (Node* node : all_nodes_) {
|
| + classes_[node->id()] = equivalence.ClassOf(node);
|
| + }
|
| + }
|
| +
|
| + bool IsEquivalenceClass(size_t length, Node** nodes) {
|
| + BitVector in_class(graph()->NodeCount(), zone());
|
| + size_t expected_class = classes_[nodes[0]->id()];
|
| + for (size_t i = 0; i < length; ++i) {
|
| + in_class.Add(nodes[i]->id());
|
| + }
|
| + for (Node* node : all_nodes_) {
|
| + if (in_class.Contains(node->id())) {
|
| + if (classes_[node->id()] != expected_class) return false;
|
| + } else {
|
| + if (classes_[node->id()] == expected_class) return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + Node* Value() { return NumberConstant(0.0); }
|
| +
|
| + Node* Branch(Node* control) {
|
| + return Store(graph()->NewNode(common()->Branch(), Value(), control));
|
| + }
|
| +
|
| + Node* IfTrue(Node* control) {
|
| + return Store(graph()->NewNode(common()->IfTrue(), control));
|
| + }
|
| +
|
| + Node* IfFalse(Node* control) {
|
| + return Store(graph()->NewNode(common()->IfFalse(), control));
|
| + }
|
| +
|
| + Node* Merge2(Node* control1, Node* control2) {
|
| + return Store(graph()->NewNode(common()->Merge(2), control1, control2));
|
| + }
|
| +
|
| + Node* Loop2(Node* control) {
|
| + return Store(graph()->NewNode(common()->Loop(2), control, control));
|
| + }
|
| +
|
| + Node* End(Node* control) {
|
| + return Store(graph()->NewNode(common()->End(), control));
|
| + }
|
| +
|
| + private:
|
| + Node* Store(Node* node) {
|
| + all_nodes_.push_back(node);
|
| + return node;
|
| + }
|
| +
|
| + ZoneVector<Node*> all_nodes_;
|
| + ZoneVector<size_t> classes_;
|
| +};
|
| +
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Test cases.
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Empty1) {
|
| + Node* start = graph()->start();
|
| + ComputeEquivalence(start);
|
| +
|
| + ASSERT_EQUIVALENCE(start);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Empty2) {
|
| + Node* start = graph()->start();
|
| + Node* end = End(start);
|
| + ComputeEquivalence(end);
|
| +
|
| + ASSERT_EQUIVALENCE(start, end);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Diamond1) {
|
| + Node* start = graph()->start();
|
| + Node* b = Branch(start);
|
| + Node* t = IfTrue(b);
|
| + Node* f = IfFalse(b);
|
| + Node* m = Merge2(t, f);
|
| + ComputeEquivalence(m);
|
| +
|
| + ASSERT_EQUIVALENCE(b, m, start);
|
| + ASSERT_EQUIVALENCE(f);
|
| + ASSERT_EQUIVALENCE(t);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Diamond2) {
|
| + Node* start = graph()->start();
|
| + Node* b1 = Branch(start);
|
| + Node* t1 = IfTrue(b1);
|
| + Node* f1 = IfFalse(b1);
|
| + Node* b2 = Branch(f1);
|
| + Node* t2 = IfTrue(b2);
|
| + Node* f2 = IfFalse(b2);
|
| + Node* m2 = Merge2(t2, f2);
|
| + Node* m1 = Merge2(t1, m2);
|
| + ComputeEquivalence(m1);
|
| +
|
| + ASSERT_EQUIVALENCE(b1, m1, start);
|
| + ASSERT_EQUIVALENCE(t1);
|
| + ASSERT_EQUIVALENCE(f1, b2, m2);
|
| + ASSERT_EQUIVALENCE(t2);
|
| + ASSERT_EQUIVALENCE(f2);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Diamond3) {
|
| + Node* start = graph()->start();
|
| + Node* b1 = Branch(start);
|
| + Node* t1 = IfTrue(b1);
|
| + Node* f1 = IfFalse(b1);
|
| + Node* m1 = Merge2(t1, f1);
|
| + Node* b2 = Branch(m1);
|
| + Node* t2 = IfTrue(b2);
|
| + Node* f2 = IfFalse(b2);
|
| + Node* m2 = Merge2(t2, f2);
|
| + ComputeEquivalence(m2);
|
| +
|
| + ASSERT_EQUIVALENCE(b1, m1, b2, m2, start);
|
| + ASSERT_EQUIVALENCE(t1);
|
| + ASSERT_EQUIVALENCE(f1);
|
| + ASSERT_EQUIVALENCE(t2);
|
| + ASSERT_EQUIVALENCE(f2);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Switch1) {
|
| + Node* start = graph()->start();
|
| + Node* b1 = Branch(start);
|
| + Node* t1 = IfTrue(b1);
|
| + Node* f1 = IfFalse(b1);
|
| + Node* b2 = Branch(f1);
|
| + Node* t2 = IfTrue(b2);
|
| + Node* f2 = IfFalse(b2);
|
| + Node* b3 = Branch(f2);
|
| + Node* t3 = IfTrue(b3);
|
| + Node* f3 = IfFalse(b3);
|
| + Node* m1 = Merge2(t1, t2);
|
| + Node* m2 = Merge2(m1, t3);
|
| + Node* m3 = Merge2(m2, f3);
|
| + ComputeEquivalence(m3);
|
| +
|
| + ASSERT_EQUIVALENCE(b1, m3, start);
|
| + ASSERT_EQUIVALENCE(t1);
|
| + ASSERT_EQUIVALENCE(f1, b2);
|
| + ASSERT_EQUIVALENCE(t2);
|
| + ASSERT_EQUIVALENCE(f2, b3);
|
| + ASSERT_EQUIVALENCE(t3);
|
| + ASSERT_EQUIVALENCE(f3);
|
| + ASSERT_EQUIVALENCE(m1);
|
| + ASSERT_EQUIVALENCE(m2);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Loop1) {
|
| + Node* start = graph()->start();
|
| + Node* l = Loop2(start);
|
| + l->ReplaceInput(1, l);
|
| + ComputeEquivalence(l);
|
| +
|
| + ASSERT_EQUIVALENCE(start);
|
| + ASSERT_EQUIVALENCE(l);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Loop2) {
|
| + Node* start = graph()->start();
|
| + Node* l = Loop2(start);
|
| + Node* b = Branch(l);
|
| + Node* t = IfTrue(b);
|
| + Node* f = IfFalse(b);
|
| + l->ReplaceInput(1, t);
|
| + ComputeEquivalence(f);
|
| +
|
| + ASSERT_EQUIVALENCE(f, start);
|
| + ASSERT_EQUIVALENCE(t);
|
| + ASSERT_EQUIVALENCE(l, b);
|
| +}
|
| +
|
| +
|
| +TEST_F(ControlEquivalenceTest, Irreducible) {
|
| + Node* start = graph()->start();
|
| + Node* b1 = Branch(start);
|
| + Node* t1 = IfTrue(b1);
|
| + Node* f1 = IfFalse(b1);
|
| + Node* lp = Loop2(f1);
|
| + Node* m1 = Merge2(t1, lp);
|
| + Node* b2 = Branch(m1);
|
| + Node* t2 = IfTrue(b2);
|
| + Node* f2 = IfFalse(b2);
|
| + Node* m2 = Merge2(t2, f2);
|
| + Node* b3 = Branch(m2);
|
| + Node* t3 = IfTrue(b3);
|
| + Node* f3 = IfFalse(b3);
|
| + lp->ReplaceInput(1, f3);
|
| + ComputeEquivalence(t3);
|
| +
|
| + ASSERT_EQUIVALENCE(b1, t3, start);
|
| + ASSERT_EQUIVALENCE(t1);
|
| + ASSERT_EQUIVALENCE(f1);
|
| + ASSERT_EQUIVALENCE(m1, b2, m2, b3);
|
| + ASSERT_EQUIVALENCE(t2);
|
| + ASSERT_EQUIVALENCE(f2);
|
| + ASSERT_EQUIVALENCE(f3);
|
| + ASSERT_EQUIVALENCE(lp);
|
| +}
|
| +
|
| +
|
| +} // namespace compiler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|