[llvm] [RegAlloc] Add register allocation anti-hints infrastructure (PR #218071)

Syadus Sefat via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 12 12:17:48 PDT 2026


https://github.com/mssefat updated https://github.com/llvm/llvm-project/pull/218071

>From c07ea5062c496e42eb8d70103dfdae199a31a7a3 Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Wed, 19 Aug 2026 13:08:34 -0500
Subject: [PATCH 1/5] [RegAlloc] Add register allocation anti-hints
 infrastructure

---
 .../llvm/CodeGen/MachineRegisterInfo.h        | 59 +++++++++++++++++++
 .../include/llvm/CodeGen/TargetRegisterInfo.h |  9 +++
 llvm/lib/CodeGen/AllocationOrder.cpp          | 36 ++++++++++-
 llvm/lib/CodeGen/AllocationOrder.h            | 11 ++++
 llvm/lib/CodeGen/MachineRegisterInfo.cpp      | 22 +++++++
 llvm/lib/CodeGen/TargetRegisterInfo.cpp       | 40 +++++++++++++
 .../unittests/CodeGen/AllocationOrderTest.cpp | 24 ++++++++
 7 files changed, 198 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
index a26462641de52..890355febbb28 100644
--- a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
@@ -17,6 +17,7 @@
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSet.h"
@@ -42,6 +43,7 @@
 namespace llvm {
 
 class PSetIterator;
+class VirtRegMap;
 
 /// Convenient type to represent either a register class or a register bank.
 using RegClassOrRegBank =
@@ -119,6 +121,12 @@ class MachineRegisterInfo {
   /// pass when deserializing from .mir files.
   SmallVector<PendingVirtRegMapEntry, 0> PendingVirtRegMapEntries;
 
+  /// AntiHintRegs - This vector records register anti-hints for
+  /// virtual registers. For each virtual register, it keeps a vector of virtual
+  /// registers that should NOT be allocated to the same or overlapping physical
+  /// registers.
+  IndexedMap<SmallVector<Register, 4>, VirtReg2IndexFunctor> AntiHintRegs;
+
   /// PhysRegUseDefLists - This is an array of the head of the use/def list for
   /// physical registers.
   std::unique_ptr<MachineOperand *[]> PhysRegUseDefLists;
@@ -906,6 +914,57 @@ class MachineRegisterInfo {
     return RegAllocHints.inBounds(VReg) ? &RegAllocHints[VReg] : nullptr;
   }
 
+  /// Add a register allocation anti-hint for the specified virtual register.
+  /// This tells the allocator to avoid allocating VReg to the same physical
+  /// register as AntiHintVReg (or overlapping ones).
+  void addRegAllocAntiHint(Register VReg, Register AntiHintVReg) {
+    assert(VReg.isVirtual() && AntiHintVReg.isVirtual() &&
+           "Anti-hints and anti-hint targets are only for virtual registers");
+    AntiHintRegs.grow(VReg);
+    SmallVector<Register, 4> &AntiHints = AntiHintRegs[VReg];
+    // Avoid duplicates
+    if (!is_contained(AntiHints, AntiHintVReg))
+      AntiHints.push_back(AntiHintVReg);
+  }
+
+  /// Add multiple anti-hints at once.
+  void addRegAllocationAntiHints(Register VReg,
+                                 ArrayRef<Register> AntiHintVRegs) {
+    for (Register AntiHint : AntiHintVRegs)
+      addRegAllocAntiHint(VReg, AntiHint);
+  }
+
+  /// Clear all anti-hints for a register.
+  void clearRegAllocationAntiHints(Register VReg) {
+    assert(VReg.isVirtual() && "Anti-hints are only for virtual registers");
+    if (AntiHintRegs.inBounds(VReg))
+      AntiHintRegs[VReg].clear();
+  }
+
+  /// Return the vector of anti-hints for VReg.
+  ArrayRef<Register> getRegAllocationAntiHints(Register VReg) const {
+    assert(VReg.isVirtual() && "Anti-hints are only for virtual registers");
+    if (!AntiHintRegs.inBounds(VReg))
+      return ArrayRef<Register>();
+    return AntiHintRegs[VReg];
+  }
+
+  /// Check if VReg has AntiHintVReg as an anti-hint.
+  bool hasRegAllocationAntiHint(Register VReg, Register AntiHintVReg) const {
+    assert(VReg.isVirtual() && AntiHintVReg.isVirtual() &&
+           "Anti-hints and anti-hint targets are only for virtual registers");
+    if (!AntiHintRegs.inBounds(VReg))
+      return false;
+    const SmallVector<Register, 4> &AntiHints = AntiHintRegs[VReg];
+    return is_contained(AntiHints, AntiHintVReg);
+  }
+
+  /// Get the set of physical registers to avoid.
+  /// VRM is the current virtual register map showing allocations made so far.
+  void getPhysRegAntiHints(Register VReg,
+                           SmallVectorImpl<MCPhysReg> &PhysAntiHints,
+                           const VirtRegMap &VRM) const;
+
   /// markUsesInDebugValueAsUndef - Mark every DBG_VALUE referencing the
   /// specified register as undefined which causes the DBG_VALUE to be
   /// deleted during LiveDebugVariables analysis.
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 484234fa055fe..e0c358d25a087 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -852,6 +852,15 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
     // Do nothing.
   }
 
+  /// Apply anti-hints to the allocation order.
+  virtual void
+  applyRegAllocationAntiHints(Register VirtReg, ArrayRef<MCPhysReg> &Order,
+                              SmallVectorImpl<MCPhysReg> &OrderStorage,
+                              SmallVectorImpl<MCPhysReg> &AntiHints,
+                              const MachineFunction &MF,
+                              const VirtRegMap *VRM = nullptr,
+                              const LiveRegMatrix *Matrix = nullptr) const;
+
   /// Allow the target to reverse allocation order of local live ranges. This
   /// will generally allocate shorter local live ranges first. For targets with
   /// many registers, this could reduce regalloc compile time by a large
diff --git a/llvm/lib/CodeGen/AllocationOrder.cpp b/llvm/lib/CodeGen/AllocationOrder.cpp
index 183dc8af1b91b..1b3d3639fbc2a 100644
--- a/llvm/lib/CodeGen/AllocationOrder.cpp
+++ b/llvm/lib/CodeGen/AllocationOrder.cpp
@@ -31,6 +31,7 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
                                         const LiveRegMatrix *Matrix) {
   const MachineFunction &MF = VRM.getMachineFunction();
   const TargetRegisterInfo *TRI = &VRM.getTargetRegInfo();
+  const MachineRegisterInfo &MRI = MF.getRegInfo();
   auto Order = RegClassInfo.getOrder(MF.getRegInfo().getRegClass(VirtReg));
   SmallVector<MCPhysReg, 16> Hints;
   bool HardHints =
@@ -44,8 +45,37 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
       dbgs() << '\n';
     }
   });
