[llvm] [AArch64] Extend index load/store optimization to support store instructions (PR #177869)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 25 11:23:25 PST 2026
https://github.com/SiliconA-Z updated https://github.com/llvm/llvm-project/pull/177869
>From 31d96231376e67a0295121b521fcca462f7a7220 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 25 Jan 2026 13:52:55 -0500
Subject: [PATCH 1/2] Pre-commit test (NFC)
---
.../test/CodeGen/AArch64/str-index-hazard.mir | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/str-index-hazard.mir
diff --git a/llvm/test/CodeGen/AArch64/str-index-hazard.mir b/llvm/test/CodeGen/AArch64/str-index-hazard.mir
new file mode 100644
index 0000000000000..ff351ef756d6a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/str-index-hazard.mir
@@ -0,0 +1,57 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=aarch64 -run-pass aarch64-ldst-opt %s -o - | FileCheck %s
+
+---
+name: StrHazards
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0', virtual-reg: '' }
+body: |
+ bb.0.entry:
+ liveins: $x0
+
+ ; This test demonstrates a hazard where x8 is both the index and the value being stored.
+ ; The optimization converts:
+ ; mov x8, #LargeImm
+ ; str x8, [x0, x8]
+ ; into:
+ ; add x8, x0, #LargeBase
+ ; str x8, [x8, #SmallImm]
+ ; When this happens, the STR stores the *modified* x8 (address) instead of the original value.
+
+ ; CHECK-LABEL: name: StrHazards
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: renamable $w8 = MOVZWi 56952, 0
+ ; CHECK-NEXT: renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ ; CHECK-NEXT: STRXroX killed renamable $x8, killed renamable $x0, renamable $x8, 0, 0
+ ; CHECK-NEXT: RET undef $lr
+ renamable $w8 = MOVZWi 56952, 0
+ renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ STRXroX killed renamable $x8, killed renamable $x0, renamable $x8, 0, 0
+ RET undef $lr
+...
+---
+name: StrValid
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0', virtual-reg: '' }
+ - { reg: '$x1', virtual-reg: '' }
+body: |
+ bb.0.entry:
+ liveins: $x0, $x1
+
+ ; This is a valid case that SHOULD be optimized.
+
+ ; CHECK-LABEL: name: StrValid
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: renamable $w8 = MOVZWi 56952, 0
+ ; CHECK-NEXT: renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ ; CHECK-NEXT: STRXroX killed renamable $x1, killed renamable $x0, killed renamable $x8, 0, 0
+ ; CHECK-NEXT: RET undef $lr
+ renamable $w8 = MOVZWi 56952, 0
+ renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ STRXroX killed renamable $x1, killed renamable $x0, killed renamable $x8, 0, 0
+ RET undef $lr
+...
>From 4b5cd98ad55486190413e54bf25e9cefb5c8db63 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 25 Jan 2026 13:54:15 -0500
Subject: [PATCH 2/2] [AArch64] Extend index load/store optimization to support
store instructions
Extended the AArch64 load/store optimizer to handle store instructions with register offsets
---
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 9 ++++
.../AArch64/AArch64LoadStoreOptimizer.cpp | 48 ++++++++++++++++---
.../test/CodeGen/AArch64/str-index-hazard.mir | 27 +++++++++--
3 files changed, 74 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 755db8790003e..bdacd3f161dac 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -5063,6 +5063,15 @@ AArch64InstrInfo::getLdStAmountOp(const MachineInstr &MI) {
case AArch64::LDRDroX:
case AArch64::LDRXroX:
case AArch64::LDRQroX:
+ case AArch64::STRBroX:
+ case AArch64::STRBBroX:
+ case AArch64::STRHroX:
+ case AArch64::STRHHroX:
+ case AArch64::STRWroX:
+ case AArch64::STRSroX:
+ case AArch64::STRXroX:
+ case AArch64::STRDroX:
+ case AArch64::STRQroX:
return MI.getOperand(4);
}
}
diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
index 3d9444c0c5426..bf485c791063a 100644
--- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
@@ -513,7 +513,6 @@ static unsigned getPreIndexedOpcode(unsigned Opc) {
}
static unsigned getBaseAddressOpcode(unsigned Opc) {
- // TODO: Add more index address stores.
switch (Opc) {
default:
llvm_unreachable("Opcode has no base address equivalent!");
@@ -545,6 +544,24 @@ static unsigned getBaseAddressOpcode(unsigned Opc) {
return AArch64::LDRXui;
case AArch64::LDRQroX:
return AArch64::LDRQui;
+ case AArch64::STRBroX:
+ return AArch64::STRBui;
+ case AArch64::STRBBroX:
+ return AArch64::STRBBui;
+ case AArch64::STRHroX:
+ return AArch64::STRHui;
+ case AArch64::STRHHroX:
+ return AArch64::STRHHui;
+ case AArch64::STRWroX:
+ return AArch64::STRWui;
+ case AArch64::STRSroX:
+ return AArch64::STRSui;
+ case AArch64::STRXroX:
+ return AArch64::STRXui;
+ case AArch64::STRDroX:
+ return AArch64::STRDui;
+ case AArch64::STRQroX:
+ return AArch64::STRQui;
}
}
@@ -805,29 +822,37 @@ static bool isMergeableIndexLdSt(MachineInstr &MI, int &Scale) {
default:
return false;
// Scaled instructions.
- // TODO: Add more index address stores.
case AArch64::LDRBroX:
case AArch64::LDRBBroX:
case AArch64::LDRSBXroX:
case AArch64::LDRSBWroX:
+ case AArch64::STRBroX:
+ case AArch64::STRBBroX:
Scale = 1;
return true;
case AArch64::LDRHroX:
case AArch64::LDRHHroX:
case AArch64::LDRSHXroX:
case AArch64::LDRSHWroX:
+ case AArch64::STRHroX:
+ case AArch64::STRHHroX:
Scale = 2;
return true;
case AArch64::LDRWroX:
case AArch64::LDRSroX:
case AArch64::LDRSWroX:
+ case AArch64::STRWroX:
+ case AArch64::STRSroX:
Scale = 4;
return true;
case AArch64::LDRDroX:
case AArch64::LDRXroX:
+ case AArch64::STRDroX:
+ case AArch64::STRXroX:
Scale = 8;
return true;
case AArch64::LDRQroX:
+ case AArch64::STRQroX:
Scale = 16;
return true;
}
@@ -2712,8 +2737,8 @@ AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
MachineInstr &MemMI = *I;
MachineBasicBlock::iterator MBBI = I;
- // If the load is the first instruction in the block, there's obviously
- // not any matching load or store.
+ // If the load or store is the first instruction in the block, there's
+ // obviously not any matching const-offset instruction to merge.
if (MBBI == B)
return E;
@@ -2979,6 +3004,15 @@ bool AArch64LoadStoreOpt::tryToMergeIndexLdSt(MachineBasicBlock::iterator &MBBI,
unsigned Offset;
Update = findMatchingConstOffsetBackward(MBBI, LdStConstLimit, Offset);
if (Update != E && (Offset & (Scale - 1)) == 0) {
+ // If the index register is the same as the register being stored, we
+ // cannot perform this optimization because the add instruction will
+ // overwrite the value in the index register before it is stored.
+ if (MI.mayStore()) {
+ Register IndexReg = AArch64InstrInfo::getLdStOffsetOp(MI).getReg();
+ Register StoreReg = getLdStRegOp(MI).getReg();
+ if (TRI->regsOverlap(IndexReg, StoreReg))
+ return false;
+ }
// Merge the imm12 into the ld/st.
MBBI = mergeConstOffsetInsn(MBBI, Update, Offset, Scale);
return true;
@@ -3074,12 +3108,12 @@ bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
}
// 5) Find a register assigned with a const value that can be combined with
- // into the load or store. e.g.,
+ // the load or store. e.g.,
// mov x8, #LargeImm ; = a * (1<<12) + imm12
- // ldr x1, [x0, x8]
+ // ldr x1, [x0, x8] ; or str x1, [x0, x8]
// ; becomes
// add x8, x0, a * (1<<12)
- // ldr x1, [x8, imm12]
+ // ldr x1, [x8, imm12] ; or str x1, [x8, imm12]
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
MBBI != E;) {
int Scale;
diff --git a/llvm/test/CodeGen/AArch64/str-index-hazard.mir b/llvm/test/CodeGen/AArch64/str-index-hazard.mir
index ff351ef756d6a..b741a962ccbaa 100644
--- a/llvm/test/CodeGen/AArch64/str-index-hazard.mir
+++ b/llvm/test/CodeGen/AArch64/str-index-hazard.mir
@@ -32,6 +32,28 @@ body: |
RET undef $lr
...
---
+name: StrHazardsSubReg
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0', virtual-reg: '' }
+body: |
+ bb.0.entry:
+ liveins: $x0
+
+ ; Hazard where x8 (index) overlaps with w8 (store value).
+ ; CHECK-LABEL: name: StrHazardsSubReg
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: renamable $w8 = MOVZWi 56952, 0
+ ; CHECK-NEXT: renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ ; CHECK-NEXT: STRWroX renamable $w8, killed renamable $x0, killed renamable $x8, 0, 0
+ ; CHECK-NEXT: RET undef $lr
+ renamable $w8 = MOVZWi 56952, 0
+ renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
+ STRWroX renamable $w8, killed renamable $x0, killed renamable $x8, 0, 0
+ RET undef $lr
+...
+---
name: StrValid
tracksRegLiveness: true
liveins:
@@ -46,9 +68,8 @@ body: |
; CHECK-LABEL: name: StrValid
; CHECK: liveins: $x0, $x1
; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: renamable $w8 = MOVZWi 56952, 0
- ; CHECK-NEXT: renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
- ; CHECK-NEXT: STRXroX killed renamable $x1, killed renamable $x0, killed renamable $x8, 0, 0
+ ; CHECK-NEXT: $x8 = ADDXri $x0, 248, 12
+ ; CHECK-NEXT: STRXui killed renamable $x1, killed renamable $x8, 3023
; CHECK-NEXT: RET undef $lr
renamable $w8 = MOVZWi 56952, 0
renamable $w8 = MOVKWi $w8, 15, 16, implicit-def $x8
More information about the llvm-commits
mailing list