v8/test/unittests/compiler/node-unittest.cc
mstarzinger f3ca214222 [turbofan] Speed up structural graph verification.
This removes the checking for use-def and def-use chain links from the
graph verification. Presence of such links can only be violated by a bug
in the actual {Node} implementation itself. That container class is also
covered by unit tests.

The verification in question was useful in the early days when the graph
implementation itself was prone to bugs. By now it has stabilized and
spending O(n^2) time during graph verification is too wasteful to still
be considered a reasonable trade-off.

R=jarin@chromium.org
TEST=unittests/NodeTest.*

Review-Url: https://codereview.chromium.org/2140973003
Cr-Commit-Position: refs/heads/master@{#37670}
2016-07-12 09:31:12 +00:00

268 lines
8.4 KiB
C++

// 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.
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock-support.h"
using testing::Contains;
using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::UnorderedElementsAre;
namespace v8 {
namespace internal {
namespace compiler {
typedef TestWithZone NodeTest;
namespace {
const IrOpcode::Value kOpcode0 = static_cast<IrOpcode::Value>(0);
const IrOpcode::Value kOpcode1 = static_cast<IrOpcode::Value>(1);
const IrOpcode::Value kOpcode2 = static_cast<IrOpcode::Value>(2);
const Operator kOp0(kOpcode0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 0, 0);
const Operator kOp1(kOpcode1, Operator::kNoProperties, "Op1", 1, 0, 0, 1, 0, 0);
const Operator kOp2(kOpcode2, Operator::kNoProperties, "Op2", 2, 0, 0, 1, 0, 0);
} // namespace
TEST_F(NodeTest, New) {
Node* const node = Node::New(zone(), 1, &kOp0, 0, nullptr, false);
EXPECT_EQ(1U, node->id());
EXPECT_EQ(0, node->UseCount());
EXPECT_TRUE(node->uses().empty());
EXPECT_EQ(0, node->InputCount());
EXPECT_TRUE(node->inputs().empty());
EXPECT_EQ(&kOp0, node->op());
EXPECT_EQ(kOpcode0, node->opcode());
}
TEST_F(NodeTest, NewWithInputs) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(0, n0->UseCount());
EXPECT_EQ(0, n0->InputCount());
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_EQ(1, n0->UseCount());
EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1));
EXPECT_EQ(0, n1->UseCount());
EXPECT_EQ(1, n1->InputCount());
EXPECT_EQ(n0, n1->InputAt(0));
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_EQ(2, n0->UseCount());
EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2));
EXPECT_THAT(n1->uses(), UnorderedElementsAre(n2));
EXPECT_EQ(2, n2->InputCount());
EXPECT_EQ(n0, n2->InputAt(0));
EXPECT_EQ(n1, n2->InputAt(1));
}
TEST_F(NodeTest, InputIteratorEmpty) {
Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(node->inputs().begin(), node->inputs().end());
}
TEST_F(NodeTest, InputIteratorOne) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_THAT(n1->inputs(), ElementsAre(n0));
}
TEST_F(NodeTest, InputIteratorTwo) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_THAT(n2->inputs(), ElementsAre(n0, n1));
}
TEST_F(NodeTest, UseIteratorEmpty) {
Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_EQ(node->uses().begin(), node->uses().end());
}
TEST_F(NodeTest, UseIteratorOne) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_THAT(n0->uses(), ElementsAre(n1));
}
TEST_F(NodeTest, UseIteratorTwo) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2));
}
TEST_F(NodeTest, OwnedBy) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
EXPECT_FALSE(n0->OwnedBy(n0));
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
EXPECT_FALSE(n0->OwnedBy(n0));
EXPECT_FALSE(n1->OwnedBy(n1));
EXPECT_TRUE(n0->OwnedBy(n1));
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
EXPECT_FALSE(n0->OwnedBy(n0));
EXPECT_FALSE(n1->OwnedBy(n1));
EXPECT_FALSE(n2->OwnedBy(n2));
EXPECT_FALSE(n0->OwnedBy(n1));
EXPECT_FALSE(n0->OwnedBy(n2));
EXPECT_TRUE(n1->OwnedBy(n2));
EXPECT_TRUE(n0->OwnedBy(n1, n2));
n2->ReplaceInput(0, n2);
EXPECT_TRUE(n0->OwnedBy(n1));
EXPECT_TRUE(n1->OwnedBy(n2));
n2->ReplaceInput(1, n0);
EXPECT_FALSE(n0->OwnedBy(n1));
EXPECT_FALSE(n1->OwnedBy(n2));
}
TEST_F(NodeTest, ReplaceUsesNone) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* n0_n1[] = {n0, n1};
Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
Node* node = Node::New(zone(), 42, &kOp0, 0, nullptr, false);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n0);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n1);
EXPECT_TRUE(node->uses().empty());
node->ReplaceUses(n2);
EXPECT_TRUE(node->uses().empty());
}
TEST_F(NodeTest, AppendInput) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
Node* node = Node::New(zone(), 12345, &kOp0, 0, nullptr, true);
EXPECT_TRUE(node->inputs().empty());
node->AppendInput(zone(), n0);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n0));
node->AppendInput(zone(), n1);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1));
node->AppendInput(zone(), n0);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0));
node->AppendInput(zone(), n0);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0));
node->AppendInput(zone(), n1);
EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0, n1));
}
TEST_F(NodeTest, TrimThenAppend) {
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp0, 0, nullptr, false);
Node* n2 = Node::New(zone(), 2, &kOp0, 0, nullptr, false);
Node* n3 = Node::New(zone(), 3, &kOp0, 0, nullptr, false);
Node* n4 = Node::New(zone(), 4, &kOp0, 0, nullptr, false);
Node* n5 = Node::New(zone(), 5, &kOp0, 0, nullptr, false);
Node* n6 = Node::New(zone(), 6, &kOp0, 0, nullptr, false);
Node* n7 = Node::New(zone(), 7, &kOp0, 0, nullptr, false);
Node* n8 = Node::New(zone(), 8, &kOp0, 0, nullptr, false);
Node* n9 = Node::New(zone(), 9, &kOp0, 0, nullptr, false);
Node* node = Node::New(zone(), 12345, &kOp0, 0, nullptr, true);
EXPECT_TRUE(node->inputs().empty());
node->AppendInput(zone(), n0);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n0));
node->TrimInputCount(0);
EXPECT_TRUE(node->inputs().empty());
node->AppendInput(zone(), n1);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1));
node->AppendInput(zone(), n2);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n2));
node->TrimInputCount(1);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1));
node->AppendInput(zone(), n3);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3));
node->AppendInput(zone(), n4);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4));
node->AppendInput(zone(), n5);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5));
node->AppendInput(zone(), n6);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n6));
node->AppendInput(zone(), n7);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n6, n7));
node->TrimInputCount(4);
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5));
node->AppendInput(zone(), n8);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n8));
node->AppendInput(zone(), n9);
EXPECT_FALSE(node->inputs().empty());
EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n8, n9));
}
TEST_F(NodeTest, BigNodes) {
static const int kMaxSize = 512;
Node* inputs[kMaxSize];
Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
for (int i = 0; i < kMaxSize; i++) {
inputs[i] = i & 1 ? n0 : n1;
}
for (int size = 13; size <= kMaxSize; size += 9) {
Node* node = Node::New(zone(), 12345, &kOp0, size, inputs, false);
EXPECT_EQ(size, node->InputCount());
for (int i = 0; i < size; i++) {
EXPECT_EQ(inputs[i], node->InputAt(i));
}
EXPECT_THAT(n0->uses(), Contains(node));
EXPECT_THAT(n1->uses(), Contains(node));
EXPECT_THAT(node->inputs(), ElementsAreArray(inputs, size));
}
}
} // namespace compiler
} // namespace internal
} // namespace v8