[llvm] [MachineCopyPropagation][NFC] Refactor EliminateSpillageCopies (PR #192609)

Jack Styles via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 17 01:28:48 PDT 2026


https://github.com/Stylie777 created https://github.com/llvm/llvm-project/pull/192609

This patch builds on the original implementation to address areas that may impact compile time regression if enabled. The aim of the patch is to streamline and improve the implementation for better compile time impact. A summary of the changes is as follows:
- Cost modelling that does an initial scan of the block, any blocks with less than 6 copies are immediately skipped.
- RegMask scan in `findLastSeenDefInCopy` removed. This now only checks the recorded copies to ensure that RegMasks are clobbered when they are seen if they clobber a Reg
- Streamlining of `IsSpillReloadPair` and `IsChainedCopy` to reduce the need for a second call to isCopyInstr to get the DestSourcePair, these are now returned from the lamdba function
- Use of TRI API to get the CommonRegClass

Assisted-by: Claude Sonnet 4.6 (Co-Pilot)

>From 60b81d115cb72cbf1b853d460466f6028dffb891 Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Tue, 14 Apr 2026 14:38:38 +0100
Subject: [PATCH] [MachineCopyPropagation][NFC] Refactor
 EliminateSpillageCopies

This patch builds on the original implementation to address areas that
may impact compile time regression if enabled. The aim of the patch is
to streamline and improve the implementation for better compile time
impact. A summary of the changes is as follows:
- Cost modelling that does an initial scan of the block, any blocks with
less than 6 copies are immediately skipped.
- RegMask scan in `findLastSeenDefInCopy` removed. This now only checks
the recorded copies to ensure that RegMasks are clobbered when they are
seen if they clobber a Reg
- Streamlining of `IsSpillReloadPair` and `IsChainedCopy` to reduce the
need for a second call to isCopyInstr to get the DestSourcePair, these
are now returned from the lamdba function
- Use of TRI API to get the CommonRegClass, rather than scanning all
RegClasses

Assisted-by: Claude Sonnet 4.6 (Co-Pilot)
---
 llvm/lib/CodeGen/MachineCopyPropagation.cpp | 97 ++++++++++++---------
 1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/CodeGen/MachineCopyPropagation.cpp b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
index 58ff6f77830b3..1111c68b24575 100644
--- a/llvm/lib/CodeGen/MachineCopyPropagation.cpp
+++ b/llvm/lib/CodeGen/MachineCopyPropagation.cpp
@@ -421,20 +421,20 @@ class CopyTracker {
     if (!TRI.isSubRegisterEq(Def, Reg))
       return nullptr;
 
-    for (const MachineInstr &MI :
-         make_range(static_cast<const MachineInstr *>(DefCopy)->getIterator(),
-                    Current.getIterator()))
-      for (const MachineOperand &MO : MI.operands())
-        if (MO.isRegMask())
-          if (MO.clobbersPhysReg(Def)) {
-            LLVM_DEBUG(dbgs() << "MCP: Removed tracking of "
-                              << printReg(Def, &TRI) << "\n");
-            return nullptr;
-          }
-
     return DefCopy;
   }
 
+  void clobberNonPreservedRegs(const BitVector &PreservedRegUnits,
+                              const TargetRegisterInfo &TRI,
+                              const TargetInstrInfo &TII, bool UseCopyInstr) {
+    SmallVector<MCRegUnit, 8> UnitsToClobber;
+    for (auto &[Unit, _] : Copies)
+      if (!PreservedRegUnits.test(static_cast<unsigned>(Unit)))
+        UnitsToClobber.push_back(Unit);
+    for (MCRegUnit Unit : UnitsToClobber)
+      clobberRegUnit(Unit, TRI, TII, UseCopyInstr);
+  }
+
   // Find last COPY that uses Reg.
   MachineInstr *findLastSeenUseInCopy(MCRegister Reg,
                                       const TargetRegisterInfo &TRI) {
@@ -1298,6 +1298,18 @@ void MachineCopyPropagation::BackwardCopyPropagateBlock(
 // Reg is defined by a COPY, we untrack this Reg via
 // CopyTracker::clobberRegister(Reg, ...).
 void MachineCopyPropagation::EliminateSpillageCopies(MachineBasicBlock &MBB) {
+
+  // Perform some cost modelling to ensure that only MBB's with more
+  // than 6 copies are checked. To create a chain that can be optimised,
+  // 6 copies are needed.
+  unsigned CopyCount = 0;
+  for (const MachineInstr &MI : MBB) {
+    if (isCopyInstr(MI, *TII, UseCopyInstr) && ++CopyCount > 6)
+      break;
+  }
+  if (CopyCount < 6)
+    return;
+
   // ChainLeader maps MI inside a spill-reload chain to its innermost reload COPY.
   // Thus we can track if a MI belongs to an existing spill-reload chain.
   DenseMap<MachineInstr *, MachineInstr *> ChainLeader;
@@ -1337,10 +1349,8 @@ void MachineCopyPropagation::EliminateSpillageCopies(MachineBasicBlock &MBB) {
             return;
 
         auto CheckCopyConstraint = [this](Register Def, Register Src) {
-          for (const TargetRegisterClass *RC : TRI->regclasses()) {
-            if (RC->contains(Def) && RC->contains(Src))
-              return true;
-          }
+          if (TRI->getCommonMinimalPhysRegClass(Def, Src))
+            return true;
           return false;
         };
 
@@ -1380,45 +1390,44 @@ void MachineCopyPropagation::EliminateSpillageCopies(MachineBasicBlock &MBB) {
         }
       };
 
-  auto IsFoldableCopy = [this](const MachineInstr &MaybeCopy) {
+  auto GetFoldableCopy =
+      [this](const MachineInstr &MaybeCopy) -> std::optional<DestSourcePair> {
     if (MaybeCopy.getNumImplicitOperands() > 0)
-      return false;
+      return std::nullopt;
     std::optional<DestSourcePair> CopyOperands =
         isCopyInstr(MaybeCopy, *TII, UseCopyInstr);
     if (!CopyOperands)
-      return false;
+      return std::nullopt;
     Register Src = CopyOperands->Source->getReg();
     Register Def = CopyOperands->Destination->getReg();
-    return Src && Def && !TRI->regsOverlap(Src, Def) &&
-           CopyOperands->Source->isRenamable() &&
-           CopyOperands->Destination->isRenamable();
+    if (Src && Def && !TRI->regsOverlap(Src, Def) &&
+        CopyOperands->Source->isRenamable() &&
+        CopyOperands->Destination->isRenamable())
+      return CopyOperands;
+    return std::nullopt;
   };
 
-  auto IsSpillReloadPair = [&, this](const MachineInstr &Spill,
-                                     const MachineInstr &Reload) {
-    if (!IsFoldableCopy(Spill) || !IsFoldableCopy(Reload))
-      return false;
-    std::optional<DestSourcePair> SpillCopy =
-        isCopyInstr(Spill, *TII, UseCopyInstr);
-    std::optional<DestSourcePair> ReloadCopy =
-        isCopyInstr(Reload, *TII, UseCopyInstr);
-    if (!SpillCopy || !ReloadCopy)
+  auto IsSpillReloadPair = [&](const MachineInstr &Spill,
+                               const MachineInstr &Reload) {
+    std::optional<DestSourcePair> FoldableSpillCopy = GetFoldableCopy(Spill);
+    std::optional<DestSourcePair> FoldableReloadCopy = GetFoldableCopy(Reload);
+    if (!FoldableReloadCopy || !FoldableSpillCopy)
       return false;
-    return SpillCopy->Source->getReg() == ReloadCopy->Destination->getReg() &&
-           SpillCopy->Destination->getReg() == ReloadCopy->Source->getReg();
+    return FoldableSpillCopy->Source->getReg() ==
+               FoldableReloadCopy->Destination->getReg() &&
+           FoldableSpillCopy->Destination->getReg() ==
+               FoldableReloadCopy->Source->getReg();
   };
 
-  auto IsChainedCopy = [&, this](const MachineInstr &Prev,
-                                 const MachineInstr &Current) {
-    if (!IsFoldableCopy(Prev) || !IsFoldableCopy(Current))
+  auto IsChainedCopy = [&](const MachineInstr &Prev,
+                           const MachineInstr &Current) {
+    std::optional<DestSourcePair> FoldablePrevCopy = GetFoldableCopy(Prev);
+    std::optional<DestSourcePair> FoldableCurrentCopy =
+        GetFoldableCopy(Current);
+    if (!FoldablePrevCopy || !FoldableCurrentCopy)
       return false;
-    std::optional<DestSourcePair> PrevCopy =
-        isCopyInstr(Prev, *TII, UseCopyInstr);
-    std::optional<DestSourcePair> CurrentCopy =
-        isCopyInstr(Current, *TII, UseCopyInstr);
-    if (!PrevCopy || !CurrentCopy)
-      return false;
-    return PrevCopy->Source->getReg() == CurrentCopy->Destination->getReg();
+    return FoldablePrevCopy->Source->getReg() ==
+           FoldableCurrentCopy->Destination->getReg();
   };
 
   for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
@@ -1429,6 +1438,10 @@ void MachineCopyPropagation::EliminateSpillageCopies(MachineBasicBlock &MBB) {
     SmallSet<Register, 8> RegsToClobber;
     if (!CopyOperands) {
       for (const MachineOperand &MO : MI.operands()) {
+        if (MO.isRegMask()) {
+          BitVector &PreservedRegUnits = Tracker.getPreservedRegUnits(MO, *TRI);
+          Tracker.clobberNonPreservedRegs(PreservedRegUnits, *TRI, *TII, UseCopyInstr);
+        }
         if (!MO.isReg())
           continue;
         Register Reg = MO.getReg();



More information about the llvm-commits mailing list