68f1a37f8e
Add a more efficient encoding for state values that have a large number of optimized-out inputs. Review-Url: https://codereview.chromium.org/2509623002 Cr-Commit-Position: refs/heads/master@{#42088}
232 lines
6.9 KiB
C++
232 lines
6.9 KiB
C++
// 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/state-values-utils.h"
|
|
#include "src/bit-vector.h"
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class StateValuesIteratorTest : public GraphTest {
|
|
public:
|
|
StateValuesIteratorTest() : GraphTest(3) {}
|
|
|
|
Node* StateValuesFromVector(NodeVector* nodes) {
|
|
int count = static_cast<int>(nodes->size());
|
|
return graph()->NewNode(
|
|
common()->StateValues(count, SparseInputMask::Dense()), count,
|
|
count == 0 ? nullptr : &(nodes->front()));
|
|
}
|
|
};
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, SimpleIteration) {
|
|
NodeVector inputs(zone());
|
|
const int count = 10;
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(count, i);
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, EmptyIteration) {
|
|
NodeVector inputs(zone());
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
for (auto node : StateValuesAccess(state_values)) {
|
|
USE(node);
|
|
FAIL();
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, NestedIteration) {
|
|
NodeVector inputs(zone());
|
|
int count = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
if (i == 2) {
|
|
// Single nested in index 2.
|
|
NodeVector nested_inputs(zone());
|
|
for (int j = 0; j < 8; j++) {
|
|
nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
inputs.push_back(StateValuesFromVector(&nested_inputs));
|
|
} else if (i == 5) {
|
|
// Double nested at index 5.
|
|
NodeVector nested_inputs(zone());
|
|
for (int j = 0; j < 8; j++) {
|
|
if (j == 7) {
|
|
NodeVector doubly_nested_inputs(zone());
|
|
for (int k = 0; k < 2; k++) {
|
|
doubly_nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
nested_inputs.push_back(StateValuesFromVector(&doubly_nested_inputs));
|
|
} else {
|
|
nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
}
|
|
inputs.push_back(StateValuesFromVector(&nested_inputs));
|
|
} else {
|
|
inputs.push_back(Int32Constant(count++));
|
|
}
|
|
}
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(count, i);
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, TreeFromVector) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
|
|
// Build the tree.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* values_node = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
|
|
// Check the tree contents with vector.
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, TreeFromVectorWithLiveness) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
// Generate the input liveness.
|
|
BitVector liveness(count, zone());
|
|
for (int i = 0; i < count; i++) {
|
|
if (i % 3 == 0) {
|
|
liveness.Add(i);
|
|
}
|
|
}
|
|
|
|
// Build the tree.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* values_node = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
|
|
// Check the tree contents with vector.
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
|
|
if (liveness.Contains(i)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
} else {
|
|
EXPECT_EQ(node.node, nullptr);
|
|
}
|
|
i++;
|
|
}
|
|
EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, BuildTreeIdentical) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
|
|
// Build two trees from the same data.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* node1 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
Node* node2 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
|
|
// The trees should be equal since the data was the same.
|
|
EXPECT_EQ(node1, node2);
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, BuildTreeWithLivenessIdentical) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
// Generate the input liveness.
|
|
BitVector liveness(count, zone());
|
|
for (int i = 0; i < count; i++) {
|
|
if (i % 3 == 0) {
|
|
liveness.Add(i);
|
|
}
|
|
}
|
|
|
|
// Build two trees from the same data.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* node1 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
Node* node2 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
|
|
// The trees should be equal since the data was the same.
|
|
EXPECT_EQ(node1, node2);
|
|
}
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|