[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