[llvm] [MCP] Avoid Folding Spill Chains Over Across Source Clobbers (PR #207169)

Jack Styles via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 6 02:00:28 PDT 2026


https://github.com/Stylie777 updated https://github.com/llvm/llvm-project/pull/207169

>From e6fc9d90f57f581acabf8303989ff4b43fc748ef Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Thu, 2 Jul 2026 13:02:55 +0100
Subject: [PATCH 1/3] [MCP] Avoid Folding Spill Chains Over Across Source
 Clobbers

Previously, MachineCopyPropogation::eliminateSpillageCopies was able
to fold COPY instructions that were part of a spill/reload chain over
a different COPY instruction that would clobber the original source.
This was missed, and as a result would lead to the original value of
the source being lost.

To ensure the original value is retained, the uses of the COPY's outside
of the chain are tracked, and then when folding is attempted, any
instructions that are unexpected will ensure the Spill Chain is retained
for that source, maintaining the original value.

Fixes: #206839
---
 llvm/lib/CodeGen/MachineCopyPropagation.cpp   | 27 +++++++++++++++
 .../aarch64-no-fold-over-clobbered-source.mir | 33 +++++++++++++++++++
 2 files changed, 60 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir

diff --git a/llvm/lib/CodeGen/MachineCopyPropagation.cpp b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
index ad33cb71b7c56..a9b3cf68cc2c3 100644
--- a/llvm/lib/CodeGen/MachineCopyPropagation.cpp
+++ b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
@@ -1337,6 +1337,8 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
   // If a COPY's Source has use or def until next COPY defines the Source,
   // we put the COPY in this set to keep property#2.
   DenseSet<const MachineInstr *> CopySourceInvalid;
+  // Track uses of a register as a source for a previous COPY
+  DenseMap<const MachineInstr *, SmallVector<const MachineInstr *>> CopySourceDefCopies;
 
   auto TryFoldSpillageCopies =
       [&, this](const SmallVectorImpl<MachineInstr *> &SC,
@@ -1376,6 +1378,26 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
           }
         };
 
+        auto HasUnexpectedCopySourceDef = [&](const MachineInstr *Copy, const MachineInstr *ExpectedDef) {
+          auto CopySouceDefPair = CopySourceDefCopies.find(Copy);
+          if (CopySouceDefPair == CopySourceDefCopies.end())
+            return false;
+
+          for (const MachineInstr *DefCopy : CopySouceDefPair->second)
+            if (DefCopy != ExpectedDef)
+              return true;
+          return false;
+        };
+        // Do not fold across an unexpected COPY def of a chains copy's source.
+        // The paired reload may be needed to restore the original source value.
+        // More info: https://github.com/llvm/llvm-project/issues/206839
+        for (size_t I = 1; I < SC.size(); ++I) {
+          if (HasUnexpectedCopySourceDef(SC[I], SC[I - 1]))
+            return;
+          if (I + 1 > SC.size() && HasUnexpectedCopySourceDef(RC[I], RC[I + 1]))
+            return;
+        }
+
         DestSourcePair InnerMostSpillCopy =
             *isCopyInstr(*SC[0], *TII, UseCopyInstr);
         DestSourcePair OuterMostSpillCopy =
@@ -1495,6 +1517,11 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
     }
 
     auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
+    // Track potential unexpected COPY def's that use a source in the chain. These
+    // cannot be folded across to preserve the original source value.
+    if (MachineInstr *LastUseCopy = Tracker.findLastSeenUseInCopy(Dst, *TRI)) {
+      CopySourceDefCopies[LastUseCopy].push_back(&MI);
+    }
     // Check if we can find a pair spill-reload copy.
     LLVM_DEBUG(dbgs() << "MCP: Searching paired spill for reload: ");
     LLVM_DEBUG(MI.dump());
diff --git a/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir b/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir
new file mode 100644
index 0000000000000..4908f6f159d0a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir
@@ -0,0 +1,33 @@
+# RUN: llc -mtriple=aarch64 -run-pass=machine-cp -enable-spill-copy-elim -verify-machineinstrs -o - %s | FileCheck %s
+# When running MachineCopyPropagation, we need to make sure COPY's do not get removed
+# when calls outside of the chain clobber a source included in the chain.
+# See: https://github.com/llvm/llvm-project/issues/206839
+---
+name: spill_chain_copy_clobbers_source
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $w10, $w13, $w23, $w25, $x7
+
+    ; CHECK: renamable $w10 = COPY killed renamable $w13
+    ; CHECK: renamable $w13 = COPY killed renamable $w10
+
+    renamable $w11 = COPY killed renamable $w10  ; S1
+    renamable $w10 = COPY killed renamable $w13  ; S2
+
+    renamable $w13 = COPY killed renamable $w23  ; clobbers S2 source
+    renamable $w15 = COPY killed renamable $w13
+    HINT 0, implicit killed $w15
+
+    renamable $w13 = COPY killed renamable $w25  ; S3
+
+    HINT 0, implicit killed $x7
+
+    renamable $w25 = COPY killed renamable $w13  ; R1
+    renamable $w13 = COPY killed renamable $w10  ; R2
+    renamable $w10 = COPY killed renamable $w11  ; R3
+
+    HINT 0, implicit killed $w10
+    HINT 0, implicit killed $w13
+
+...