-  assert(all_of(Hints,
-                [&](MCPhysReg Hint) { return is_contained(Order, Hint); }) &&
+
+  // Get anti-hints
+  SmallVector<MCPhysReg, 16> AntiHintedPhysRegs;
+  MRI.getPhysRegAntiHints(VirtReg, AntiHintedPhysRegs, VRM);
+
+  LLVM_DEBUG({
+    if (!AntiHintedPhysRegs.empty()) {
+      dbgs() << "anti-hints:";
+      for (MCPhysReg AntiHint : AntiHintedPhysRegs)
+        dbgs() << ' ' << printReg(AntiHint, TRI);
+      dbgs() << '\n';
+    }
+  });
+
+  // Storage for filtered order (used if anti-hints cause reordering)
+  SmallVector<MCPhysReg, 16> ShuffledOrder;
+
+  if (!AntiHintedPhysRegs.empty()) {
+    TRI->applyRegAllocationAntiHints(VirtReg, Order, ShuffledOrder,
+                                     AntiHintedPhysRegs, MF, &VRM, Matrix);
+  }
+  // Use ShuffledOrder as the order if it was populated by anti-hints
+  // processing
+  ArrayRef<MCPhysReg> FinalOrder =
+      ShuffledOrder.empty() ? Order : ShuffledOrder;
+  // Create allocation order object
+  AllocationOrder AO(std::move(Hints), FinalOrder, HardHints,
+                     std::move(ShuffledOrder));
+
+  assert(all_of(AO.Hints,
+                [&](MCPhysReg Hint) { return is_contained(AO.Order, Hint); }) &&
          "Target hint is outside allocation order.");
-  return AllocationOrder(std::move(Hints), Order, HardHints);
+  return AO;
 }
diff --git a/llvm/lib/CodeGen/AllocationOrder.h b/llvm/lib/CodeGen/AllocationOrder.h
index 3dd02c3b14d3a..3b7c7cd4cac10 100644
--- a/llvm/lib/CodeGen/AllocationOrder.h
+++ b/llvm/lib/CodeGen/AllocationOrder.h
@@ -20,6 +20,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/CodeGen/Register.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
 
 namespace llvm {
 
@@ -29,6 +30,9 @@ class LiveRegMatrix;
 
 class LLVM_LIBRARY_VISIBILITY AllocationOrder {
   const SmallVector<MCPhysReg, 16> Hints;
+  // Used as storage if the Order received in the constructor needs to be
+  // altered.
+  SmallVector<MCPhysReg, 16> FilteredOrderStorage;
   ArrayRef<MCPhysReg> Order;
   // How far into the Order we can iterate. This is 0 if the AllocationOrder is
   // constructed with HardHints = true, Order.size() otherwise. While
@@ -92,6 +96,13 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
       : Hints(std::move(Hints)), Order(Order),
         IterationLimit(HardHints ? 0 : static_cast<int>(Order.size())) {}
 
+  /// Create an AllocationOrder with pre-computed FilteredOrderStorage.
+  AllocationOrder(SmallVector<MCPhysReg, 16> &&Hints, ArrayRef<MCPhysReg> Order,
+                  bool HardHints, SmallVector<MCPhysReg, 16> &&Storage)
+      : Hints(std::move(Hints)), FilteredOrderStorage(std::move(Storage)),
+        Order(FilteredOrderStorage.empty() ? Order : FilteredOrderStorage),
+        IterationLimit(HardHints ? 0 : static_cast<int>(this->Order.size())) {}
+
   Iterator begin() const {
     return Iterator(*this, -(static_cast<int>(Hints.size())));
   }
diff --git a/llvm/lib/CodeGen/MachineRegisterInfo.cpp b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
index dbba413548018..3918c169b978c 100644
--- a/llvm/lib/CodeGen/MachineRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
@@ -11,15 +11,18 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/Register.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/DebugLoc.h"
@@ -714,3 +717,22 @@ void MachineRegisterInfo::updateDbgUsersToReg(
     }
   }
 }
+
+void MachineRegisterInfo::getPhysRegAntiHints(
+    Register VReg, SmallVectorImpl<MCPhysReg> &PhysAntiHints,
+    const VirtRegMap &VRM) const {
+  assert(VReg.isVirtual() && "Anti-hints are only for virtual registers");
+  if (!AntiHintRegs.inBounds(VReg))
+    return;
+
+  const SmallVector<Register, 4> &AntiHints = AntiHintRegs[VReg];
+
+  for (Register AntiHintVReg : AntiHints) {
+    // Check if the anti-hinted register has been allocated
+    if (VRM.hasPhys(AntiHintVReg)) {
+      MCPhysReg PhysReg = VRM.getPhys(AntiHintVReg);
+      if (!is_contained(PhysAntiHints, PhysReg))
+        PhysAntiHints.push_back(PhysReg);
+    }
+  }
+}
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index 3b29b0863dd6c..fd696297e35d9 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -443,6 +443,46 @@ bool TargetRegisterInfo::getRegAllocationHints(
   return false;
 }
 
+void TargetRegisterInfo::applyRegAllocationAntiHints(
+    Register VirtReg, ArrayRef<MCPhysReg> &Order,
+    SmallVectorImpl<MCPhysReg> &OrderStorage,
+    SmallVectorImpl<MCPhysReg> &AntiHints, const MachineFunction &MF,
+    const VirtRegMap *VRM, const LiveRegMatrix *Matrix) const {
+
+  if (AntiHints.empty() || !VRM)
+    return;
+
+  auto isAntiHinted = [&](MCPhysReg Reg) {
+    return llvm::any_of(AntiHints, [&](MCPhysReg AntiHint) {
+      return regsOverlap(Reg, AntiHint);
+    });
+  };
+
+  // Copy order into storage
+  OrderStorage.clear();
+  OrderStorage.assign(Order.begin(), Order.end());
+
+  // Partition non-anti-hinted register go first
+  auto PartionPoint =
+      std::stable_partition(OrderStorage.begin(), OrderStorage.end(),
+                            [&](MCPhysReg Reg) { return !isAntiHinted(Reg); });
+
+  Order = OrderStorage;
+
+  // print the details
+  LLVM_DEBUG({
+    size_t NonAntiHintedCount =
+        std::distance(OrderStorage.begin(), PartionPoint);
+    size_t AntiHintedCount = std::distance(PartionPoint, OrderStorage.end());
+    dbgs() << "Added " << NonAntiHintedCount
+           << " non-anti-hinted registers first\n"
+           << "Added " << AntiHintedCount
+           << " anti-hinted registers at the end\n";
+  });
+
+  return;
+}
+
 bool TargetRegisterInfo::isCalleeSavedPhysReg(
     MCRegister PhysReg, const MachineFunction &MF) const {
   if (!PhysReg)
diff --git a/llvm/unittests/CodeGen/AllocationOrderTest.cpp b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
index d4da8e28ae7f7..ec02579f55c58 100644
--- a/llvm/unittests/CodeGen/AllocationOrderTest.cpp
+++ b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
@@ -116,3 +116,27 @@ TEST(AllocationOrderTest, IsHintTest) {
   EXPECT_FALSE(I.isHint());
   EXPECT_EQ(V, 5U);
 }
+
+TEST(AllocationOrderTest, StorageOverridesOrder) {
+  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+  SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
+  SmallVector<MCPhysReg, 16> Storage = {5, 3, 4};
+  AllocationOrder O(std::move(Hints), Order, false, std::move(Storage));
+  EXPECT_EQ((std::vector<MCPhysReg>{1, 2, 5, 3, 4}), loadOrder(O));
+}
+
+TEST(AllocationOrderTest, EmptyStorageFallsBackToOrder) {
+  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+  SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
+  SmallVector<MCPhysReg, 16> Storage;
+  AllocationOrder O(std::move(Hints), Order, false, std::move(Storage));
+  EXPECT_EQ((std::vector<MCPhysReg>{1, 2, 3, 4, 5}), loadOrder(O));
+}
+
+TEST(AllocationOrderTest, StorageHardHints) {
+  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+  SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
+  SmallVector<MCPhysReg, 16> Storage = {5, 3, 4};
+  AllocationOrder O(std::move(Hints), Order, true, std::move(Storage));
+  EXPECT_EQ((std::vector<MCPhysReg>{1, 2}), loadOrder(O));
+}

>From 463d506d42371d2cfcdbcffc49a713d249c753ce Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Wed, 26 Aug 2026 10:18:38 -0500
Subject: [PATCH 2/5] Addressed review

---
 llvm/lib/CodeGen/AllocationOrder.cpp | 12 +++++-------
 llvm/lib/CodeGen/AllocationOrder.h   |  8 ++++----
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/CodeGen/AllocationOrder.cpp b/llvm/lib/CodeGen/AllocationOrder.cpp
index 1b3d3639fbc2a..ca34a00ea5d08 100644
--- a/llvm/lib/CodeGen/AllocationOrder.cpp
+++ b/llvm/lib/CodeGen/AllocationOrder.cpp
@@ -9,7 +9,8 @@
 // This file implements an allocation order for virtual registers.
 //
 // The preferred allocation order for a virtual register depends on allocation
-// hints and target hooks. The AllocationOrder class encapsulates all of that.
+// hints, anti-hints, and target hooks. The AllocationOrder class encapsulates
+// all of that.
 //
 //===----------------------------------------------------------------------===//
 
@@ -59,19 +60,16 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
     }
   });
 
-  // Storage for filtered order (used if anti-hints cause reordering)
+  // Storage for shuffled order (used if anti-hints cause reordering)
   SmallVector<MCPhysReg, 16> ShuffledOrder;
 
   if (!AntiHintedPhysRegs.empty()) {
     TRI->applyRegAllocationAntiHints(VirtReg, Order, ShuffledOrder,
                                      AntiHintedPhysRegs, MF, &VRM, Matrix);
   }
-  // Use ShuffledOrder as the order if it was populated by anti-hints
-  // processing
-  ArrayRef<MCPhysReg> FinalOrder =
-      ShuffledOrder.empty() ? Order : ShuffledOrder;
+
   // Create allocation order object
