Commit ba41489d authored by baptiste.afsa's avatar baptiste.afsa Committed by Commit bot

[turbofan][arm64] Match add with shifted operand for mult by a power of 2 plus 1.

R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#27612}
parent a1b2c275
...@@ -852,6 +852,18 @@ void InstructionSelector::VisitInt32Mul(Node* node) { ...@@ -852,6 +852,18 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
} }
} }
// x * (2^k + 1) -> x + (x << k)
if (m.right().HasValue() && m.right().Value() > 0) {
int32_t value = m.right().Value();
if (base::bits::IsPowerOfTwo32(value - 1)) {
Emit(kArm64Add32 | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
return;
}
}
VisitRRR(this, kArm64Mul32, node); VisitRRR(this, kArm64Mul32, node);
} }
...@@ -883,6 +895,18 @@ void InstructionSelector::VisitInt64Mul(Node* node) { ...@@ -883,6 +895,18 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
} }
} }
// x * (2^k + 1) -> x + (x << k)
if (m.right().HasValue() && m.right().Value() > 0) {
int64_t value = m.right().Value();
if (base::bits::IsPowerOfTwo64(value - 1)) {
Emit(kArm64Add | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2_64(value - 1)));
return;
}
}
VisitRRR(this, kArm64Mul, node); VisitRRR(this, kArm64Mul, node);
} }
......
...@@ -67,6 +67,41 @@ inline int WhichPowerOf2(uint32_t x) { ...@@ -67,6 +67,41 @@ inline int WhichPowerOf2(uint32_t x) {
} }
// X must be a power of 2. Returns the number of trailing zeros.
inline int WhichPowerOf2_64(uint64_t x) {
DCHECK(base::bits::IsPowerOfTwo64(x));
int bits = 0;
#ifdef DEBUG
uint64_t original_x = x;
#endif
if (x >= 0x100000000L) {
bits += 32;
x >>= 32;
}
if (x >= 0x10000) {
bits += 16;
x >>= 16;
}
if (x >= 0x100) {
bits += 8;
x >>= 8;
}
if (x >= 0x10) {
bits += 4;
x >>= 4;
}
switch (x) {
default: UNREACHABLE();
case 8: bits++; // Fall through.
case 4: bits++; // Fall through.
case 2: bits++; // Fall through.
case 1: break;
}
DCHECK_EQ(1L << bits, original_x);
return bits;
}
inline int MostSignificantBit(uint32_t x) { inline int MostSignificantBit(uint32_t x) {
static const int msb4[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; static const int msb4[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
int nibble = 0; int nibble = 0;
......
...@@ -1520,6 +1520,66 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, ...@@ -1520,6 +1520,66 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
::testing::ValuesIn(kMulDPInstructions)); ::testing::ValuesIn(kMulDPInstructions));
TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
// x * (2^k + 1) -> x + (x << k)
TRACED_FORRANGE(int32_t, k, 1, 30) {
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
EXPECT_EQ(1U, s[0]->OutputCount());
}
// (2^k + 1) * x -> x + (x << k)
TRACED_FORRANGE(int32_t, k, 1, 30) {
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
TEST_F(InstructionSelectorTest, Int64MulWithImmediate) {
// x * (2^k + 1) -> x + (x << k)
TRACED_FORRANGE(int64_t, k, 1, 62) {
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Int64Mul(m.Parameter(0), m.Int64Constant((1L << k) + 1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
EXPECT_EQ(1U, s[0]->OutputCount());
}
// (2^k + 1) * x -> x + (x << k)
TRACED_FORRANGE(int64_t, k, 1, 62) {
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Floating point instructions. // Floating point 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