Commit 472e2ba9 authored by dusan.m.milosavljevic's avatar dusan.m.milosavljevic Committed by Commit bot

MIPS:[turbofan] Match shift left and bitwise And with mask when possible.

TEST=unittests/InstructionSelectorTest.Word(32|64)ShlWithWord(32|64)And
BUG=

Review URL: https://codereview.chromium.org/1496013003

Cr-Commit-Position: refs/heads/master@{#32612}
parent af9fa490
......@@ -330,6 +330,32 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
void InstructionSelector::VisitWord32Shl(Node* node) {
Int32BinopMatcher m(node);
if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
m.right().IsInRange(1, 31)) {
MipsOperandGenerator g(this);
Int32BinopMatcher mleft(m.left().node());
// Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is
// contiguous, and the shift immediate non-zero.
if (mleft.right().HasValue()) {
uint32_t mask = mleft.right().Value();
uint32_t mask_width = base::bits::CountPopulation32(mask);
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
uint32_t shift = m.right().Value();
DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
DCHECK_NE(0u, shift);
if ((shift + mask_width) >= 32) {
// If the mask is contiguous and reaches or extends beyond the top
// bit, only the shift is needed.
Emit(kMipsShl, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()),
g.UseImmediate(m.right().node()));
return;
}
}
}
}
VisitRRO(this, kMipsShl, node);
}
......
......@@ -422,6 +422,32 @@ void InstructionSelector::VisitWord64Xor(Node* node) {
void InstructionSelector::VisitWord32Shl(Node* node) {
Int32BinopMatcher m(node);
if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
m.right().IsInRange(1, 31)) {
Mips64OperandGenerator g(this);
Int32BinopMatcher mleft(m.left().node());
// Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is
// contiguous, and the shift immediate non-zero.
if (mleft.right().HasValue()) {
uint32_t mask = mleft.right().Value();
uint32_t mask_width = base::bits::CountPopulation32(mask);
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
uint32_t shift = m.right().Value();
DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
DCHECK_NE(0u, shift);
if ((shift + mask_width) >= 32) {
// If the mask is contiguous and reaches or extends beyond the top
// bit, only the shift is needed.
Emit(kMips64Shl, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()),
g.UseImmediate(m.right().node()));
return;
}
}
}
}
VisitRRO(this, kMips64Shl, node);
}
......@@ -468,6 +494,31 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
g.UseImmediate(m.right().node()));
return;
}
if (m.left().IsWord64And() && CanCover(node, m.left().node()) &&
m.right().IsInRange(1, 63)) {
// Match Word64Shl(Word64And(x, mask), imm) to Dshl where the mask is
// contiguous, and the shift immediate non-zero.
Int64BinopMatcher mleft(m.left().node());
if (mleft.right().HasValue()) {
uint64_t mask = mleft.right().Value();
uint32_t mask_width = base::bits::CountPopulation64(mask);
uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
uint64_t shift = m.right().Value();
DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
DCHECK_NE(0u, shift);
if ((shift + mask_width) >= 64) {
// If the mask is contiguous and reaches or extends beyond the top
// bit, only the shift is needed.
Emit(kMips64Dshl, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()),
g.UseImmediate(m.right().node()));
return;
}
}
}
}
VisitRRO(this, kMips64Dshl, node);
}
......
......@@ -336,6 +336,25 @@ TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
}
TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) {
TRACED_FORRANGE(int32_t, shift, 0, 30) {
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)),
m.Int32Constant(shift + 1));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMipsShl, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
// ----------------------------------------------------------------------------
// Logical instructions.
// ----------------------------------------------------------------------------
......
......@@ -622,6 +622,44 @@ TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
}
TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) {
TRACED_FORRANGE(int32_t, shift, 0, 30) {
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)),
m.Int32Constant(shift + 1));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Shl, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) {
TRACED_FORRANGE(int32_t, shift, 0, 62) {
StreamBuilder m(this, kMachInt64, kMachInt64);
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word64Shl(m.Word64And(p0, m.Int64Constant((1L << (63 - shift)) - 1)),
m.Int64Constant(shift + 1));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Dshl, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
// ----------------------------------------------------------------------------
// MUL/DIV instructions.
// ----------------------------------------------------------------------------
......
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