Commit b05ab0af authored by Santiago Aboy Solanes's avatar Santiago Aboy Solanes Committed by Commit Bot

[ptr-compr][Turbofan] Word64Equal reducing between decompress and constant

Adding the case of having a decompress and a constant (both HeapConstant
and Int64Constant).

Cq-Include-Trybots: luci.v8.try:v8_linux64_pointer_compression_rel_ng
Cq-Include-Trybots: luci.v8.try:v8_linux64_arm64_pointer_compression_rel_ng
Bug: v8:8977, v8:7703
Change-Id: Ic9475e9762575e7f6ca2937d832638f7c9897e1d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1613253
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61736}
parent 880c3202
......@@ -10,8 +10,23 @@ namespace internal {
namespace compiler {
DecompressionElimination::DecompressionElimination(
Editor* editor, Graph* graph, MachineOperatorBuilder* machine)
: AdvancedReducer(editor), graph_(graph), machine_(machine) {}
Editor* editor, Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common)
: AdvancedReducer(editor),
graph_(graph),
machine_(machine),
common_(common) {}
bool DecompressionElimination::IsReduceableConstantOpcode(
IrOpcode::Value opcode) {
switch (opcode) {
case IrOpcode::kInt64Constant:
case IrOpcode::kHeapConstant:
return true;
default:
return false;
}
}
bool DecompressionElimination::IsValidDecompress(
IrOpcode::Value compressOpcode, IrOpcode::Value decompressOpcode) {
......@@ -30,6 +45,25 @@ bool DecompressionElimination::IsValidDecompress(
}
}
Node* DecompressionElimination::GetCompressedConstant(Node* constant) {
switch (constant->opcode()) {
case IrOpcode::kInt64Constant:
return graph()->NewNode(common()->Int32Constant(
static_cast<int32_t>(OpParameter<int64_t>(constant->op()))));
break;
case IrOpcode::kHeapConstant:
// TODO(v8:8977): The HeapConstant remains as 64 bits. This does not
// affect the comparison and it will still work correctly. However, we are
// introducing a 64 bit value in the stream where a 32 bit one will
// suffice. Currently there is no "CompressedHeapConstant", and
// introducing a new opcode and handling it correctly throught the
// pipeline seems that it will involve quite a bit of work.
return constant;
default:
UNREACHABLE();
}
}
Reduction DecompressionElimination::ReduceCompress(Node* node) {
DCHECK(IrOpcode::IsCompressOpcode(node->opcode()));
......@@ -51,9 +85,11 @@ Reduction DecompressionElimination::ReduceWord64Equal(Node* node) {
Node* lhs = node->InputAt(0);
Node* rhs = node->InputAt(1);
if (IrOpcode::IsDecompressOpcode(lhs->opcode()) &&
IrOpcode::IsDecompressOpcode(rhs->opcode())) {
// Do a Word32Equal on the two input nodes before they are decompressed.
bool lhs_is_decompress = IrOpcode::IsDecompressOpcode(lhs->opcode());
bool rhs_is_decompress = IrOpcode::IsDecompressOpcode(rhs->opcode());
// Case where both of its inputs are Decompress nodes.
if (lhs_is_decompress && rhs_is_decompress) {
DCHECK_EQ(lhs->InputCount(), 1);
node->ReplaceInput(0, lhs->InputAt(0));
DCHECK_EQ(rhs->InputCount(), 1);
......@@ -62,6 +98,20 @@ Reduction DecompressionElimination::ReduceWord64Equal(Node* node) {
return Changed(node);
}
bool lhs_is_constant = IsReduceableConstantOpcode(lhs->opcode());
bool rhs_is_constant = IsReduceableConstantOpcode(rhs->opcode());
// Case where one input is a Decompress node and the other a constant.
if ((lhs_is_decompress && rhs_is_constant) ||
(lhs_is_constant && rhs_is_decompress)) {
node->ReplaceInput(
0, lhs_is_decompress ? lhs->InputAt(0) : GetCompressedConstant(lhs));
node->ReplaceInput(
1, lhs_is_decompress ? GetCompressedConstant(rhs) : rhs->InputAt(0));
NodeProperties::ChangeOp(node, machine()->Word32Equal());
return Changed(node);
}
return NoChange();
}
......@@ -78,6 +128,7 @@ Reduction DecompressionElimination::Reduce(Node* node) {
default:
break;
}
return NoChange();
}
......
......@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_DECOMPRESSION_ELIMINATION_H_
#define V8_COMPILER_DECOMPRESSION_ELIMINATION_H_
#include "src/compiler/common-operator.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/graph.h"
#include "src/compiler/machine-operator.h"
......@@ -18,7 +19,8 @@ class V8_EXPORT_PRIVATE DecompressionElimination final
: public NON_EXPORTED_BASE(AdvancedReducer) {
public:
explicit DecompressionElimination(Editor* editor, Graph* graph,
MachineOperatorBuilder* machine);
MachineOperatorBuilder* machine,
CommonOperatorBuilder* common);
~DecompressionElimination() final = default;
const char* reducer_name() const override {
......@@ -28,6 +30,17 @@ class V8_EXPORT_PRIVATE DecompressionElimination final
Reduction Reduce(Node* node) final;
private:
// Returns true if the decompress opcode is valid for the compressed one.
bool IsValidDecompress(IrOpcode::Value compressOpcode,
IrOpcode::Value decompressOpcode);
// Returns true if the constant opcode is a reduceable one in decompression
// elimination.
bool IsReduceableConstantOpcode(IrOpcode::Value opcode);
// Get the new 32 bit node constant given the 64 bit one
Node* GetCompressedConstant(Node* constant);
// Removes direct Decompressions & Compressions, going from
// Parent <- Decompression <- Compression <- Child
// to
......@@ -36,18 +49,19 @@ class V8_EXPORT_PRIVATE DecompressionElimination final
Reduction ReduceCompress(Node* node);
// Replaces a Word64Equal with a Word32Equal if both of its inputs are
// Decompress nodes. In that case, it uses the inputs to each of the
// Decompress nodes.
// Decompress nodes, or if one is a Decompress node and the other a constant.
// In the case of two decompresses, it uses the original inputs before they
// are decompressed. In the case of having a constant, it uses the compressed
// value of that constant.
Reduction ReduceWord64Equal(Node* node);
// Returns true if the decompress opcode is valid for the compressed one.
bool IsValidDecompress(IrOpcode::Value compressOpcode,
IrOpcode::Value decompressOpcode);
Graph* graph() const { return graph_; }
MachineOperatorBuilder* machine() const { return machine_; }
CommonOperatorBuilder* common() const { return common_; }
Graph* const graph_;
MachineOperatorBuilder* const machine_;
CommonOperatorBuilder* const common_;
};
} // namespace compiler
......
......@@ -1541,7 +1541,7 @@ struct LateOptimizationPhase {
data->jsgraph()->common());
#ifdef V8_COMPRESS_POINTERS
DecompressionElimination decompression_elimination(
&graph_reducer, data->graph(), data->machine());
&graph_reducer, data->graph(), data->machine(), data->common());
AddReducer(data, &graph_reducer, &decompression_elimination);
#endif
AddReducer(data, &graph_reducer, &branch_condition_elimination);
......
......@@ -27,7 +27,7 @@ class DecompressionEliminationTest : public GraphTest {
Reduction Reduce(Node* node) {
StrictMock<MockAdvancedReducerEditor> editor;
DecompressionElimination decompression_elimination(&editor, graph(),
machine());
machine(), common());
return decompression_elimination.Reduce(node);
}
MachineOperatorBuilder* machine() { return &machine_; }
......@@ -251,9 +251,9 @@ TEST_F(DecompressionEliminationTest,
}
// -----------------------------------------------------------------------------
// Comparison of two decompressions
// Word64Equal comparison of two decompressions
TEST_F(DecompressionEliminationTest, TwoDecompressionComparison) {
TEST_F(DecompressionEliminationTest, TwoDecompressionWord64Equal) {
// Skip test if pointer compression is not enabled
if (!COMPRESS_POINTERS_BOOL) {
return;
......@@ -348,6 +348,142 @@ TEST_F(DecompressionEliminationTest, TwoDecompressionWord64EqualSameInput) {
}
}
// -----------------------------------------------------------------------------
// Word64Equal comparison of decompress and a constant
TEST_F(DecompressionEliminationTest, DecompressionConstantWord64Equal) {
// 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 Operator* DecompressionOps[] = {
machine()->ChangeCompressedToTagged(),
machine()->ChangeCompressedSignedToTaggedSigned(),
machine()->ChangeCompressedPointerToTaggedPointer()};
const ElementAccess ElementAccesses[] = {
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier},
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::TaggedSigned(),
kNoWriteBarrier},
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::TaggedPointer(),
kNoWriteBarrier}};
ASSERT_EQ(arraysize(DecompressionOps), arraysize(ElementAccesses));
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)};
// For every decompression (lhs)
for (size_t j = 0; j < arraysize(DecompressionOps); ++j) {
// For every constant (rhs)
for (size_t k = 0; k < arraysize(constants); ++k) {
// Test with both (lhs, rhs) combinations
for (bool lhsIsDecompression : {false, true}) {
// Create the graph
Node* load =
graph()->NewNode(simplified()->LoadElement(ElementAccesses[j]),
object, index, effect, control);
Node* changeToTagged = graph()->NewNode(DecompressionOps[j], load);
Node* constant =
graph()->NewNode(common()->Int64Constant(constants[k]));
Node* lhs = lhsIsDecompression ? changeToTagged : constant;
Node* rhs = lhsIsDecompression ? constant : changeToTagged;
Node* comparison = graph()->NewNode(machine()->Word64Equal(), lhs, rhs);
// Reduce
Reduction r = Reduce(comparison);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
}
}
}
}
TEST_F(DecompressionEliminationTest, DecompressionHeapConstantWord64Equal) {
// 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 Operator* DecompressionOps[] = {
machine()->ChangeCompressedToTagged(),
machine()->ChangeCompressedSignedToTaggedSigned(),
machine()->ChangeCompressedPointerToTaggedPointer()};
const ElementAccess ElementAccesses[] = {
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier},
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::TaggedSigned(),
kNoWriteBarrier},
{kTaggedBase, kTaggedSize, Type::Any(), MachineType::TaggedPointer(),
kNoWriteBarrier}};
ASSERT_EQ(arraysize(DecompressionOps), arraysize(ElementAccesses));
const Handle<HeapNumber> heapConstants[] = {
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)};
// For every decompression (lhs)
for (size_t j = 0; j < arraysize(DecompressionOps); ++j) {
// For every constant (rhs)
for (size_t k = 0; k < arraysize(heapConstants); ++k) {
// Test with both (lhs, rhs) combinations
for (bool lhsIsDecompression : {false, true}) {
// Create the graph
Node* load =
graph()->NewNode(simplified()->LoadElement(ElementAccesses[j]),
object, index, effect, control);
Node* changeToTagged = graph()->NewNode(DecompressionOps[j], load);
Node* constant =
graph()->NewNode(common()->HeapConstant(heapConstants[k]));
Node* lhs = lhsIsDecompression ? changeToTagged : constant;
Node* rhs = lhsIsDecompression ? constant : changeToTagged;
Node* comparison = graph()->NewNode(machine()->Word64Equal(), lhs, rhs);
// Reduce
Reduction r = Reduce(comparison);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(r.replacement()->opcode(), IrOpcode::kWord32Equal);
}
}
}
}
} // namespace compiler
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment