Commit 1e586c3c authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan][x64] Match memory operand comparisons with zero.

The InstructionSelector on x64 was missing the ability to properly match
comparisons of memory operands with zero, i.e. it used to turn something
like

  Word32Equal(Load[Uint8](o, i), Int32Constant(0))

into

  movzbl reg, [o,i]
  cmp 0, reg

even requiring a temporary register. Now with this change it generates
the proper

  cmpb [o,i], 0

sequence.

R=sigurds@chromium.org

Bug: v8:8238
Change-Id: I52a71bbf95c85e11cb275f0f4a5726a6873cde95
Reviewed-on: https://chromium-review.googlesource.com/c/1281342Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56677}
parent b76c27bf
...@@ -1817,7 +1817,37 @@ void VisitCompareZero(InstructionSelector* selector, Node* user, Node* node, ...@@ -1817,7 +1817,37 @@ void VisitCompareZero(InstructionSelector* selector, Node* user, Node* node,
break; break;
} }
} }
VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont); int effect_level = selector->GetEffectLevel(node);
if (cont->IsBranch()) {
effect_level = selector->GetEffectLevel(
cont->true_block()->PredecessorAt(0)->control_input());
}
if (node->opcode() == IrOpcode::kLoad) {
switch (LoadRepresentationOf(node->op()).representation()) {
case MachineRepresentation::kWord8:
if (opcode == kX64Cmp32) {
opcode = kX64Cmp8;
} else if (opcode == kX64Test32) {
opcode = kX64Test8;
}
break;
case MachineRepresentation::kWord16:
if (opcode == kX64Cmp32) {
opcode = kX64Cmp16;
} else if (opcode == kX64Test32) {
opcode = kX64Test16;
}
break;
default:
break;
}
}
if (g.CanBeMemoryOperand(opcode, user, node, effect_level)) {
VisitCompareWithMemoryOperand(selector, opcode, node, g.TempImmediate(0),
cont);
} else {
VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
}
} }
......
...@@ -1205,10 +1205,114 @@ TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) { ...@@ -1205,10 +1205,114 @@ TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Binops with a memory operand. // Binops with a memory operand.
TEST_F(InstructionSelectorTest, LoadCmp32) {
{
// Word32Equal(Load[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.Load(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(),
MachineType::Int64());
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
m.Return(m.Word32Equal(m.Load(MachineType::Uint8(), 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[Int16](p0, p1), Int32Constant(0)) -> cmpw [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.Load(MachineType::Int16(), p0, p1),
m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64Cmp16, 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[Uint16](p0, p1), Int32Constant(0)) -> cmpw [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.Load(MachineType::Uint16(), p0, p1),
m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64Cmp16, 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[Int32](p0, p1), Int32Constant(0)) -> cmpl [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.Load(MachineType::Int32(), p0, p1),
m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64Cmp32, 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[Uint32](p0, p1), Int32Constant(0)) -> cmpl [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.Load(MachineType::Uint32(), p0, p1),
m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64Cmp32, 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());
}
}
TEST_F(InstructionSelectorTest, LoadAnd32) { TEST_F(InstructionSelectorTest, LoadAnd32) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
MachineType::Int32()); MachineType::Int32());
......
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