>From a4b42cd3ddc499c75cf55e2707a08042ccdf21a7 Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Thu, 2 Jul 2026 13:45:53 +0100
Subject: [PATCH 2/3] Formatting

---
 llvm/lib/CodeGen/MachineCopyPropagation.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/CodeGen/MachineCopyPropagation.cpp b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
index a9b3cf68cc2c3..c2b77f55d10f1 100644
--- a/llvm/lib/CodeGen/MachineCopyPropagation.cpp
+++ b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
@@ -1338,7 +1338,8 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
   // we put the COPY in this set to keep property#2.
   DenseSet<const MachineInstr *> CopySourceInvalid;
   // Track uses of a register as a source for a previous COPY
-  DenseMap<const MachineInstr *, SmallVector<const MachineInstr *>> CopySourceDefCopies;
+  DenseMap<const MachineInstr *, SmallVector<const MachineInstr *>>
+      CopySourceDefCopies;
 
   auto TryFoldSpillageCopies =
       [&, this](const SmallVectorImpl<MachineInstr *> &SC,
@@ -1378,7 +1379,8 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
           }
         };
 
-        auto HasUnexpectedCopySourceDef = [&](const MachineInstr *Copy, const MachineInstr *ExpectedDef) {
+        auto HasUnexpectedCopySourceDef = [&](const MachineInstr *Copy,
+                                              const MachineInstr *ExpectedDef) {
           auto CopySouceDefPair = CopySourceDefCopies.find(Copy);
           if (CopySouceDefPair == CopySourceDefCopies.end())
             return false;
@@ -1517,8 +1519,8 @@ void MachineCopyPropagation::eliminateSpillageCopies(MachineBasicBlock &MBB) {
     }
 
     auto [Dst, Src] = getDstSrcMCRegs(*CopyOperands);
-    // Track potential unexpected COPY def's that use a source in the chain. These
-    // cannot be folded across to preserve the original source value.
+    // Track potential unexpected COPY def's that use a source in the chain.
+    // These cannot be folded across to preserve the original source value.
     if (MachineInstr *LastUseCopy = Tracker.findLastSeenUseInCopy(Dst, *TRI)) {
       CopySourceDefCopies[LastUseCopy].push_back(&MI);
     }

>From f084f71791f0fa623a3d11d5a83f78fad5632a90 Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Mon, 6 Jul 2026 10:00:05 +0100
Subject: [PATCH 3/3] Update test to check full MIR output

---
 .../aarch64-no-fold-over-clobbered-source.mir     | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir b/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir
index 4908f6f159d0a..1bac98daf2169 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir
+++ b/llvm/test/CodeGen/AArch64/aarch64-no-fold-over-clobbered-source.mir
@@ -1,3 +1,4 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
 # RUN: llc -mtriple=aarch64 -run-pass=machine-cp -enable-spill-copy-elim -verify-machineinstrs -o - %s | FileCheck %s
 # When running MachineCopyPropagation, we need to make sure COPY's do not get removed
 # when calls outside of the chain clobber a source included in the chain.
@@ -9,9 +10,19 @@ body: |
   bb.0:
     liveins: $w10, $w13, $w23, $w25, $x7
 
-    ; CHECK: renamable $w10 = COPY killed renamable $w13
-    ; CHECK: renamable $w13 = COPY killed renamable $w10
 
+    ; CHECK-LABEL: name: spill_chain_copy_clobbers_source
+    ; CHECK: liveins: $w10, $w13, $w23, $w25, $x7
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: renamable $w11 = COPY killed renamable $w10
+    ; CHECK-NEXT: renamable $w10 = COPY killed renamable $w13
+    ; CHECK-NEXT: renamable $w15 = COPY $w23
+    ; CHECK-NEXT: HINT 0, implicit killed $w15
+    ; CHECK-NEXT: HINT 0, implicit killed $x7
+    ; CHECK-NEXT: renamable $w13 = COPY killed renamable $w10
+    ; CHECK-NEXT: renamable $w10 = COPY killed renamable $w11
+    ; CHECK-NEXT: HINT 0, implicit killed $w10
+    ; CHECK-NEXT: HINT 0, implicit killed $w13
     renamable $w11 = COPY killed renamable $w10  ; S1
     renamable $w10 = COPY killed renamable $w13  ; S2
 



More information about the llvm-commits mailing list