// Copyright 2013 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 #include "src/v8.h" #include "graph-tester.h" #include "src/compiler/node.h" #include "src/compiler/operator.h" using namespace v8::internal; using namespace v8::internal::compiler; static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, "dummy", 0, 0, 0, 1, 0, 0); TEST(NodeAllocation) { GraphTester graph; Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); CHECK(n2->id() != n1->id()); } TEST(NodeWithOpcode) { GraphTester graph; Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); CHECK(n1->op() == &dummy_operator); CHECK(n2->op() == &dummy_operator); } TEST(NodeInputs1) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); CHECK_EQ(1, n2->InputCount()); CHECK(n0 == n2->InputAt(0)); } TEST(NodeInputs2) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); CHECK_EQ(2, n2->InputCount()); CHECK(n0 == n2->InputAt(0)); CHECK(n1 == n2->InputAt(1)); } TEST(NodeInputs3) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1, n1); CHECK_EQ(3, n2->InputCount()); CHECK(n0 == n2->InputAt(0)); CHECK(n1 == n2->InputAt(1)); CHECK(n1 == n2->InputAt(2)); } TEST(NodeInputIteratorEmpty) { GraphTester graph; Node* n1 = graph.NewNode(&dummy_operator); Node::Inputs::iterator i(n1->inputs().begin()); int input_count = 0; for (; i != n1->inputs().end(); ++i) { input_count++; } CHECK_EQ(0, input_count); } TEST(NodeInputIteratorOne) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node::Inputs::iterator i(n1->inputs().begin()); CHECK_EQ(1, n1->InputCount()); CHECK_EQ(n0, *i); ++i; CHECK(n1->inputs().end() == i); } TEST(NodeUseIteratorEmpty) { GraphTester graph; Node* n1 = graph.NewNode(&dummy_operator); int use_count = 0; for (Edge const edge : n1->use_edges()) { USE(edge); use_count++; } CHECK_EQ(0, use_count); } TEST(NodeUseIteratorOne) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node::Uses::iterator i(n0->uses().begin()); CHECK_EQ(n1, *i); ++i; CHECK(n0->uses().end() == i); } TEST(NodeUseIteratorReplaceNoUses) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); Node* n3 = graph.NewNode(&dummy_operator, n2); n0->ReplaceUses(n1); CHECK(n0->uses().begin() == n0->uses().end()); n0->ReplaceUses(n2); CHECK(n0->uses().begin() == n0->uses().end()); USE(n3); } TEST(NodeUseIteratorReplaceUses) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); Node::Uses::iterator i1(n0->uses().begin()); CHECK_EQ(n1, *i1); ++i1; CHECK_EQ(n2, *i1); n0->ReplaceUses(n3); Node::Uses::iterator i2(n3->uses().begin()); CHECK_EQ(n1, *i2); ++i2; CHECK_EQ(n2, *i2); Node::Inputs::iterator i3(n1->inputs().begin()); CHECK_EQ(n3, *i3); ++i3; CHECK(n1->inputs().end() == i3); Node::Inputs::iterator i4(n2->inputs().begin()); CHECK_EQ(n3, *i4); ++i4; CHECK(n2->inputs().end() == i4); } TEST(NodeUseIteratorReplaceUsesSelf) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); n1->ReplaceInput(0, n1); // Create self-reference. Node::Uses::iterator i1(n1->uses().begin()); CHECK_EQ(n1, *i1); n1->ReplaceUses(n3); CHECK(n1->uses().begin() == n1->uses().end()); Node::Uses::iterator i2(n3->uses().begin()); CHECK_EQ(n1, *i2); ++i2; CHECK(n1->uses().end() == i2); } TEST(ReplaceInput) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); Node::Inputs::iterator i1(n3->inputs().begin()); CHECK(n0 == *i1); CHECK_EQ(n0, n3->InputAt(0)); ++i1; CHECK_EQ(n1, *i1); CHECK_EQ(n1, n3->InputAt(1)); ++i1; CHECK_EQ(n2, *i1); CHECK_EQ(n2, n3->InputAt(2)); ++i1; CHECK(i1 == n3->inputs().end()); Node::Uses::iterator i2(n1->uses().begin()); CHECK_EQ(n3, *i2); ++i2; CHECK(i2 == n1->uses().end()); Node* n4 = graph.NewNode(&dummy_operator); Node::Uses::iterator i3(n4->uses().begin()); CHECK(i3 == n4->uses().end()); n3->ReplaceInput(1, n4); Node::Uses::iterator i4(n1->uses().begin()); CHECK(i4 == n1->uses().end()); Node::Uses::iterator i5(n4->uses().begin()); CHECK_EQ(n3, *i5); ++i5; CHECK(i5 == n4->uses().end()); Node::Inputs::iterator i6(n3->inputs().begin()); CHECK(n0 == *i6); CHECK_EQ(n0, n3->InputAt(0)); ++i6; CHECK_EQ(n4, *i6); CHECK_EQ(n4, n3->InputAt(1)); ++i6; CHECK_EQ(n2, *i6); CHECK_EQ(n2, n3->InputAt(2)); ++i6; CHECK(i6 == n3->inputs().end()); } TEST(OwnedBy) { GraphTester graph; { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); CHECK(!n0->OwnedBy(n1)); CHECK(!n1->OwnedBy(n0)); Node* n2 = graph.NewNode(&dummy_operator, n0); CHECK(n0->OwnedBy(n2)); CHECK(!n2->OwnedBy(n0)); Node* n3 = graph.NewNode(&dummy_operator, n0); CHECK(!n0->OwnedBy(n2)); CHECK(!n0->OwnedBy(n3)); CHECK(!n2->OwnedBy(n0)); CHECK(!n3->OwnedBy(n0)); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); CHECK(n0->OwnedBy(n1)); CHECK(!n1->OwnedBy(n0)); Node* n2 = graph.NewNode(&dummy_operator, n0); CHECK(!n0->OwnedBy(n1)); CHECK(!n0->OwnedBy(n2)); CHECK(!n1->OwnedBy(n0)); CHECK(!n1->OwnedBy(n2)); CHECK(!n2->OwnedBy(n0)); CHECK(!n2->OwnedBy(n1)); Node* n3 = graph.NewNode(&dummy_operator); n2->ReplaceInput(0, n3); CHECK(n0->OwnedBy(n1)); CHECK(!n1->OwnedBy(n0)); CHECK(!n1->OwnedBy(n0)); CHECK(!n1->OwnedBy(n2)); CHECK(!n2->OwnedBy(n0)); CHECK(!n2->OwnedBy(n1)); CHECK(n3->OwnedBy(n2)); CHECK(!n2->OwnedBy(n3)); } } TEST(Uses) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); CHECK_EQ(1, n0->UseCount()); printf("A: %d vs %d\n", n0->UseAt(0)->id(), n1->id()); CHECK(n0->UseAt(0) == n1); Node* n2 = graph.NewNode(&dummy_operator, n0); CHECK_EQ(2, n0->UseCount()); printf("B: %d vs %d\n", n0->UseAt(1)->id(), n2->id()); CHECK(n0->UseAt(1) == n2); Node* n3 = graph.NewNode(&dummy_operator, n0); CHECK_EQ(3, n0->UseCount()); CHECK(n0->UseAt(2) == n3); } TEST(Inputs) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); CHECK_EQ(3, n3->InputCount()); CHECK(n3->InputAt(0) == n0); CHECK(n3->InputAt(1) == n1); CHECK(n3->InputAt(2) == n2); Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2); n3->AppendInput(graph.zone(), n4); CHECK_EQ(4, n3->InputCount()); CHECK(n3->InputAt(0) == n0); CHECK(n3->InputAt(1) == n1); CHECK(n3->InputAt(2) == n2); CHECK(n3->InputAt(3) == n4); Node* n5 = graph.NewNode(&dummy_operator, n4); n3->AppendInput(graph.zone(), n4); CHECK_EQ(5, n3->InputCount()); CHECK(n3->InputAt(0) == n0); CHECK(n3->InputAt(1) == n1); CHECK(n3->InputAt(2) == n2); CHECK(n3->InputAt(3) == n4); CHECK(n3->InputAt(4) == n4); // Make sure uses have been hooked op correctly. Node::Uses uses(n4->uses()); Node::Uses::iterator current = uses.begin(); CHECK(current != uses.end()); CHECK(*current == n3); ++current; CHECK(current != uses.end()); CHECK(*current == n5); ++current; CHECK(current != uses.end()); CHECK(*current == n3); ++current; CHECK(current == uses.end()); } TEST(RemoveInput) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n1->RemoveInput(0); CHECK_EQ(0, n1->InputCount()); CHECK_EQ(1, n0->UseCount()); n2->RemoveInput(0); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); n2->RemoveInput(0); CHECK_EQ(0, n2->InputCount()); } TEST(AppendInputsAndIterator) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); Node::InputEdges inputs(n2->input_edges()); Node::InputEdges::iterator current = inputs.begin(); CHECK(current != inputs.end()); CHECK((*current).to() == n0); ++current; CHECK(current != inputs.end()); CHECK((*current).to() == n1); ++current; CHECK(current == inputs.end()); Node* n3 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n3); inputs = n2->input_edges(); current = inputs.begin(); CHECK(current != inputs.end()); CHECK((*current).to() == n0); CHECK_EQ(0, (*current).index()); ++current; CHECK(current != inputs.end()); CHECK((*current).to() == n1); CHECK_EQ(1, (*current).index()); ++current; CHECK(current != inputs.end()); CHECK((*current).to() == n3); CHECK_EQ(2, (*current).index()); ++current; CHECK(current == inputs.end()); } TEST(NullInputsSimple) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); CHECK_EQ(2, n2->InputCount()); CHECK(n0 == n2->InputAt(0)); CHECK(n1 == n2->InputAt(1)); CHECK_EQ(2, n0->UseCount()); n2->ReplaceInput(0, NULL); CHECK(NULL == n2->InputAt(0)); CHECK(n1 == n2->InputAt(1)); CHECK_EQ(1, n0->UseCount()); } TEST(NullInputsAppended) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator, n0); n3->AppendInput(graph.zone(), n1); n3->AppendInput(graph.zone(), n2); CHECK_EQ(3, n3->InputCount()); CHECK(n0 == n3->InputAt(0)); CHECK(n1 == n3->InputAt(1)); CHECK(n2 == n3->InputAt(2)); CHECK_EQ(1, n1->UseCount()); n3->ReplaceInput(1, NULL); CHECK(n0 == n3->InputAt(0)); CHECK(NULL == n3->InputAt(1)); CHECK(n2 == n3->InputAt(2)); CHECK_EQ(0, n1->UseCount()); } TEST(ReplaceUsesFromAppendedInputs) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n1); n2->AppendInput(graph.zone(), n0); CHECK_EQ(0, n3->UseCount()); CHECK_EQ(3, n0->UseCount()); n0->ReplaceUses(n3); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(3, n3->UseCount()); Node::Uses uses(n3->uses()); Node::Uses::iterator current = uses.begin(); CHECK(current != uses.end()); CHECK(*current == n1); ++current; CHECK(current != uses.end()); CHECK(*current == n2); ++current; CHECK(current != uses.end()); CHECK(*current == n2); ++current; CHECK(current == uses.end()); } template struct FixedPredicate { bool operator()(const Node* node) const { return result; } }; TEST(ReplaceUsesIfWithFixedPredicate) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); CHECK_EQ(0, n2->UseCount()); n2->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(0, n2->UseCount()); n2->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(0, n2->UseCount()); CHECK_EQ(0, n3->UseCount()); n3->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(0, n3->UseCount()); n3->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(0, n3->UseCount()); CHECK_EQ(2, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); n0->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(2, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); n0->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(2, n1->UseCount()); n1->AppendInput(graph.zone(), n1); CHECK_EQ(3, n1->UseCount()); n1->AppendInput(graph.zone(), n3); CHECK_EQ(1, n3->UseCount()); n3->ReplaceUsesIf(FixedPredicate(), n1); CHECK_EQ(4, n1->UseCount()); CHECK_EQ(0, n3->UseCount()); n1->ReplaceUsesIf(FixedPredicate(), n3); CHECK_EQ(4, n1->UseCount()); CHECK_EQ(0, n3->UseCount()); } TEST(ReplaceUsesIfWithEqualTo) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); CHECK_EQ(0, n2->UseCount()); n2->ReplaceUsesIf(std::bind1st(std::equal_to(), n1), n0); CHECK_EQ(0, n2->UseCount()); CHECK_EQ(2, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); n1->ReplaceUsesIf(std::bind1st(std::equal_to(), n0), n0); CHECK_EQ(2, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); n0->ReplaceUsesIf(std::bind2nd(std::equal_to(), n2), n1); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(2, n1->UseCount()); } TEST(ReplaceInputMultipleUses) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->ReplaceInput(0, n1); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); Node* n3 = graph.NewNode(&dummy_operator, n0); n3->ReplaceInput(0, n1); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(2, n1->UseCount()); } TEST(TrimInputCountInline) { GraphTester graph; { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); n1->TrimInputCount(1); CHECK_EQ(1, n1->InputCount()); CHECK_EQ(n0, n1->InputAt(0)); CHECK_EQ(1, n0->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); n1->TrimInputCount(0); CHECK_EQ(0, n1->InputCount()); CHECK_EQ(0, n0->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(2); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n0); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n0); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } } TEST(TrimInputCountOutOfLine1) { GraphTester graph; { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); n1->AppendInput(graph.zone(), n0); n1->TrimInputCount(1); CHECK_EQ(1, n1->InputCount()); CHECK_EQ(n0, n1->InputAt(0)); CHECK_EQ(1, n0->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); n1->AppendInput(graph.zone(), n0); CHECK_EQ(1, n1->InputCount()); n1->TrimInputCount(0); CHECK_EQ(0, n1->InputCount()); CHECK_EQ(0, n0->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(2); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(n0, n2->InputAt(0)); CHECK_EQ(n1, n2->InputAt(1)); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(n0, n2->InputAt(0)); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n0); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(2, n0->UseCount()); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n0); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(2, n0->UseCount()); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } } TEST(TrimInputCountOutOfLine2) { GraphTester graph; { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(2); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(n0, n2->InputAt(0)); CHECK_EQ(n1, n2->InputAt(1)); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(n0, n2->InputAt(0)); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); CHECK_EQ(2, n2->InputCount()); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n0); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(2, n0->UseCount()); n2->TrimInputCount(1); CHECK_EQ(1, n2->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n0); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(2, n0->UseCount()); n2->TrimInputCount(0); CHECK_EQ(0, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n2->UseCount()); } } TEST(RemoveAllInputs) { GraphTester graph; for (int i = 0; i < 2; i++) { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2; if (i == 0) { n2 = graph.NewNode(&dummy_operator, n0, n1); } else { n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); // with out-of-line input. } n0->RemoveAllInputs(); CHECK_EQ(0, n0->InputCount()); CHECK_EQ(2, n0->UseCount()); n1->RemoveAllInputs(); CHECK_EQ(1, n1->InputCount()); CHECK_EQ(1, n0->UseCount()); CHECK_EQ(NULL, n1->InputAt(0)); CHECK_EQ(1, n1->UseCount()); n2->RemoveAllInputs(); CHECK_EQ(2, n2->InputCount()); CHECK_EQ(0, n0->UseCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(NULL, n2->InputAt(0)); CHECK_EQ(NULL, n2->InputAt(1)); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); n1->ReplaceInput(0, n1); // self-reference. CHECK_EQ(0, n0->UseCount()); CHECK_EQ(1, n1->UseCount()); n1->RemoveAllInputs(); CHECK_EQ(1, n1->InputCount()); CHECK_EQ(0, n1->UseCount()); CHECK_EQ(NULL, n1->InputAt(0)); } }