[llvm] [AArch64][SelectionDAG] Reduce redundant loads for constant <2 x i64> values (PR #214864)
Ethan Luis McDonough via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 11 00:23:04 PDT 2026
https://github.com/EthanLuisMcDonough updated https://github.com/llvm/llvm-project/pull/214864
>From 28a1c6ae138fbbd877deda57e0052f426f1d2b07 Mon Sep 17 00:00:00 2001
From: Ethan Luis McDonough <emcdonou at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 15:00:09 -0700
Subject: [PATCH 1/2] Fix #38518
---
.../Target/AArch64/AArch64ISelLowering.cpp | 29 +++++++++++++++++++
.../test/CodeGen/AArch64/v2i64-const-store.ll | 25 ++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/v2i64-const-store.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2ac6c5fbc471a..56d543423a368 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -27597,6 +27597,35 @@ static SDValue performSTORECombine(SDNode *N,
}
}
+ // For loads that read constant <2 x i64> values, use two MOVZs and a stp
+ // instruction if both i64 values fit inside 16 bits.
+ if (ST->getOperand(1).getValueType() == MVT::v2i64 &&
+ ST->getOperand(1).getNumOperands() == 2) {
+ auto *FirstVal =
+ dyn_cast<ConstantSDNode>(ST->getOperand(1).getOperand(0).getNode());
+ auto *SecondVal =
+ dyn_cast<ConstantSDNode>(ST->getOperand(1).getOperand(1).getNode());
+ if (FirstVal && SecondVal &&
+ FirstVal->getZExtValue() <= std::numeric_limits<uint16_t>::max() &&
+ SecondVal->getZExtValue() <= std::numeric_limits<uint16_t>::max()) {
+ auto GenImmMov = [&](uint64_t Imm) {
+ return Imm == 0 ? DAG.getRegister(AArch64::XZR, MVT::i64)
+ : SDValue(DAG.getMachineNode(
+ AArch64::MOVZXi, DL, MVT::i64,
+ DAG.getTargetConstant(Imm, DL, MVT::i16),
+ DAG.getTargetConstant(0, DL, MVT::i64)),
+ 0);
+ };
+ auto FV = GenImmMov(FirstVal->getZExtValue());
+ auto SV = GenImmMov(SecondVal->getZExtValue());
+ if (DAG.getDataLayout().isBigEndian())
+ std::swap(FV, SV);
+ return DAG.getMemIntrinsicNode(
+ AArch64ISD::STP, DL, DAG.getVTList(MVT::Other), {Chain, FV, SV, Ptr},
+ MemVT, ST->getMemOperand());
+ }
+ }
+
// This is an integer vector_extract_elt followed by a (possibly truncating)
// store. We may be able to replace this with a store of an FP subregister.
if (DCI.isAfterLegalizeDAG() && ST->isUnindexed() &&
diff --git a/llvm/test/CodeGen/AArch64/v2i64-const-store.ll b/llvm/test/CodeGen/AArch64/v2i64-const-store.ll
new file mode 100644
index 0000000000000..70170ba28fb40
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/v2i64-const-store.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O3 -verify-machineinstrs -mtriple=aarch64-unknown-linux | FileCheck %s
+
+define void @foo(ptr %s) {
+; CHECK-LABEL: foo:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov x8, #1 // =0x1
+; CHECK-NEXT: stp x8, xzr, [x0]
+; CHECK-NEXT: ret
+entry:
+ store <2 x i64> <i64 1, i64 0>, ptr %s, align 8
+ ret void
+}
+
+define void @foo2(ptr %s) {
+; CHECK-LABEL: foo2:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov x8, #10293 // =0x2835
+; CHECK-NEXT: mov x9, #2329 // =0x919
+; CHECK-NEXT: stp x9, x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ store <2 x i64> <i64 2329, i64 10293>, ptr %s, align 8
+ ret void
+}
>From d0ee6191364c5e4ae33a0f99d668c991f2828a51 Mon Sep 17 00:00:00 2001
From: Ethan Luis McDonough <emcdonou at qti.qualcomm.com>
Date: Tue, 11 Aug 2026 00:16:27 -0700
Subject: [PATCH 2/2] Refactor transformation logic
---
.../Target/AArch64/AArch64ISelLowering.cpp | 30 ++++++-------------
.../test/CodeGen/AArch64/v2i64-const-store.ll | 6 ++--
2 files changed, 12 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 56d543423a368..b91d5ce457014 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -27597,27 +27597,15 @@ static SDValue performSTORECombine(SDNode *N,
}
}
- // For loads that read constant <2 x i64> values, use two MOVZs and a stp
- // instruction if both i64 values fit inside 16 bits.
- if (ST->getOperand(1).getValueType() == MVT::v2i64 &&
- ST->getOperand(1).getNumOperands() == 2) {
- auto *FirstVal =
- dyn_cast<ConstantSDNode>(ST->getOperand(1).getOperand(0).getNode());
- auto *SecondVal =
- dyn_cast<ConstantSDNode>(ST->getOperand(1).getOperand(1).getNode());
- if (FirstVal && SecondVal &&
- FirstVal->getZExtValue() <= std::numeric_limits<uint16_t>::max() &&
- SecondVal->getZExtValue() <= std::numeric_limits<uint16_t>::max()) {
- auto GenImmMov = [&](uint64_t Imm) {
- return Imm == 0 ? DAG.getRegister(AArch64::XZR, MVT::i64)
- : SDValue(DAG.getMachineNode(
- AArch64::MOVZXi, DL, MVT::i64,
- DAG.getTargetConstant(Imm, DL, MVT::i16),
- DAG.getTargetConstant(0, DL, MVT::i64)),
- 0);
- };
- auto FV = GenImmMov(FirstVal->getZExtValue());
- auto SV = GenImmMov(SecondVal->getZExtValue());
+ // For stores that save constant <2 x i64> values, use two mov instructions
+ // and a stp instruction if both i64 are elligable mov immediate values.
+ if (Value.getValueType() == MVT::v2i64 && Value.getNumOperands() == 2) {
+ auto FV = Value.getOperand(0);
+ auto SV = Value.getOperand(1);
+ auto *FC = dyn_cast<ConstantSDNode>(FV.getNode());
+ auto *SC = dyn_cast<ConstantSDNode>(SV.getNode());
+ if (FC && SC && AArch64_AM::isAnyMOVWMovAlias(FC->getZExtValue(), 64) &&
+ AArch64_AM::isAnyMOVWMovAlias(SC->getZExtValue(), 64)) {
if (DAG.getDataLayout().isBigEndian())
std::swap(FV, SV);
return DAG.getMemIntrinsicNode(
diff --git a/llvm/test/CodeGen/AArch64/v2i64-const-store.ll b/llvm/test/CodeGen/AArch64/v2i64-const-store.ll
index 70170ba28fb40..47446c45d6097 100644
--- a/llvm/test/CodeGen/AArch64/v2i64-const-store.ll
+++ b/llvm/test/CodeGen/AArch64/v2i64-const-store.ll
@@ -4,7 +4,7 @@
define void @foo(ptr %s) {
; CHECK-LABEL: foo:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: mov x8, #1 // =0x1
+; CHECK-NEXT: mov w8, #1 // =0x1
; CHECK-NEXT: stp x8, xzr, [x0]
; CHECK-NEXT: ret
entry:
@@ -15,8 +15,8 @@ entry:
define void @foo2(ptr %s) {
; CHECK-LABEL: foo2:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: mov x8, #10293 // =0x2835
-; CHECK-NEXT: mov x9, #2329 // =0x919
+; CHECK-NEXT: mov w8, #10293 // =0x2835
+; CHECK-NEXT: mov w9, #2329 // =0x919
; CHECK-NEXT: stp x9, x8, [x0]
; CHECK-NEXT: ret
entry:
More information about the llvm-commits
mailing list