-  AllocationOrder AO(std::move(Hints), FinalOrder, HardHints,
+  AllocationOrder AO(std::move(Hints), Order, HardHints,
                      std::move(ShuffledOrder));
 
   assert(all_of(AO.Hints,
diff --git a/llvm/lib/CodeGen/AllocationOrder.h b/llvm/lib/CodeGen/AllocationOrder.h
index 3b7c7cd4cac10..84e459c5b8e67 100644
--- a/llvm/lib/CodeGen/AllocationOrder.h
+++ b/llvm/lib/CodeGen/AllocationOrder.h
@@ -32,7 +32,7 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
   const SmallVector<MCPhysReg, 16> Hints;
   // Used as storage if the Order received in the constructor needs to be
   // altered.
-  SmallVector<MCPhysReg, 16> FilteredOrderStorage;
+  SmallVector<MCPhysReg, 16> ShuffledOrderStorage;
   ArrayRef<MCPhysReg> Order;
   // How far into the Order we can iterate. This is 0 if the AllocationOrder is
   // constructed with HardHints = true, Order.size() otherwise. While
@@ -96,11 +96,11 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
       : Hints(std::move(Hints)), Order(Order),
         IterationLimit(HardHints ? 0 : static_cast<int>(Order.size())) {}
 
-  /// Create an AllocationOrder with pre-computed FilteredOrderStorage.
+  /// Create an AllocationOrder with pre-computed ShuffledOrderStorage.
   AllocationOrder(SmallVector<MCPhysReg, 16> &&Hints, ArrayRef<MCPhysReg> Order,
                   bool HardHints, SmallVector<MCPhysReg, 16> &&Storage)
-      : Hints(std::move(Hints)), FilteredOrderStorage(std::move(Storage)),
-        Order(FilteredOrderStorage.empty() ? Order : FilteredOrderStorage),
+      : Hints(std::move(Hints)), ShuffledOrderStorage(std::move(Storage)),
+        Order(ShuffledOrderStorage.empty() ? Order : ShuffledOrderStorage),
         IterationLimit(HardHints ? 0 : static_cast<int>(this->Order.size())) {}
 
   Iterator begin() const {

>From a018b6c8a3ee5a4afeb50680faa2d0db5525cea7 Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Sun, 30 Aug 2026 15:00:47 -0500
Subject: [PATCH 3/5] Addressed review: Removed ShuffledOrderStorage

---
 .../include/llvm/CodeGen/TargetRegisterInfo.h | 13 +++---
 llvm/lib/CodeGen/AllocationOrder.cpp          | 31 +++++++------
 llvm/lib/CodeGen/AllocationOrder.h            | 44 +++++++++++--------
 llvm/lib/CodeGen/TargetRegisterInfo.cpp       | 25 +++++------
 .../unittests/CodeGen/AllocationOrderTest.cpp | 21 ++++-----
 5 files changed, 69 insertions(+), 65 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index e0c358d25a087..bdb2a4d0363b5 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -853,13 +853,12 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   }
 
   /// Apply anti-hints to the allocation order.
-  virtual void
-  applyRegAllocationAntiHints(Register VirtReg, ArrayRef<MCPhysReg> &Order,
-                              SmallVectorImpl<MCPhysReg> &OrderStorage,
-                              SmallVectorImpl<MCPhysReg> &AntiHints,
-                              const MachineFunction &MF,
-                              const VirtRegMap *VRM = nullptr,
-                              const LiveRegMatrix *Matrix = nullptr) const;
+  virtual void applyRegAllocationAntiHints(
+      Register VirtReg, ArrayRef<MCPhysReg> Order,
+      SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
+      SmallVectorImpl<MCPhysReg> &AntiHints, const MachineFunction &MF,
+      const VirtRegMap *VRM = nullptr,
+      const LiveRegMatrix *Matrix = nullptr) const;
 
   /// Allow the target to reverse allocation order of local live ranges. This
   /// will generally allocate shorter local live ranges first. For targets with
diff --git a/llvm/lib/CodeGen/AllocationOrder.cpp b/llvm/lib/CodeGen/AllocationOrder.cpp
index ca34a00ea5d08..2367095ce23df 100644
--- a/llvm/lib/CodeGen/AllocationOrder.cpp
+++ b/llvm/lib/CodeGen/AllocationOrder.cpp
@@ -34,14 +34,20 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
   const TargetRegisterInfo *TRI = &VRM.getTargetRegInfo();
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   auto Order = RegClassInfo.getOrder(MF.getRegInfo().getRegClass(VirtReg));
-  SmallVector<MCPhysReg, 16> Hints;
-  bool HardHints =
-      TRI->getRegAllocationHints(VirtReg, Order, Hints, MF, &VRM, Matrix);
+
+  // HintsAndCustomOrder holds Hints first followed by the shuffled order if the
+  // anti-hints shuffle it.
+  SmallVector<MCPhysReg, 16> HintsAndCustomOrder;
+
+  // Get hints
+  bool HardHints = TRI->getRegAllocationHints(
+      VirtReg, Order, HintsAndCustomOrder, MF, &VRM, Matrix);
+  const int NumHints = static_cast<int>(HintsAndCustomOrder.size());
 
   LLVM_DEBUG({
-    if (!Hints.empty()) {
+    if (NumHints) {
       dbgs() << "hints:";
-      for (MCPhysReg Hint : Hints)
+      for (MCPhysReg Hint : HintsAndCustomOrder)
         dbgs() << ' ' << printReg(Hint, TRI);
       dbgs() << '\n';
     }
@@ -60,19 +66,18 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
     }
   });
 
-  // Storage for shuffled order (used if anti-hints cause reordering)
-  SmallVector<MCPhysReg, 16> ShuffledOrder;
-
   if (!AntiHintedPhysRegs.empty()) {
-    TRI->applyRegAllocationAntiHints(VirtReg, Order, ShuffledOrder,
-                                     AntiHintedPhysRegs, MF, &VRM, Matrix);
+    HintsAndCustomOrder.reserve(NumHints + Order.size());
+    TRI->applyRegAllocationAntiHints(VirtReg, Order, HintsAndCustomOrder,
+                                     NumHints, AntiHintedPhysRegs, MF, &VRM,
+                                     Matrix);
   }
 
   // Create allocation order object
-  AllocationOrder AO(std::move(Hints), Order, HardHints,
-                     std::move(ShuffledOrder));
+  AllocationOrder AO(std::move(HintsAndCustomOrder), NumHints, Order,
+                     HardHints);
 
-  assert(all_of(AO.Hints,
+  assert(all_of(AO.hints(),
                 [&](MCPhysReg Hint) { return is_contained(AO.Order, Hint); }) &&
          "Target hint is outside allocation order.");
   return AO;
diff --git a/llvm/lib/CodeGen/AllocationOrder.h b/llvm/lib/CodeGen/AllocationOrder.h
index 84e459c5b8e67..643c927103802 100644
--- a/llvm/lib/CodeGen/AllocationOrder.h
+++ b/llvm/lib/CodeGen/AllocationOrder.h
@@ -29,10 +29,11 @@ class VirtRegMap;
 class LiveRegMatrix;
 
 class LLVM_LIBRARY_VISIBILITY AllocationOrder {
-  const SmallVector<MCPhysReg, 16> Hints;
-  // Used as storage if the Order received in the constructor needs to be
-  // altered.
-  SmallVector<MCPhysReg, 16> ShuffledOrderStorage;
+  // The Hints occupy [0, NumHints). If the Order received in the constructor
+  // needed to be shuffled, the shuffled copy is stored right after them, at
+  // [NumHints, end).
+  const SmallVector<MCPhysReg, 16> HintsAndCustomOrder;
+  const int NumHints;
   ArrayRef<MCPhysReg> Order;
   // How far into the Order we can iterate. This is 0 if the AllocationOrder is
   // constructed with HardHints = true, Order.size() otherwise. While
@@ -43,6 +44,10 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
   // IterationLimit defines an invalid iterator position.
   const int IterationLimit;
 
+  ArrayRef<MCPhysReg> hints() const {
+    return ArrayRef<MCPhysReg>(HintsAndCustomOrder).take_front(NumHints);
+  }
+
 public:
   /// Forward iterator for an AllocationOrder.
   class Iterator final {
@@ -58,7 +63,7 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
     /// Return the next physical register in the allocation order.
     MCRegister operator*() const {
       if (Pos < 0)
-        return AO.Hints.end()[Pos];
+        return AO.HintsAndCustomOrder[AO.NumHints + Pos];
       assert(Pos < AO.IterationLimit);
       return AO.Order[Pos];
     }
@@ -89,23 +94,26 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
                                 const RegisterClassInfo &RegClassInfo,
                                 const LiveRegMatrix *Matrix);
 
+  /// Create an AllocationOrder from HintsAndCustomOrder that contains NumHints
+  /// Hints optionally followed by a reordered Order. If no reordered copy is
+  /// present use Order as-is.
+  AllocationOrder(SmallVector<MCPhysReg, 16> &&HintsAndCustomOrder,
+                  int NumHints, ArrayRef<MCPhysReg> Order, bool HardHints)
+      : HintsAndCustomOrder(std::move(HintsAndCustomOrder)), NumHints(NumHints),
+        Order(static_cast<int>(this->HintsAndCustomOrder.size()) > NumHints
+                  ? ArrayRef<MCPhysReg>(this->HintsAndCustomOrder)
+                        .drop_front(NumHints)
+                  : Order),
+        IterationLimit(HardHints ? 0 : static_cast<int>(this->Order.size())) {}
+
   /// Create an AllocationOrder given the Hints, Order, and HardHints values.
   /// Use the create method above - the ctor is for unittests.
   AllocationOrder(SmallVector<MCPhysReg, 16> &&Hints, ArrayRef<MCPhysReg> Order,
                   bool HardHints)
-      : Hints(std::move(Hints)), Order(Order),
-        IterationLimit(HardHints ? 0 : static_cast<int>(Order.size())) {}
+      : AllocationOrder(std::move(Hints), static_cast<int>(Hints.size()), Order,
+                        HardHints) {}
 
-  /// Create an AllocationOrder with pre-computed ShuffledOrderStorage.
-  AllocationOrder(SmallVector<MCPhysReg, 16> &&Hints, ArrayRef<MCPhysReg> Order,
-                  bool HardHints, SmallVector<MCPhysReg, 16> &&Storage)
-      : Hints(std::move(Hints)), ShuffledOrderStorage(std::move(Storage)),
-        Order(ShuffledOrderStorage.empty() ? Order : ShuffledOrderStorage),
-        IterationLimit(HardHints ? 0 : static_cast<int>(this->Order.size())) {}
-
-  Iterator begin() const {
-    return Iterator(*this, -(static_cast<int>(Hints.size())));
-  }
+  Iterator begin() const { return Iterator(*this, -NumHints); }
 
   Iterator end() const { return Iterator(*this, IterationLimit); }
 
@@ -126,7 +134,7 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
     assert(!Reg.isPhysical() ||
            Reg.id() <
                static_cast<uint32_t>(std::numeric_limits<MCPhysReg>::max()));
-    return Reg.isPhysical() && is_contained(Hints, Reg.id());
+    return Reg.isPhysical() && is_contained(hints(), Reg.id());
   }
 };
 
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index fd696297e35d9..44defb5e455a8 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -444,8 +444,8 @@ bool TargetRegisterInfo::getRegAllocationHints(
 }
 
 void TargetRegisterInfo::applyRegAllocationAntiHints(
-    Register VirtReg, ArrayRef<MCPhysReg> &Order,
-    SmallVectorImpl<MCPhysReg> &OrderStorage,
+    Register VirtReg, ArrayRef<MCPhysReg> Order,
+    SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
     SmallVectorImpl<MCPhysReg> &AntiHints, const MachineFunction &MF,
     const VirtRegMap *VRM, const LiveRegMatrix *Matrix) const {
 
@@ -458,29 +458,24 @@ void TargetRegisterInfo::applyRegAllocationAntiHints(
     });
   };
 
-  // Copy order into storage
-  OrderStorage.clear();
-  OrderStorage.assign(Order.begin(), Order.end());
+  HintsAndCustomOrder.truncate(NumHints);
+  HintsAndCustomOrder.append(Order.begin(), Order.end());
 
   // Partition non-anti-hinted register go first
-  auto PartionPoint =
-      std::stable_partition(OrderStorage.begin(), OrderStorage.end(),
-                            [&](MCPhysReg Reg) { return !isAntiHinted(Reg); });
-
-  Order = OrderStorage;
+  auto *PartitionPoint = std::stable_partition(
+      HintsAndCustomOrder.begin() + NumHints, HintsAndCustomOrder.end(),
+      [&](MCPhysReg Reg) { return !isAntiHinted(Reg); });
 
-  // print the details
   LLVM_DEBUG({
     size_t NonAntiHintedCount =
-        std::distance(OrderStorage.begin(), PartionPoint);
-    size_t AntiHintedCount = std::distance(PartionPoint, OrderStorage.end());
+        std::distance(HintsAndCustomOrder.begin() + NumHints, PartitionPoint);
+    size_t AntiHintedCount =
+        std::distance(PartitionPoint, HintsAndCustomOrder.end());
     dbgs() << "Added " << NonAntiHintedCount
            << " non-anti-hinted registers first\n"
            << "Added " << AntiHintedCount
            << " anti-hinted registers at the end\n";
   });
-
-  return;
 }
 
 bool TargetRegisterInfo::isCalleeSavedPhysReg(
diff --git a/llvm/unittests/CodeGen/AllocationOrderTest.cpp b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
index ec02579f55c58..aa636b6673b1e 100644
--- a/llvm/unittests/CodeGen/AllocationOrderTest.cpp
+++ b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
@@ -117,26 +117,23 @@ TEST(AllocationOrderTest, IsHintTest) {
   EXPECT_EQ(V, 5U);
 }
 
-TEST(AllocationOrderTest, StorageOverridesOrder) {
-  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+TEST(AllocationOrderTest, AntiHintShuffleOrderOverridesOrder) {
+  SmallVector<MCPhysReg, 16> HintsAndCustomOrder = {1, 2, 5, 3, 4};
   SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
-  SmallVector<MCPhysReg, 16> Storage = {5, 3, 4};
-  AllocationOrder O(std::move(Hints), Order, false, std::move(Storage));
+  AllocationOrder O(std::move(HintsAndCustomOrder), 2, Order, false);
   EXPECT_EQ((std::vector<MCPhysReg>{1, 2, 5, 3, 4}), loadOrder(O));
 }
 
-TEST(AllocationOrderTest, EmptyStorageFallsBackToOrder) {
-  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+TEST(AllocationOrderTest, EmptyAntiHintedCustomOrderFallsBackToOrder) {
+  SmallVector<MCPhysReg, 16> HintsAndCustomOrder = {1, 2};
   SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
-  SmallVector<MCPhysReg, 16> Storage;
-  AllocationOrder O(std::move(Hints), Order, false, std::move(Storage));
+  AllocationOrder O(std::move(HintsAndCustomOrder), 2, Order, false);
   EXPECT_EQ((std::vector<MCPhysReg>{1, 2, 3, 4, 5}), loadOrder(O));
 }
 
-TEST(AllocationOrderTest, StorageHardHints) {
-  SmallVector<MCPhysReg, 16> Hints = {1, 2};
+TEST(AllocationOrderTest, HardHintsIgnoreAntiHintShuffleOrder) {
+  SmallVector<MCPhysReg, 16> HintsAndCustomOrder = {1, 2, 5, 3, 4};
   SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
-  SmallVector<MCPhysReg, 16> Storage = {5, 3, 4};
-  AllocationOrder O(std::move(Hints), Order, true, std::move(Storage));
+  AllocationOrder O(std::move(HintsAndCustomOrder), 2, Order, true);
   EXPECT_EQ((std::vector<MCPhysReg>{1, 2}), loadOrder(O));
 }

>From 82e68bdd3c0dd3f2e24ad168103edb2f4ffbdbc0 Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Fri, 4 Sep 2026 22:29:10 -0500
Subject: [PATCH 4/5] Addressed review and added target overrideable
 filterAndSort

---
 .../llvm/CodeGen/MachineRegisterInfo.h        |  9 ++--
 .../include/llvm/CodeGen/TargetRegisterInfo.h | 15 +++++--
 llvm/lib/CodeGen/AllocationOrder.cpp          | 30 +++++++------
 llvm/lib/CodeGen/AllocationOrder.h            | 10 ++---
 llvm/lib/CodeGen/MachineRegisterInfo.cpp      | 26 ++++++------
 llvm/lib/CodeGen/TargetRegisterInfo.cpp       | 42 ++++++++++++-------
 .../unittests/CodeGen/AllocationOrderTest.cpp |  4 +-
 7 files changed, 81 insertions(+), 55 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
index 890355febbb28..69d14fd11507f 100644
--- a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
@@ -922,7 +922,7 @@ class MachineRegisterInfo {
            "Anti-hints and anti-hint targets are only for virtual registers");
     AntiHintRegs.grow(VReg);
     SmallVector<Register, 4> &AntiHints = AntiHintRegs[VReg];
-    // Avoid duplicates
+    // Avoid duplicates.
     if (!is_contained(AntiHints, AntiHintVReg))
       AntiHints.push_back(AntiHintVReg);
   }
@@ -959,11 +959,10 @@ class MachineRegisterInfo {
     return is_contained(AntiHints, AntiHintVReg);
   }
 
-  /// Get the set of physical registers to avoid.
+  /// Get the BitVector of register units to avoid in anti-hints.
   /// VRM is the current virtual register map showing allocations made so far.
-  void getPhysRegAntiHints(Register VReg,
-                           SmallVectorImpl<MCPhysReg> &PhysAntiHints,
-                           const VirtRegMap &VRM) const;
+  void getBitVecRegAntiHints(Register VReg, BitVector &AntiHintedRegUnits,
+                             const VirtRegMap &VRM) const;
 
   /// markUsesInDebugValueAsUndef - Mark every DBG_VALUE referencing the
   /// specified register as undefined which causes the DBG_VALUE to be
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index bdb2a4d0363b5..9de9e644effda 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -852,12 +852,21 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
     // Do nothing.
   }
 
+  /// Return true if Reg overlaps one of the anti-hinted register units.
+  bool isAntiHintedReg(MCPhysReg Reg,
+                       const BitVector &AntiHintedRegUnits) const;
+
   /// Apply anti-hints to the allocation order.
-  virtual void applyRegAllocationAntiHints(
+  void applyRegAllocationAntiHints(
       Register VirtReg, ArrayRef<MCPhysReg> Order,
       SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
-      SmallVectorImpl<MCPhysReg> &AntiHints, const MachineFunction &MF,
-      const VirtRegMap *VRM = nullptr,
+      const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
+      const LiveRegMatrix *Matrix = nullptr) const;
+
+  /// Custom reordering of the allocation order.
+  virtual void filterAndSortForAntiHintedRegs(
+      Register VirtReg, MutableArrayRef<MCPhysReg> CustomOrder,
+      const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
       const LiveRegMatrix *Matrix = nullptr) const;
 
   /// Allow the target to reverse allocation order of local live ranges. This
diff --git a/llvm/lib/CodeGen/AllocationOrder.cpp b/llvm/lib/CodeGen/AllocationOrder.cpp
index 2367095ce23df..ac4485c849a00 100644
--- a/llvm/lib/CodeGen/AllocationOrder.cpp
+++ b/llvm/lib/CodeGen/AllocationOrder.cpp
@@ -15,6 +15,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "AllocationOrder.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/RegisterClassInfo.h"
@@ -35,15 +36,16 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   auto Order = RegClassInfo.getOrder(MF.getRegInfo().getRegClass(VirtReg));
 
-  // HintsAndCustomOrder holds Hints first followed by the shuffled order if the
-  // anti-hints shuffle it.
+  // HintsAndCustomOrder holds Hints first followed by the custom order if the
+  // anti-hints reorders it.
   SmallVector<MCPhysReg, 16> HintsAndCustomOrder;
 
-  // Get hints
+  // Get Hints.
   bool HardHints = TRI->getRegAllocationHints(
       VirtReg, Order, HintsAndCustomOrder, MF, &VRM, Matrix);
   const int NumHints = static_cast<int>(HintsAndCustomOrder.size());
 
+  // HintsAndCustomOrder only holds Hints (custom order is not added yet).
   LLVM_DEBUG({
     if (NumHints) {
       dbgs() << "hints:";
@@ -53,27 +55,29 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
     }
   });
 
-  // Get anti-hints
-  SmallVector<MCPhysReg, 16> AntiHintedPhysRegs;
-  MRI.getPhysRegAntiHints(VirtReg, AntiHintedPhysRegs, VRM);
+  // Get anti-hints.
+  BitVector AntiHintedRegUnits;
+  MRI.getBitVecRegAntiHints(VirtReg, AntiHintedRegUnits, VRM);
 
   LLVM_DEBUG({
-    if (!AntiHintedPhysRegs.empty()) {
+    if (AntiHintedRegUnits.any()) {
       dbgs() << "anti-hints:";
-      for (MCPhysReg AntiHint : AntiHintedPhysRegs)
-        dbgs() << ' ' << printReg(AntiHint, TRI);
+      for (Register AntiHintVReg : MRI.getRegAllocationAntiHints(VirtReg)) {
+        if (!VRM.hasPhys(AntiHintVReg))
+          continue;
+        dbgs() << ' ' << printReg(VRM.getPhys(AntiHintVReg), TRI);
+      }
       dbgs() << '\n';
     }
   });
 
-  if (!AntiHintedPhysRegs.empty()) {
+  if (AntiHintedRegUnits.any()) {
     HintsAndCustomOrder.reserve(NumHints + Order.size());
     TRI->applyRegAllocationAntiHints(VirtReg, Order, HintsAndCustomOrder,
-                                     NumHints, AntiHintedPhysRegs, MF, &VRM,
-                                     Matrix);
+                                     NumHints, AntiHintedRegUnits, MF, Matrix);
   }
 
-  // Create allocation order object
+  // Create allocation order object.
   AllocationOrder AO(std::move(HintsAndCustomOrder), NumHints, Order,
                      HardHints);
 
diff --git a/llvm/lib/CodeGen/AllocationOrder.h b/llvm/lib/CodeGen/AllocationOrder.h
index 643c927103802..09d8fd68de17b 100644
--- a/llvm/lib/CodeGen/AllocationOrder.h
+++ b/llvm/lib/CodeGen/AllocationOrder.h
@@ -29,9 +29,9 @@ class VirtRegMap;
 class LiveRegMatrix;
 
 class LLVM_LIBRARY_VISIBILITY AllocationOrder {
-  // The Hints occupy [0, NumHints). If the Order received in the constructor
-  // needed to be shuffled, the shuffled copy is stored right after them, at
-  // [NumHints, end).
+  // Used as storage for both Hints and CustomOrder if the Order received in the
+  // constructor needs to be altered. [0, NumHints) contains regular hints. If a
+  // custom order is present, [NumHints, end) contains the custom order.
   const SmallVector<MCPhysReg, 16> HintsAndCustomOrder;
   const int NumHints;
   ArrayRef<MCPhysReg> Order;
@@ -95,8 +95,8 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
                                 const LiveRegMatrix *Matrix);
 
   /// Create an AllocationOrder from HintsAndCustomOrder that contains NumHints
-  /// Hints optionally followed by a reordered Order. If no reordered copy is
-  /// present use Order as-is.
+  /// Hints optionally followed by a custom order. When that custom order is
+  /// present it becomes the allocation order otherwise Order is used as-is.
   AllocationOrder(SmallVector<MCPhysReg, 16> &&HintsAndCustomOrder,
                   int NumHints, ArrayRef<MCPhysReg> Order, bool HardHints)
       : HintsAndCustomOrder(std::move(HintsAndCustomOrder)), NumHints(NumHints),
diff --git a/llvm/lib/CodeGen/MachineRegisterInfo.cpp b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
index 3918c169b978c..61fae6d3fa281 100644
--- a/llvm/lib/CodeGen/MachineRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
@@ -718,21 +718,23 @@ void MachineRegisterInfo::updateDbgUsersToReg(
   }
 }
 
-void MachineRegisterInfo::getPhysRegAntiHints(
-    Register VReg, SmallVectorImpl<MCPhysReg> &PhysAntiHints,
-    const VirtRegMap &VRM) const {
+void MachineRegisterInfo::getBitVecRegAntiHints(Register VReg,
+                                                BitVector &AntiHintedRegUnits,
+                                                const VirtRegMap &VRM) const {
   assert(VReg.isVirtual() && "Anti-hints are only for virtual registers");
   if (!AntiHintRegs.inBounds(VReg))
     return;
 
-  const SmallVector<Register, 4> &AntiHints = AntiHintRegs[VReg];
-
-  for (Register AntiHintVReg : AntiHints) {
-    // Check if the anti-hinted register has been allocated
-    if (VRM.hasPhys(AntiHintVReg)) {
-      MCPhysReg PhysReg = VRM.getPhys(AntiHintVReg);
-      if (!is_contained(PhysAntiHints, PhysReg))
-        PhysAntiHints.push_back(PhysReg);
-    }
+  auto *TRI = getTargetRegisterInfo();
+  for (Register AntiHintVReg : AntiHintRegs[VReg]) {
+    // Check if the anti-hinted register has been allocated.
+    if (!VRM.hasPhys(AntiHintVReg))
+      continue;
+    // Delay until first allocated anti-hinted register so unused cases keep
+    // default empty BitVector.
+    if (AntiHintedRegUnits.empty())
+      AntiHintedRegUnits.resize(TRI->getNumRegUnits());
+    for (MCRegUnit Unit : TRI->regunits(VRM.getPhys(AntiHintVReg)))
+      AntiHintedRegUnits.set(static_cast<unsigned>(Unit));
   }
 }
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index 44defb5e455a8..f6ec5c9ac46e0 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -443,34 +443,46 @@ bool TargetRegisterInfo::getRegAllocationHints(
   return false;
 }
 
+bool TargetRegisterInfo::isAntiHintedReg(
+    MCPhysReg Reg, const BitVector &AntiHintedRegUnits) const {
+  return llvm::any_of(regunits(Reg), [&](MCRegUnit Unit) {
+    return AntiHintedRegUnits.test(static_cast<unsigned>(Unit));
+  });
+}
+
 void TargetRegisterInfo::applyRegAllocationAntiHints(
     Register VirtReg, ArrayRef<MCPhysReg> Order,
     SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
-    SmallVectorImpl<MCPhysReg> &AntiHints, const MachineFunction &MF,
-    const VirtRegMap *VRM, const LiveRegMatrix *Matrix) const {
+    const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
+    const LiveRegMatrix *Matrix) const {
 
-  if (AntiHints.empty() || !VRM)
+  if (AntiHintedRegUnits.none())
     return;
 
-  auto isAntiHinted = [&](MCPhysReg Reg) {
-    return llvm::any_of(AntiHints, [&](MCPhysReg AntiHint) {
-      return regsOverlap(Reg, AntiHint);
-    });
-  };
-
   HintsAndCustomOrder.truncate(NumHints);
   HintsAndCustomOrder.append(Order.begin(), Order.end());
 
-  // Partition non-anti-hinted register go first
+  // Custom reordering of the allocation order.
+  filterAndSortForAntiHintedRegs(
+      VirtReg,
+      MutableArrayRef<MCPhysReg>(HintsAndCustomOrder).drop_front(NumHints),
+      AntiHintedRegUnits, MF, Matrix);
+}
+
+void TargetRegisterInfo::filterAndSortForAntiHintedRegs(
+    Register VirtReg, MutableArrayRef<MCPhysReg> CustomOrder,
+    const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
+    const LiveRegMatrix *Matrix) const {
+
+  // Partition non-anti-hinted register go first.
   auto *PartitionPoint = std::stable_partition(
-      HintsAndCustomOrder.begin() + NumHints, HintsAndCustomOrder.end(),
-      [&](MCPhysReg Reg) { return !isAntiHinted(Reg); });
+      CustomOrder.begin(), CustomOrder.end(),
+      [&](MCPhysReg Reg) { return !isAntiHintedReg(Reg, AntiHintedRegUnits); });
 
   LLVM_DEBUG({
     size_t NonAntiHintedCount =
-        std::distance(HintsAndCustomOrder.begin() + NumHints, PartitionPoint);
-    size_t AntiHintedCount =
-        std::distance(PartitionPoint, HintsAndCustomOrder.end());
+        std::distance(CustomOrder.begin(), PartitionPoint);
+    size_t AntiHintedCount = std::distance(PartitionPoint, CustomOrder.end());
     dbgs() << "Added " << NonAntiHintedCount
            << " non-anti-hinted registers first\n"
            << "Added " << AntiHintedCount
diff --git a/llvm/unittests/CodeGen/AllocationOrderTest.cpp b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
index aa636b6673b1e..5346d1b1863aa 100644
--- a/llvm/unittests/CodeGen/AllocationOrderTest.cpp
+++ b/llvm/unittests/CodeGen/AllocationOrderTest.cpp
@@ -117,7 +117,7 @@ TEST(AllocationOrderTest, IsHintTest) {
   EXPECT_EQ(V, 5U);
 }
 
-TEST(AllocationOrderTest, AntiHintShuffleOrderOverridesOrder) {
+TEST(AllocationOrderTest, AntiHintCustomOrderOverridesOrder) {
   SmallVector<MCPhysReg, 16> HintsAndCustomOrder = {1, 2, 5, 3, 4};
   SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
   AllocationOrder O(std::move(HintsAndCustomOrder), 2, Order, false);
@@ -131,7 +131,7 @@ TEST(AllocationOrderTest, EmptyAntiHintedCustomOrderFallsBackToOrder) {
   EXPECT_EQ((std::vector<MCPhysReg>{1, 2, 3, 4, 5}), loadOrder(O));
 }
 
-TEST(AllocationOrderTest, HardHintsIgnoreAntiHintShuffleOrder) {
+TEST(AllocationOrderTest, HardHintsIgnoreAntiHintCustomOrder) {
   SmallVector<MCPhysReg, 16> HintsAndCustomOrder = {1, 2, 5, 3, 4};
   SmallVector<MCPhysReg, 16> Order = {3, 4, 5};
   AllocationOrder O(std::move(HintsAndCustomOrder), 2, Order, true);

>From 22cdb36c98424b4bde30e6ff70ab9907ea0f035a Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Sat, 12 Sep 2026 13:34:40 -0500
Subject: [PATCH 5/5] Addressed review

---
 llvm/include/llvm/CodeGen/TargetRegisterInfo.h | 7 +++++--
 llvm/lib/CodeGen/AllocationOrder.cpp           | 3 ++-
 llvm/lib/CodeGen/AllocationOrder.h             | 5 +++++
 llvm/lib/CodeGen/RegAllocGreedy.cpp            | 5 ++++-
 llvm/lib/CodeGen/TargetRegisterInfo.cpp        | 6 +++---
 5 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 9de9e644effda..182a8984bae4d 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -39,6 +39,7 @@ class DIExpression;
 class LiveRegMatrix;
 class MachineFunction;
 class MachineInstr;
+class RegisterClassInfo;
 class RegScavenger;
 class VirtRegMap;
 class LiveIntervals;
@@ -861,13 +862,15 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
       Register VirtReg, ArrayRef<MCPhysReg> Order,
       SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
       const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
-      const LiveRegMatrix *Matrix = nullptr) const;
+      const LiveRegMatrix *Matrix = nullptr,
+      const RegisterClassInfo *RegClassInfo = nullptr) const;
 
   /// Custom reordering of the allocation order.
   virtual void filterAndSortForAntiHintedRegs(
       Register VirtReg, MutableArrayRef<MCPhysReg> CustomOrder,
       const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
-      const LiveRegMatrix *Matrix = nullptr) const;
+      const LiveRegMatrix *Matrix = nullptr,
+      const RegisterClassInfo *RegClassInfo = nullptr) const;
 
   /// Allow the target to reverse allocation order of local live ranges. This
   /// will generally allocate shorter local live ranges first. For targets with
diff --git a/llvm/lib/CodeGen/AllocationOrder.cpp b/llvm/lib/CodeGen/AllocationOrder.cpp
index ac4485c849a00..705fcef23030b 100644
--- a/llvm/lib/CodeGen/AllocationOrder.cpp
+++ b/llvm/lib/CodeGen/AllocationOrder.cpp
@@ -74,7 +74,8 @@ AllocationOrder AllocationOrder::create(Register VirtReg, const VirtRegMap &VRM,
   if (AntiHintedRegUnits.any()) {
     HintsAndCustomOrder.reserve(NumHints + Order.size());
     TRI->applyRegAllocationAntiHints(VirtReg, Order, HintsAndCustomOrder,
-                                     NumHints, AntiHintedRegUnits, MF, Matrix);
+                                     NumHints, AntiHintedRegUnits, MF, Matrix,
+                                     &RegClassInfo);
   }
 
   // Create allocation order object.
diff --git a/llvm/lib/CodeGen/AllocationOrder.h b/llvm/lib/CodeGen/AllocationOrder.h
index 09d8fd68de17b..7c61c01d9ea59 100644
--- a/llvm/lib/CodeGen/AllocationOrder.h
+++ b/llvm/lib/CodeGen/AllocationOrder.h
@@ -129,6 +129,11 @@ class LLVM_LIBRARY_VISIBILITY AllocationOrder {
   /// Get the allocation order without reordered hints.
   ArrayRef<MCPhysReg> getOrder() const { return Order; }
 
+  /// Return true if a custom order replaced the RegisterClassInfo order.
+  bool hasCustomOrder() const {
+    return static_cast<int>(HintsAndCustomOrder.size()) > NumHints;
+  }
+
   /// Return true if Reg is a preferred physical register.
   bool isHint(Register Reg) const {
     assert(!Reg.isPhysical() ||
diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp
index fc28b229dcddc..42de9fc7f6f75 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -683,7 +683,10 @@ RegAllocEvictionAdvisor::getOrderLimit(const LiveInterval &VirtReg,
 
     // It is normal for register classes to have a long tail of registers with
     // the same cost. We don't need to look at them if they're too expensive.
-    if (RegCosts[Order.getOrder().back()] >= CostPerUseLimit) {
+    // LastCostChange is an index into the original RegisterClassInfo order, so
+    // it cannot be used to shorten a custom order.
+    if (!Order.hasCustomOrder() &&
+        RegCosts[Order.getOrder().back()] >= CostPerUseLimit) {
       OrderLimit = RegClassInfo.getLastCostChange(RC);
       LLVM_DEBUG(dbgs() << "Only trying the first " << OrderLimit
                         << " regs.\n");
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index f6ec5c9ac46e0..7db9732213ed5 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -454,7 +454,7 @@ void TargetRegisterInfo::applyRegAllocationAntiHints(
     Register VirtReg, ArrayRef<MCPhysReg> Order,
     SmallVectorImpl<MCPhysReg> &HintsAndCustomOrder, unsigned NumHints,
     const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
-    const LiveRegMatrix *Matrix) const {
+    const LiveRegMatrix *Matrix, const RegisterClassInfo *RegClassInfo) const {
 
   if (AntiHintedRegUnits.none())
     return;
@@ -466,13 +466,13 @@ void TargetRegisterInfo::applyRegAllocationAntiHints(
   filterAndSortForAntiHintedRegs(
       VirtReg,
       MutableArrayRef<MCPhysReg>(HintsAndCustomOrder).drop_front(NumHints),
-      AntiHintedRegUnits, MF, Matrix);
+      AntiHintedRegUnits, MF, Matrix, RegClassInfo);
 }
 
 void TargetRegisterInfo::filterAndSortForAntiHintedRegs(
     Register VirtReg, MutableArrayRef<MCPhysReg> CustomOrder,
     const BitVector &AntiHintedRegUnits, const MachineFunction &MF,
-    const LiveRegMatrix *Matrix) const {
+    const LiveRegMatrix *Matrix, const RegisterClassInfo *RegClassInfo) const {
 
   // Partition non-anti-hinted register go first.
   auto *PartitionPoint = std::stable_partition(



More information about the llvm-commits mailing list