Commit cc0d6a85 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[turbofan] LoadImmutable should be eligible as memory operand

Bug: v8:11510

Change-Id: I6cb4bdb45a735bd85adfa02b92f01cd144517560
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2840324Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74084}
parent d5feb5c0
......@@ -65,7 +65,8 @@ class IA32OperandGenerator final : public OperandGenerator {
bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input,
int effect_level) {
if (input->opcode() != IrOpcode::kLoad ||
if ((input->opcode() != IrOpcode::kLoad &&
input->opcode() != IrOpcode::kLoadImmutable) ||
!selector()->CanCover(node, input)) {
return false;
}
......@@ -818,7 +819,8 @@ void InstructionSelector::VisitStackPointerGreaterThan(
Node* const value = node->InputAt(0);
if (g.CanBeMemoryOperand(kIA32Cmp, node, value, effect_level)) {
DCHECK_EQ(IrOpcode::kLoad, value->opcode());
DCHECK(value->opcode() == IrOpcode::kLoad ||
value->opcode() == IrOpcode::kLoadImmutable);
// GetEffectiveAddressMemoryOperand can create at most 3 inputs.
static constexpr int kMaxInputCount = 3;
......@@ -1434,7 +1436,8 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector,
InstructionCode opcode, Node* left,
InstructionOperand right,
FlagsContinuation* cont) {
DCHECK_EQ(IrOpcode::kLoad, left->opcode());
DCHECK(left->opcode() == IrOpcode::kLoad ||
left->opcode() == IrOpcode::kLoadImmutable);
IA32OperandGenerator g(selector);
size_t input_count = 0;
InstructionOperand inputs[4];
......@@ -1465,7 +1468,8 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
}
MachineType MachineTypeForNarrow(Node* node, Node* hint_node) {
if (hint_node->opcode() == IrOpcode::kLoad) {
if (hint_node->opcode() == IrOpcode::kLoad ||
hint_node->opcode() == IrOpcode::kLoadImmutable) {
MachineType hint = LoadRepresentationOf(hint_node->op());
if (node->opcode() == IrOpcode::kInt32Constant ||
node->opcode() == IrOpcode::kInt64Constant) {
......@@ -1499,8 +1503,10 @@ MachineType MachineTypeForNarrow(Node* node, Node* hint_node) {
}
}
}
return node->opcode() == IrOpcode::kLoad ? LoadRepresentationOf(node->op())
: MachineType::None();
return node->opcode() == IrOpcode::kLoad ||
node->opcode() == IrOpcode::kLoadImmutable
? LoadRepresentationOf(node->op())
: MachineType::None();
}
// Tries to match the size of the given opcode to that of the operands, if
......
......@@ -1454,7 +1454,8 @@ void InstructionSelector::VisitBitcastWord32ToWord64(Node* node) {
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
Node* value = node->InputAt(0);
if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
if ((value->opcode() == IrOpcode::kLoad || IrOpcode::kLoadImmutable) &&
CanCover(node, value)) {
// Generate sign-extending load.
LoadRepresentation load_rep = LoadRepresentationOf(value->op());
InstructionCode opcode = kArchNop;
......
......@@ -1216,7 +1216,9 @@ void InstructionSelector::VisitBitcastWord32ToWord64(Node* node) {
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
Node* value = node->InputAt(0);
if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
if ((value->opcode() == IrOpcode::kLoad ||
value->opcode() == IrOpcode::kLoadImmutable) &&
CanCover(node, value)) {
// Generate sign-extending load.
LoadRepresentation load_rep = LoadRepresentationOf(value->op());
InstructionCode opcode = kArchNop;
......@@ -1244,7 +1246,8 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
bool InstructionSelector::ZeroExtendsWord32ToWord64NoPhis(Node* node) {
DCHECK_NE(node->opcode(), IrOpcode::kPhi);
if (node->opcode() == IrOpcode::kLoad) {
if (node->opcode() == IrOpcode::kLoad ||
node->opcode() == IrOpcode::kLoadImmutable) {
LoadRepresentation load_rep = LoadRepresentationOf(node->op());
if (load_rep.IsUnsigned()) {
switch (load_rep.representation()) {
......
......@@ -141,7 +141,8 @@ class S390OperandGenerator final : public OperandGenerator {
bool CanBeMemoryOperand(InstructionCode opcode, Node* user, Node* input,
int effect_level) {
if (input->opcode() != IrOpcode::kLoad ||
if ((input->opcode() != IrOpcode::kLoad &&
input->opcode() != IrOpcode::kLoadImmutable) ||
!selector()->CanCover(user, input)) {
return false;
}
......
......@@ -66,7 +66,8 @@ class X64OperandGenerator final : public OperandGenerator {
bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input,
int effect_level) {
if (input->opcode() != IrOpcode::kLoad ||
if ((input->opcode() != IrOpcode::kLoad &&
input->opcode() != IrOpcode::kLoadImmutable) ||
!selector()->CanCover(node, input)) {
return false;
}
......@@ -708,7 +709,8 @@ void InstructionSelector::VisitStackPointerGreaterThan(
X64OperandGenerator g(this);
Node* const value = node->InputAt(0);
if (g.CanBeMemoryOperand(kX64Cmp, node, value, effect_level)) {
DCHECK_EQ(IrOpcode::kLoad, value->opcode());
DCHECK(IrOpcode::kLoad == value->opcode() ||
IrOpcode::kLoadImmutable == value->opcode());
// GetEffectiveAddressMemoryOperand can create at most 3 inputs.
static constexpr int kMaxInputCount = 3;
......@@ -730,7 +732,9 @@ namespace {
bool TryMergeTruncateInt64ToInt32IntoLoad(InstructionSelector* selector,
Node* node, Node* load) {
if (load->opcode() == IrOpcode::kLoad && selector->CanCover(node, load)) {
if ((load->opcode() == IrOpcode::kLoad ||
load->opcode() == IrOpcode::kLoadImmutable) &&
selector->CanCover(node, load)) {
LoadRepresentation load_rep = LoadRepresentationOf(load->op());
MachineRepresentation rep = load_rep.representation();
InstructionCode opcode;
......@@ -1367,7 +1371,9 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
X64OperandGenerator g(this);
Node* const value = node->InputAt(0);
if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
if ((value->opcode() == IrOpcode::kLoad ||
value->opcode() == IrOpcode::kLoadImmutable) &&
CanCover(node, value)) {
LoadRepresentation load_rep = LoadRepresentationOf(value->op());
MachineRepresentation rep = load_rep.representation();
InstructionCode opcode;
......@@ -1874,7 +1880,8 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector,
InstructionCode opcode, Node* left,
InstructionOperand right,
FlagsContinuation* cont) {
DCHECK_EQ(IrOpcode::kLoad, left->opcode());
DCHECK(IrOpcode::kLoad == left->opcode() ||
IrOpcode::kLoadImmutable == left->opcode());
X64OperandGenerator g(selector);
size_t input_count = 0;
InstructionOperand inputs[6];
......@@ -1917,7 +1924,8 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
}
MachineType MachineTypeForNarrow(Node* node, Node* hint_node) {
if (hint_node->opcode() == IrOpcode::kLoad) {
if (hint_node->opcode() == IrOpcode::kLoad ||
hint_node->opcode() == IrOpcode::kLoadImmutable) {
MachineType hint = LoadRepresentationOf(hint_node->op());
if (node->opcode() == IrOpcode::kInt32Constant ||
node->opcode() == IrOpcode::kInt64Constant) {
......@@ -1951,8 +1959,10 @@ MachineType MachineTypeForNarrow(Node* node, Node* hint_node) {
}
}
}
return node->opcode() == IrOpcode::kLoad ? LoadRepresentationOf(node->op())
: MachineType::None();
return node->opcode() == IrOpcode::kLoad ||
node->opcode() == IrOpcode::kLoadImmutable
? LoadRepresentationOf(node->op())
: MachineType::None();
}
// Tries to match the size of the given opcode to that of the operands, if
......@@ -2167,7 +2177,8 @@ void VisitCompareZero(InstructionSelector* selector, Node* user, Node* node,
}
}
int effect_level = selector->GetEffectLevel(node, cont);
if (node->opcode() == IrOpcode::kLoad) {
if (node->opcode() == IrOpcode::kLoad ||
node->opcode() == IrOpcode::kLoadImmutable) {
switch (LoadRepresentationOf(node->op()).representation()) {
case MachineRepresentation::kWord8:
if (opcode == kX64Cmp32) {
......
......@@ -17,7 +17,8 @@ bool IsMachineLoad(Node* const node) {
const IrOpcode::Value opcode = node->opcode();
return opcode == IrOpcode::kLoad || opcode == IrOpcode::kPoisonedLoad ||
opcode == IrOpcode::kProtectedLoad ||
opcode == IrOpcode::kUnalignedLoad;
opcode == IrOpcode::kUnalignedLoad ||
opcode == IrOpcode::kLoadImmutable;
}
bool IsTaggedMachineLoad(Node* const node) {
......@@ -204,6 +205,10 @@ void DecompressionOptimizer::ChangeLoad(Node* const node) {
case IrOpcode::kLoad:
NodeProperties::ChangeOp(node, machine()->Load(compressed_load_rep));
break;
case IrOpcode::kLoadImmutable:
NodeProperties::ChangeOp(node,
machine()->LoadImmutable(compressed_load_rep));
break;
case IrOpcode::kPoisonedLoad:
NodeProperties::ChangeOp(node,
machine()->PoisonedLoad(compressed_load_rep));
......
......@@ -148,6 +148,13 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
Node* load = AddNode(op, base, index);
return load;
}
Node* LoadImmutable(MachineType type, Node* base) {
return LoadImmutable(type, base, IntPtrConstant(0));
}
Node* LoadImmutable(MachineType type, Node* base, Node* index) {
const Operator* op = machine()->LoadImmutable(type);
return AddNode(op, base, index);
}
bool IsMapOffsetConstant(Node* node) {
Int64Matcher m(node);
if (m.Is(HeapObject::kMapOffset)) return true;
......
......@@ -331,8 +331,8 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet(
bool RedundantStoreFinder::CannotObserveStoreField(Node* node) {
IrOpcode::Value opcode = node->opcode();
return opcode == IrOpcode::kLoadElement || opcode == IrOpcode::kLoad ||
opcode == IrOpcode::kStore || opcode == IrOpcode::kEffectPhi ||
opcode == IrOpcode::kStoreElement ||
opcode == IrOpcode::kLoadImmutable || opcode == IrOpcode::kStore ||
opcode == IrOpcode::kEffectPhi || opcode == IrOpcode::kStoreElement ||
opcode == IrOpcode::kUnsafePointerAdd || opcode == IrOpcode::kRetain;
}
......
......@@ -658,6 +658,21 @@ TEST_F(InstructionSelectorTest, LoadAnd32) {
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
}
TEST_F(InstructionSelectorTest, LoadImmutableAnd32) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
m.Return(m.Word32And(
p0, m.LoadImmutable(MachineType::Int32(), p1, m.Int32Constant(127))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kIA32And, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
}
TEST_F(InstructionSelectorTest, LoadOr32) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
MachineType::Int32());
......
......@@ -1315,6 +1315,24 @@ TEST_F(InstructionSelectorTest, LoadCmp32) {
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
}
{
// Word32Equal(LoadImmutable[Int8](p0, p1), Int32Constant(0)) ->
// cmpb [p0,p1], 0
StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
MachineType::Int64());
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
m.Return(m.Word32Equal(m.LoadImmutable(MachineType::Int8(), p0, p1),
m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
}
{
// Word32Equal(Load[Uint8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0
StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
......
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