2019-05-13 09:57:32 +00:00
|
|
|
// Copyright 2019 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/decompression-elimination.h"
|
2019-06-07 14:39:18 +00:00
|
|
|
#include "src/compiler/node-properties.h"
|
2019-05-13 09:57:32 +00:00
|
|
|
#include "src/compiler/simplified-operator.h"
|
|
|
|
#include "test/unittests/compiler/graph-reducer-unittest.h"
|
|
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
2019-06-07 14:39:18 +00:00
|
|
|
#include "testing/gmock-support.h"
|
2019-05-13 09:57:32 +00:00
|
|
|
|
2019-06-07 14:39:18 +00:00
|
|
|
using testing::_;
|
2019-05-13 09:57:32 +00:00
|
|
|
using testing::StrictMock;
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
class DecompressionEliminationTest : public GraphTest {
|
|
|
|
public:
|
|
|
|
DecompressionEliminationTest()
|
|
|
|
: GraphTest(),
|
|
|
|
machine_(zone(), MachineType::PointerRepresentation(),
|
|
|
|
MachineOperatorBuilder::kNoFlags),
|
|
|
|
simplified_(zone()) {}
|
|
|
|
~DecompressionEliminationTest() override = default;
|
|
|
|
|
|
|
|
protected:
|
2019-06-07 14:39:18 +00:00
|
|
|
Reduction Reduce(StrictMock<MockAdvancedReducerEditor>* editor, Node* node) {
|
|
|
|
DecompressionElimination decompression_elimination(editor, graph(),
|
2019-05-22 11:12:50 +00:00
|
|
|
machine(), common());
|
2019-05-13 09:57:32 +00:00
|
|
|
return decompression_elimination.Reduce(node);
|
|
|
|
}
|
2019-06-07 14:39:18 +00:00
|
|
|
Reduction Reduce(Node* node) {
|
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
return Reduce(&editor, node);
|
|
|
|
}
|
|
|
|
Node* GetUniqueValueUse(Node* node) {
|
|
|
|
Node* value_use = nullptr;
|
|
|
|
for (Edge edge : node->use_edges()) {
|
|
|
|
if (NodeProperties::IsValueEdge(edge)) {
|
|
|
|
if (value_use) {
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
value_use = edge.from();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Return the value use of node after the reduction, if there is exactly one
|
|
|
|
return value_use;
|
|
|
|
}
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
const Operator* DecompressionOpFromAccess(const ElementAccess access) {
|
|
|
|
switch (access.machine_type.representation()) {
|
|
|
|
case MachineRepresentation::kCompressed:
|
|
|
|
return machine()->ChangeCompressedToTagged();
|
|
|
|
case MachineRepresentation::kCompressedSigned:
|
|
|
|
return machine()->ChangeCompressedSignedToTaggedSigned();
|
|
|
|
case MachineRepresentation::kCompressedPointer:
|
|
|
|
return machine()->ChangeCompressedPointerToTaggedPointer();
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Operator* CompressionOpFromAccess(const ElementAccess access) {
|
|
|
|
switch (access.machine_type.representation()) {
|
|
|
|
case MachineRepresentation::kCompressed:
|
|
|
|
return machine()->ChangeTaggedToCompressed();
|
|
|
|
case MachineRepresentation::kCompressedSigned:
|
|
|
|
return machine()->ChangeTaggedSignedToCompressedSigned();
|
|
|
|
case MachineRepresentation::kCompressedPointer:
|
|
|
|
return machine()->ChangeTaggedPointerToCompressedPointer();
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 'Global' accesses used to simplify the tests.
|
|
|
|
ElementAccess const any_access = {kTaggedBase, kTaggedSize, Type::Any(),
|
|
|
|
MachineType::AnyCompressed(),
|
|
|
|
kNoWriteBarrier};
|
|
|
|
ElementAccess const signed_access = {kTaggedBase, kTaggedSize, Type::Any(),
|
|
|
|
MachineType::CompressedSigned(),
|
|
|
|
kNoWriteBarrier};
|
|
|
|
ElementAccess const pointer_access = {kTaggedBase, kTaggedSize, Type::Any(),
|
|
|
|
MachineType::CompressedPointer(),
|
|
|
|
kNoWriteBarrier};
|
|
|
|
const ElementAccess element_accesses[3] = {any_access, signed_access,
|
|
|
|
pointer_access};
|
|
|
|
|
2019-05-13 09:57:32 +00:00
|
|
|
MachineOperatorBuilder* machine() { return &machine_; }
|
|
|
|
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
MachineOperatorBuilder machine_;
|
|
|
|
SimplifiedOperatorBuilder simplified_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Direct Decompression & Compression.
|
2019-05-13 09:57:32 +00:00
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, BasicDecompressionCompression) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-13 09:57:32 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-13 09:57:32 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Pairs of <load, store> accesses
|
|
|
|
const std::pair<ElementAccess, ElementAccess> accesses[] = {
|
|
|
|
{any_access, any_access}, {signed_access, any_access},
|
|
|
|
{pointer_access, any_access}, {any_access, signed_access},
|
|
|
|
{signed_access, signed_access}, {any_access, pointer_access},
|
|
|
|
{pointer_access, pointer_access}};
|
2019-05-13 09:57:32 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
for (size_t i = 0; i < arraysize(accesses); ++i) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* load = graph()->NewNode(simplified()->LoadElement(accesses[i].first),
|
|
|
|
object, index, effect, control);
|
|
|
|
Node* change_to_tagged =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(accesses[i].first), load);
|
|
|
|
Node* change_to_compressed = graph()->NewNode(
|
|
|
|
CompressionOpFromAccess(accesses[i].second), change_to_tagged);
|
|
|
|
effect =
|
|
|
|
graph()->NewNode(simplified()->StoreElement(accesses[i].second), object,
|
|
|
|
index, change_to_compressed, effect, control);
|
|
|
|
|
|
|
|
// Reduce.
|
|
|
|
Reduction r = Reduce(change_to_compressed);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(load, r.replacement());
|
2019-05-13 09:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Direct Compression & Decompression
|
2019-05-13 09:57:32 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
TEST_F(DecompressionEliminationTest, BasicCompressionDecompression) {
|
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-13 09:57:32 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-13 09:57:32 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Pairs of <load, store> accesses
|
|
|
|
const std::pair<ElementAccess, ElementAccess> accesses[] = {
|
|
|
|
{any_access, any_access}, {signed_access, any_access},
|
|
|
|
{pointer_access, any_access}, {any_access, signed_access},
|
|
|
|
{signed_access, signed_access}, {any_access, pointer_access},
|
|
|
|
{pointer_access, pointer_access}};
|
2019-05-13 09:57:32 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
for (size_t i = 0; i < arraysize(accesses); ++i) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* load = graph()->NewNode(simplified()->LoadElement(accesses[i].first),
|
|
|
|
object, index, effect, control);
|
|
|
|
Node* change_to_compressed =
|
|
|
|
graph()->NewNode(CompressionOpFromAccess(accesses[i].first), load);
|
|
|
|
Node* change_to_tagged = graph()->NewNode(
|
|
|
|
DecompressionOpFromAccess(accesses[i].second), change_to_compressed);
|
|
|
|
effect = graph()->NewNode(simplified()->StoreElement(accesses[i].second),
|
|
|
|
object, index, change_to_tagged, effect, control);
|
|
|
|
|
|
|
|
// Reduce.
|
|
|
|
Reduction r = Reduce(change_to_tagged);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(load, r.replacement());
|
2019-05-13 09:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 10:45:16 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Compress after constant.
|
2019-05-28 10:45:16 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
TEST_F(DecompressionEliminationTest, CompressionAfterInt64Constant) {
|
2019-05-28 10:45:16 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define variables.
|
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
|
|
|
const int64_t constants[] = {static_cast<int64_t>(0x0000000000000000),
|
|
|
|
static_cast<int64_t>(0x0000000000000001),
|
|
|
|
static_cast<int64_t>(0x0000FFFFFFFF0000),
|
|
|
|
static_cast<int64_t>(0x7FFFFFFFFFFFFFFF),
|
|
|
|
static_cast<int64_t>(0x8000000000000000),
|
|
|
|
static_cast<int64_t>(0x8000000000000001),
|
|
|
|
static_cast<int64_t>(0x8000FFFFFFFF0000),
|
|
|
|
static_cast<int64_t>(0x8FFFFFFFFFFFFFFF),
|
|
|
|
static_cast<int64_t>(0xFFFFFFFFFFFFFFFF)};
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-05-28 10:45:16 +00:00
|
|
|
// For every Int64Constant.
|
|
|
|
for (size_t j = 0; j < arraysize(constants); ++j) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* constant = graph()->NewNode(common()->Int64Constant(constants[j]));
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_compressed = graph()->NewNode(
|
|
|
|
CompressionOpFromAccess(element_accesses[i]), constant);
|
|
|
|
effect = graph()->NewNode(simplified()->StoreElement(element_accesses[i]),
|
|
|
|
object, index, change_to_compressed, effect,
|
|
|
|
control);
|
2019-05-28 10:45:16 +00:00
|
|
|
// Reduce.
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = Reduce(change_to_compressed);
|
2019-05-28 10:45:16 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kInt32Constant);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
TEST_F(DecompressionEliminationTest, CompressionAfterHeapConstant) {
|
2019-05-28 10:45:16 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define variables.
|
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
|
|
|
const Handle<HeapNumber> heap_constants[] = {
|
|
|
|
factory()->NewHeapNumber(0.0),
|
|
|
|
factory()->NewHeapNumber(-0.0),
|
|
|
|
factory()->NewHeapNumber(11.2),
|
|
|
|
factory()->NewHeapNumber(-11.2),
|
|
|
|
factory()->NewHeapNumber(3.1415 + 1.4142),
|
|
|
|
factory()->NewHeapNumber(3.1415 - 1.4142),
|
|
|
|
factory()->NewHeapNumber(0x0000000000000000),
|
|
|
|
factory()->NewHeapNumber(0x0000000000000001),
|
|
|
|
factory()->NewHeapNumber(0x0000FFFFFFFF0000),
|
|
|
|
factory()->NewHeapNumber(0x7FFFFFFFFFFFFFFF),
|
|
|
|
factory()->NewHeapNumber(0x8000000000000000),
|
|
|
|
factory()->NewHeapNumber(0x8000000000000001),
|
|
|
|
factory()->NewHeapNumber(0x8000FFFFFFFF0000),
|
|
|
|
factory()->NewHeapNumber(0x8FFFFFFFFFFFFFFF),
|
|
|
|
factory()->NewHeapNumber(0xFFFFFFFFFFFFFFFF)};
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-05-28 10:45:16 +00:00
|
|
|
// For every HeapNumber.
|
|
|
|
for (size_t j = 0; j < arraysize(heap_constants); ++j) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* constant =
|
|
|
|
graph()->NewNode(common()->HeapConstant(heap_constants[j]));
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_compressed = graph()->NewNode(
|
|
|
|
CompressionOpFromAccess(element_accesses[i]), constant);
|
|
|
|
effect = graph()->NewNode(simplified()->StoreElement(element_accesses[i]),
|
|
|
|
object, index, change_to_compressed, effect,
|
|
|
|
control);
|
2019-05-28 10:45:16 +00:00
|
|
|
// Reduce.
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = Reduce(change_to_compressed);
|
2019-05-28 10:45:16 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-05-30 12:46:57 +00:00
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kCompressedHeapConstant);
|
2019-05-28 10:45:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 12:01:58 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Phi.
|
2019-05-24 08:55:28 +00:00
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, PhiOneDecompress) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-24 08:55:28 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
const int number_of_inputs = 1;
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
2019-05-24 08:55:28 +00:00
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Create the graph.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load);
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* phi = graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kTagged, number_of_inputs),
|
|
|
|
change_to_tagged, control);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-06-07 14:39:18 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
EXPECT_CALL(editor, ReplaceWithValue(phi, _, _, _));
|
|
|
|
Reduction r = Reduce(&editor, phi);
|
2019-05-24 08:55:28 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// Get the actual decompress after the Phi, and check against the expected
|
|
|
|
// one.
|
2019-06-07 14:39:18 +00:00
|
|
|
Node* decompress = GetUniqueValueUse(phi);
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(DecompressionOpFromAccess(element_accesses[i]), decompress->op());
|
2019-05-24 08:55:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, PhiThreeDecompressSameRepresentation) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-24 08:55:28 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
const int number_of_inputs = 3;
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
2019-05-24 08:55:28 +00:00
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Create the graph.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load1 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* load2 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* load3 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load1);
|
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load2);
|
|
|
|
Node* change_to_tagged_3 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load3);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
|
|
|
Node* phi = graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kTagged, number_of_inputs),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged_1, change_to_tagged_2, change_to_tagged_3, control);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-06-07 14:39:18 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
EXPECT_CALL(editor, ReplaceWithValue(phi, _, _, _));
|
|
|
|
Reduction r = Reduce(&editor, phi);
|
2019-05-24 08:55:28 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// Get the actual decompress after the Phi, and check against the expected
|
|
|
|
// one.
|
2019-06-07 14:39:18 +00:00
|
|
|
Node* decompress = GetUniqueValueUse(phi);
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(DecompressionOpFromAccess(element_accesses[i]), decompress->op());
|
2019-05-24 08:55:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, PhiThreeDecompressOneAnyRepresentation) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-24 08:55:28 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
const int number_of_inputs = 3;
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Signed and Pointer (and not Any) accesses.
|
|
|
|
const ElementAccess not_any_accesses[] = {signed_access, pointer_access};
|
2019-05-24 08:55:28 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(not_any_accesses); ++i) {
|
|
|
|
// Create the graph.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load1 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(not_any_accesses[i]), object,
|
2019-05-24 08:55:28 +00:00
|
|
|
index, effect, control);
|
|
|
|
Node* load2 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(not_any_accesses[i]), object,
|
2019-05-24 08:55:28 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
// Note that load3 loads a CompressedAny instead of not_any_accesses[i]
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load3 = graph()->NewNode(simplified()->LoadElement(any_access),
|
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(not_any_accesses[i]), load1);
|
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(not_any_accesses[i]), load2);
|
|
|
|
Node* change_to_tagged_3 =
|
2019-05-24 08:55:28 +00:00
|
|
|
graph()->NewNode(machine()->ChangeCompressedToTagged(), load3);
|
|
|
|
|
|
|
|
Node* phi = graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kTagged, number_of_inputs),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged_1, change_to_tagged_2, change_to_tagged_3, control);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-06-07 14:39:18 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
EXPECT_CALL(editor, ReplaceWithValue(phi, _, _, _));
|
|
|
|
Reduction r = Reduce(&editor, phi);
|
2019-05-24 08:55:28 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// Get the actual decompress after the Phi, and check against the expected
|
|
|
|
// one.
|
2019-06-07 14:39:18 +00:00
|
|
|
Node* decompress = GetUniqueValueUse(phi);
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(machine()->ChangeCompressedToTagged(), decompress->op());
|
2019-05-24 08:55:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, PhiThreeInputsOneNotDecompressed) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-24 08:55:28 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
const int number_of_inputs = 3;
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
2019-05-24 08:55:28 +00:00
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Create the graph.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load1 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* load2 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* load3 =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load1);
|
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load2);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
|
|
|
Node* phi = graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kTagged, number_of_inputs),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged_1, change_to_tagged_2, load3, control);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-24 08:55:28 +00:00
|
|
|
Reduction r = Reduce(phi);
|
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// In the case of having one decompress Signed and one Pointer, we have to
|
|
|
|
// generate the conservative decompress any after the Phi.
|
|
|
|
TEST_F(DecompressionEliminationTest, PhiTwoDecompressesOneSignedOnePointer) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-24 08:55:28 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
const int number_of_inputs = 2;
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Create the graph.
|
2019-05-24 08:55:28 +00:00
|
|
|
Node* load1 = graph()->NewNode(simplified()->LoadElement(signed_access),
|
|
|
|
object, index, effect, control);
|
|
|
|
Node* load2 = graph()->NewNode(simplified()->LoadElement(pointer_access),
|
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(signed_access), load1);
|
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(pointer_access), load2);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
|
|
|
Node* phi = graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kTagged, number_of_inputs),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged_1, change_to_tagged_2, control);
|
2019-05-24 08:55:28 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-06-07 14:39:18 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
EXPECT_CALL(editor, ReplaceWithValue(phi, _, _, _));
|
|
|
|
Reduction r = Reduce(&editor, phi);
|
2019-05-24 08:55:28 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// Get the actual decompress after the Phi, and check against the expected
|
|
|
|
// one.
|
2019-06-07 14:39:18 +00:00
|
|
|
Node* decompress = GetUniqueValueUse(phi);
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(machine()->ChangeCompressedToTagged(), decompress->op());
|
2019-05-24 08:55:28 +00:00
|
|
|
}
|
|
|
|
|
2019-05-22 11:19:14 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// TypedStateValues.
|
2019-05-22 11:19:14 +00:00
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, TypedStateValuesOneDecompress) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:19:14 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
2019-06-24 10:34:00 +00:00
|
|
|
const int number_of_inputs = 1;
|
2019-05-22 11:19:14 +00:00
|
|
|
const ZoneVector<MachineType>* types =
|
|
|
|
new (graph()->zone()->New(sizeof(ZoneVector<MachineType>)))
|
2019-06-24 10:34:00 +00:00
|
|
|
ZoneVector<MachineType>(number_of_inputs, graph()->zone());
|
2019-05-22 11:19:14 +00:00
|
|
|
SparseInputMask dense = SparseInputMask::Dense();
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* load =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* change_to_tagged =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load);
|
|
|
|
Node* typedStateValues = graph()->NewNode(
|
|
|
|
common()->TypedStateValues(types, dense), change_to_tagged);
|
2019-05-22 11:19:14 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:19:14 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
DecompressionElimination decompression_elimination(&editor, graph(),
|
|
|
|
machine(), common());
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = decompression_elimination.Reduce(typedStateValues);
|
2019-05-22 11:19:14 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(r.replacement()->InputAt(0), load);
|
2019-05-22 11:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, TypedStateValuesTwoDecompresses) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:19:14 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
2019-06-24 10:34:00 +00:00
|
|
|
const int number_of_inputs = 3;
|
2019-05-22 11:19:14 +00:00
|
|
|
const ZoneVector<MachineType>* types =
|
|
|
|
new (graph()->zone()->New(sizeof(ZoneVector<MachineType>)))
|
2019-06-24 10:34:00 +00:00
|
|
|
ZoneVector<MachineType>(number_of_inputs, graph()->zone());
|
2019-05-22 11:19:14 +00:00
|
|
|
SparseInputMask dense = SparseInputMask::Dense();
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// Create the graph.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* load1 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
2019-05-22 11:19:14 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load1);
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* load2 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
2019-05-22 11:19:14 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load2);
|
|
|
|
Node* typedStateValues =
|
2019-05-22 11:19:14 +00:00
|
|
|
graph()->NewNode(common()->TypedStateValues(types, dense),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged_1, load1, change_to_tagged_2);
|
2019-05-22 11:19:14 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:19:14 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
DecompressionElimination decompression_elimination(&editor, graph(),
|
|
|
|
machine(), common());
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = decompression_elimination.Reduce(typedStateValues);
|
2019-05-22 11:19:14 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(r.replacement()->InputAt(0), load1);
|
|
|
|
// Note that the input at index 1 didn't change.
|
|
|
|
EXPECT_EQ(r.replacement()->InputAt(1), load1);
|
|
|
|
EXPECT_EQ(r.replacement()->InputAt(2), load2);
|
2019-05-22 11:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, TypedStateValuesAllDecompresses) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:19:14 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
2019-06-24 10:34:00 +00:00
|
|
|
const int number_of_inputs = 3;
|
2019-05-22 11:19:14 +00:00
|
|
|
const ZoneVector<MachineType>* types =
|
|
|
|
new (graph()->zone()->New(sizeof(ZoneVector<MachineType>)))
|
2019-06-24 10:34:00 +00:00
|
|
|
ZoneVector<MachineType>(number_of_inputs, graph()->zone());
|
2019-05-22 11:19:14 +00:00
|
|
|
SparseInputMask dense = SparseInputMask::Dense();
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// Create the graph.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* load1 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
2019-05-22 11:19:14 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load1);
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* load2 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
2019-05-22 11:19:14 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_2 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load2);
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* load3 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
2019-05-22 11:19:14 +00:00
|
|
|
index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_3 =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load3);
|
|
|
|
Node* typedStateValues = graph()->NewNode(
|
|
|
|
common()->TypedStateValues(types, dense), change_to_tagged_1,
|
|
|
|
change_to_tagged_2, change_to_tagged_3);
|
2019-05-22 11:19:14 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:19:14 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
DecompressionElimination decompression_elimination(&editor, graph(),
|
|
|
|
machine(), common());
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = decompression_elimination.Reduce(typedStateValues);
|
2019-05-22 11:19:14 +00:00
|
|
|
ASSERT_TRUE(r.Changed());
|
2019-06-24 10:34:00 +00:00
|
|
|
EXPECT_EQ(r.replacement()->InputAt(0), load1);
|
|
|
|
EXPECT_EQ(r.replacement()->InputAt(1), load2);
|
|
|
|
EXPECT_EQ(r.replacement()->InputAt(2), load3);
|
2019-05-22 11:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, TypedStateValuesNoDecompresses) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:19:14 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:19:14 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
2019-06-24 10:34:00 +00:00
|
|
|
const int number_of_inputs = 3;
|
2019-05-22 11:19:14 +00:00
|
|
|
const ZoneVector<MachineType>* types =
|
|
|
|
new (graph()->zone()->New(sizeof(ZoneVector<MachineType>)))
|
2019-06-24 10:34:00 +00:00
|
|
|
ZoneVector<MachineType>(number_of_inputs, graph()->zone());
|
2019-05-22 11:19:14 +00:00
|
|
|
SparseInputMask dense = SparseInputMask::Dense();
|
2019-06-24 10:34:00 +00:00
|
|
|
|
|
|
|
// For every access.
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* load =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* typedStateValues = graph()->NewNode(
|
2019-05-22 11:19:14 +00:00
|
|
|
common()->TypedStateValues(types, dense), load, load, load);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:19:14 +00:00
|
|
|
StrictMock<MockAdvancedReducerEditor> editor;
|
|
|
|
DecompressionElimination decompression_elimination(&editor, graph(),
|
|
|
|
machine(), common());
|
2019-06-24 10:34:00 +00:00
|
|
|
Reduction r = decompression_elimination.Reduce(typedStateValues);
|
2019-05-22 11:19:14 +00:00
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-20 09:36:35 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Word64Equal comparison of two decompressions.
|
2019-05-20 09:36:35 +00:00
|
|
|
|
2019-05-22 11:12:50 +00:00
|
|
|
TEST_F(DecompressionEliminationTest, TwoDecompressionWord64Equal) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-20 09:36:35 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-20 09:36:35 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every decompression (lhs).
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
2019-05-20 09:36:35 +00:00
|
|
|
// For every decompression (rhs)
|
2019-06-24 10:34:00 +00:00
|
|
|
for (size_t j = 0; j < arraysize(element_accesses); ++j) {
|
|
|
|
// Create the graph.
|
2019-05-20 09:36:35 +00:00
|
|
|
Node* load1 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]),
|
2019-05-20 09:36:35 +00:00
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_1 = graph()->NewNode(
|
|
|
|
DecompressionOpFromAccess(element_accesses[i]), load1);
|
2019-05-20 09:36:35 +00:00
|
|
|
Node* load2 =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[j]),
|
2019-05-20 09:36:35 +00:00
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged_2 = graph()->NewNode(
|
|
|
|
DecompressionOpFromAccess(element_accesses[i]), load2);
|
|
|
|
Node* comparison = graph()->NewNode(
|
|
|
|
machine()->Word64Equal(), change_to_tagged_1, change_to_tagged_2);
|
|
|
|
// Reduce.
|
2019-05-20 09:36:35 +00:00
|
|
|
Reduction r = Reduce(comparison);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 13:59:33 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Word64Equal comparison of two decompressions, where lhs == rhs.
|
2019-05-16 13:59:33 +00:00
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, TwoDecompressionWord64EqualSameInput) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-16 13:59:33 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-16 13:59:33 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every access. (same for lhs and rhs)
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// Create the graph.
|
|
|
|
Node* load =
|
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]), object,
|
|
|
|
index, effect, control);
|
|
|
|
Node* change_to_tagged =
|
|
|
|
graph()->NewNode(DecompressionOpFromAccess(element_accesses[i]), load);
|
2019-05-16 13:59:33 +00:00
|
|
|
Node* comparison = graph()->NewNode(machine()->Word64Equal(),
|
2019-06-24 10:34:00 +00:00
|
|
|
change_to_tagged, change_to_tagged);
|
|
|
|
// Reduce.
|
2019-05-16 13:59:33 +00:00
|
|
|
Reduction r = Reduce(comparison);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-22 11:12:50 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2019-06-24 10:34:00 +00:00
|
|
|
// Word64Equal comparison of decompress and a constant.
|
2019-05-22 11:12:50 +00:00
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, DecompressionConstantWord64Equal) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:12:50 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
|
|
|
const int64_t constants[] = {static_cast<int64_t>(0x0000000000000000),
|
|
|
|
static_cast<int64_t>(0x0000000000000001),
|
|
|
|
static_cast<int64_t>(0x0000FFFFFFFF0000),
|
|
|
|
static_cast<int64_t>(0x7FFFFFFFFFFFFFFF),
|
|
|
|
static_cast<int64_t>(0x8000000000000000),
|
|
|
|
static_cast<int64_t>(0x8000000000000001),
|
|
|
|
static_cast<int64_t>(0x8000FFFFFFFF0000),
|
|
|
|
static_cast<int64_t>(0x8FFFFFFFFFFFFFFF),
|
|
|
|
static_cast<int64_t>(0xFFFFFFFFFFFFFFFF)};
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every decompression (lhs).
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// For every constant (rhs).
|
|
|
|
for (size_t j = 0; j < arraysize(constants); ++j) {
|
|
|
|
// Test with both (lhs, rhs) combinations.
|
|
|
|
for (bool lhs_is_decompression : {false, true}) {
|
|
|
|
// Create the graph.
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* load =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]),
|
2019-05-22 11:12:50 +00:00
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged = graph()->NewNode(
|
|
|
|
DecompressionOpFromAccess(element_accesses[i]), load);
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* constant =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(common()->Int64Constant(constants[j]));
|
2019-05-22 11:12:50 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* lhs = lhs_is_decompression ? change_to_tagged : constant;
|
|
|
|
Node* rhs = lhs_is_decompression ? constant : change_to_tagged;
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* comparison = graph()->NewNode(machine()->Word64Equal(), lhs, rhs);
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:12:50 +00:00
|
|
|
Reduction r = Reduce(comparison);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DecompressionEliminationTest, DecompressionHeapConstantWord64Equal) {
|
2019-06-24 10:34:00 +00:00
|
|
|
// Skip test if pointer compression is not enabled.
|
2019-05-22 11:12:50 +00:00
|
|
|
if (!COMPRESS_POINTERS_BOOL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// Define variables.
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* const control = graph()->start();
|
|
|
|
Node* object = Parameter(Type::Any(), 0);
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* index = Parameter(Type::UnsignedSmall(), 1);
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
const Handle<HeapNumber> heap_constants[] = {
|
2019-05-22 11:12:50 +00:00
|
|
|
factory()->NewHeapNumber(0.0),
|
|
|
|
factory()->NewHeapNumber(-0.0),
|
|
|
|
factory()->NewHeapNumber(11.2),
|
|
|
|
factory()->NewHeapNumber(-11.2),
|
|
|
|
factory()->NewHeapNumber(3.1415 + 1.4142),
|
|
|
|
factory()->NewHeapNumber(3.1415 - 1.4142),
|
|
|
|
factory()->NewHeapNumber(0x0000000000000000),
|
|
|
|
factory()->NewHeapNumber(0x0000000000000001),
|
|
|
|
factory()->NewHeapNumber(0x0000FFFFFFFF0000),
|
|
|
|
factory()->NewHeapNumber(0x7FFFFFFFFFFFFFFF),
|
|
|
|
factory()->NewHeapNumber(0x8000000000000000),
|
|
|
|
factory()->NewHeapNumber(0x8000000000000001),
|
|
|
|
factory()->NewHeapNumber(0x8000FFFFFFFF0000),
|
|
|
|
factory()->NewHeapNumber(0x8FFFFFFFFFFFFFFF),
|
|
|
|
factory()->NewHeapNumber(0xFFFFFFFFFFFFFFFF)};
|
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
// For every decompression (lhs).
|
|
|
|
for (size_t i = 0; i < arraysize(element_accesses); ++i) {
|
|
|
|
// For every constant (rhs).
|
|
|
|
for (size_t j = 0; j < arraysize(heap_constants); ++j) {
|
|
|
|
// Test with both (lhs, rhs) combinations.
|
|
|
|
for (bool lhs_is_decompression : {false, true}) {
|
|
|
|
// Create the graph.
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* load =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(simplified()->LoadElement(element_accesses[i]),
|
2019-05-22 11:12:50 +00:00
|
|
|
object, index, effect, control);
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* change_to_tagged = graph()->NewNode(
|
|
|
|
DecompressionOpFromAccess(element_accesses[i]), load);
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* constant =
|
2019-06-24 10:34:00 +00:00
|
|
|
graph()->NewNode(common()->HeapConstant(heap_constants[j]));
|
2019-05-22 11:12:50 +00:00
|
|
|
|
2019-06-24 10:34:00 +00:00
|
|
|
Node* lhs = lhs_is_decompression ? change_to_tagged : constant;
|
|
|
|
Node* rhs = lhs_is_decompression ? constant : change_to_tagged;
|
2019-05-22 11:12:50 +00:00
|
|
|
Node* comparison = graph()->NewNode(machine()->Word64Equal(), lhs, rhs);
|
2019-06-24 10:34:00 +00:00
|
|
|
// Reduce.
|
2019-05-22 11:12:50 +00:00
|
|
|
Reduction r = Reduce(comparison);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-13 09:57:32 +00:00
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|