Commit 7f62066e authored by Ryan Everett's avatar Ryan Everett Committed by V8 LUCI CQ

[compiler][arm64] Fold SXTW, ASR into a single SBFX instruction

Use a single SBFX instruction for Word64Sar(ChangeInt32ToInt64(x), imm)
when possible.

Using PGO, this improves Speedometer2 by 0.4% on a Cortex-A55 machine,
and 0.27% on a Neoverse-N1 machine.

Change-Id: I6fea5e473f0f0869f8f6cebd9a4e61bb2fc6e9ef
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3807586Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Rodolph Perfetta <rodolph.perfetta@arm.com>
Reviewed-by: 's avatarJakob Linke <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82277}
parent 3a639c3b
......@@ -1431,6 +1431,26 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
void InstructionSelector::VisitWord64Sar(Node* node) {
if (TryEmitExtendingLoad(this, node)) return;
// Select Sbfx(x, imm, 32-imm) for Word64Sar(ChangeInt32ToInt64(x), imm)
// where possible
Int64BinopMatcher m(node);
if (m.left().IsChangeInt32ToInt64() && m.right().HasResolvedValue() &&
is_uint5(m.right().ResolvedValue()) && CanCover(node, m.left().node())) {
// Don't select Sbfx here if Asr(Ldrsw(x), imm) can be selected for
// Word64Sar(ChangeInt32ToInt64(Load(x)), imm)
if ((m.left().InputAt(0)->opcode() != IrOpcode::kLoad &&
m.left().InputAt(0)->opcode() != IrOpcode::kLoadImmutable) ||
!CanCover(m.left().node(), m.left().InputAt(0))) {
Arm64OperandGenerator g(this);
int right = static_cast<int>(m.right().ResolvedValue());
Emit(kArm64Sbfx, g.DefineAsRegister(node),
g.UseRegister(m.left().node()->InputAt(0)),
g.UseImmediate(m.right().node()), g.UseImmediate(32 - right));
return;
}
}
VisitRRO(this, kArm64Asr, node, kShift64Imm);
}
......
......@@ -3165,6 +3165,33 @@ TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithWord32Sar) {
}
}
TEST_F(InstructionSelectorTest, Word64SarWithChangeInt32ToInt64) {
TRACED_FORRANGE(int64_t, imm, -31, 63) {
StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
m.Return(m.Word64Sar(m.ChangeInt32ToInt64(m.Parameter(0)),
m.Int64Constant(imm)));
Stream s = m.Build();
// Optimization should only be applied when 0 <= imm < 32
if (0 <= imm && imm < 32) {
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Sbfx, s[0]->arch_opcode());
EXPECT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
EXPECT_EQ(32 - imm, s.ToInt64(s[0]->InputAt(2)));
} else {
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kArm64Sxtw, s[0]->arch_opcode());
EXPECT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
EXPECT_EQ(imm, s.ToInt64(s[1]->InputAt(1)));
}
}
}
// -----------------------------------------------------------------------------
// Memory access 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