[llvm] d7610f8 - [CodeGen] Avoid querying allocation order for every CSR alias (#215752)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 22:54:24 PDT 2026


Author: Cullen Rhodes
Date: 2026-08-13T06:54:19+01:00
New Revision: d7610f85ac4a9ea80eaefcd81c407670e58851b3

URL: https://github.com/llvm/llvm-project/commit/d7610f85ac4a9ea80eaefcd81c407670e58851b3
DIFF: https://github.com/llvm/llvm-project/commit/d7610f85ac4a9ea80eaefcd81c407670e58851b3.diff

LOG: [CodeGen] Avoid querying allocation order for every CSR alias (#215752)

Profiling tramp3d-v4 on aarch64-O0-g shows ~0.30% of compile-time is
spent in RegisterClassInfo::runOnMachineFunction.

It currently walks every alias of every callee-saved register for every
MachineFunction, doing a virtual call to ignoreCSRForAllocationOrder for
each alias. ARM is the only target that overrides this hook; all other
targets construct a full-sized BitVector and perform the alias traversal
only to fill it with zeroes.

Replace the per-register hook with a target-populated mask. Most targets
leave the mask empty, avoiding the allocation and alias traversal. The
mask is also only consulted after getLastCalleeSavedAlias confirms the
physical register aliases a CSR, so ARM can populate all GPR bits
directly without rediscovering the CSR aliases.

Improves CTMark geomean by -0.10%, with tramp3d-v4 -0.34%.

https://llvm-compile-time-tracker.com/compare.php?from=9c7ba7b1d12ed3f395a2317c525a98e5bfcf28e9&to=c80013a2d8e968eeeb23280663e73c86e7e5616f&stat=instructions%3Au

Assisted-by: codex

Added: 
    

Modified: 
    llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
    llvm/lib/CodeGen/RegisterClassInfo.cpp
    llvm/lib/Target/ARM/ARMSubtarget.cpp
    llvm/lib/Target/ARM/ARMSubtarget.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index a50f7f804b03d..60b30dda421d5 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -31,6 +31,7 @@
 namespace llvm {
 
 class APInt;
+class BitVector;
 class MachineFunction;
 class ScheduleDAGMutation;
 class CallLowering;
@@ -353,13 +354,12 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   /// This is called after a .mir file was loaded.
   virtual void mirFileLoaded(MachineFunction &MF) const;
 
-  /// True if the register allocator should use the allocation orders exactly as
-  /// written in the tablegen descriptions, false if it should allocate
-  /// the specified physical register later if is it callee-saved.
-  virtual bool ignoreCSRForAllocationOrder(const MachineFunction &MF,
-                                           MCRegister PhysReg) const {
-    return false;
-  }
+  /// Constructs a Mask of physical registers whose allocation orders should be
+  /// used exactly as written in the TableGen descriptions, rather than
+  /// allocating them later if they are callee-saved. Mask is empty on entry
+  /// and must either remain empty or cover all physical registers.
+  virtual void getCSRAllocationOrderMask(const MachineFunction &MF,
+                                         BitVector &Mask) const {}
 
   /// Classify a global function reference. This mainly used to fetch target
   /// special flags for lowering a function address. For example mark a function

diff  --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp
index f4b9e8d9b1704..4b011001aa6ce 100644
--- a/llvm/lib/CodeGen/RegisterClassInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp
@@ -94,12 +94,9 @@ void RegisterClassInfo::runOnMachineFunction(const MachineFunction &mf,
   }
 
   // Even if CSR list is same, we could have had a 
diff erent allocation order
-  // if ignoreCSRForAllocationOrder is evaluated 
diff erently.
-  BitVector CSRHintsForAllocOrder(TRI->getNumRegs());
-  for (const MCPhysReg *I = CSR; *I; ++I)
-    for (MCRegAliasIterator AI(*I, TRI, true); AI.isValid(); ++AI)
-      CSRHintsForAllocOrder[(*AI).id()] =
-          STI.ignoreCSRForAllocationOrder(mf, *AI);
+  // if the target's CSR allocation-order mask changes.
+  BitVector CSRHintsForAllocOrder;
+  STI.getCSRAllocationOrderMask(mf, CSRHintsForAllocOrder);
   if (IgnoreCSRForAllocOrder != CSRHintsForAllocOrder) {
     Update = true;
     IgnoreCSRForAllocOrder = std::move(CSRHintsForAllocOrder);
@@ -129,7 +126,6 @@ void RegisterClassInfo::runOnMachineFunction(const MachineFunction &mf,
 void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
   assert(RC && "no register class given");
   RCInfo &RCI = RegClass[RC->getID()];
-  auto &STI = MF->getSubtarget();
 
   // Raw register count, including all reserved regs.
   unsigned NumRegs = RC->getNumRegs();
@@ -154,7 +150,8 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
     MinCost = std::min(MinCost, Cost);
 
     if (getLastCalleeSavedAlias(PhysReg) &&
-        !STI.ignoreCSRForAllocationOrder(*MF, PhysReg))
+        (IgnoreCSRForAllocOrder.empty() ||
+         !IgnoreCSRForAllocOrder.test(PhysReg)))
       // PhysReg aliases a CSR, save it for later.
       CSRAlias.push_back(PhysReg);
     else {

diff  --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp
index dc2e0622174d9..fd09ac1050f80 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.cpp
+++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp
@@ -23,6 +23,7 @@
 #include "Thumb1FrameLowering.h"
 #include "Thumb1InstrInfo.h"
 #include "Thumb2InstrInfo.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
@@ -569,7 +570,7 @@ unsigned ARMSubtarget::getGPRAllocationOrder(const MachineFunction &MF) const {
     return 2;
 
   // Allocate low registers first, so we can select more 16-bit instructions.
-  // We also (in ignoreCSRForAllocationOrder) override  the default behaviour
+  // We also (in getCSRAllocationOrderMask) override  the default behaviour
   // with regards to callee-saved registers, because pushing extra registers is
   // much cheaper (in terms of code size) than using high registers. After
   // that, we allocate r12 (doesn't need to be saved), lr (saving it means we
@@ -583,15 +584,19 @@ unsigned ARMSubtarget::getGPRAllocationOrder(const MachineFunction &MF) const {
   return 1;
 }
 
-bool ARMSubtarget::ignoreCSRForAllocationOrder(const MachineFunction &MF,
-                                               MCRegister PhysReg) const {
+void ARMSubtarget::getCSRAllocationOrderMask(const MachineFunction &MF,
+                                             BitVector &Mask) const {
   // To minimize code size in Thumb2, we prefer the usage of low regs (lower
   // cost per use) so we can  use narrow encoding. By default, caller-saved
   // registers (e.g. lr, r12) are always  allocated first, regardless of
   // their cost per use. When optForMinSize, we prefer the low regs even if
   // they are CSR because usually push/pop can be folded into existing ones.
-  return isThumb2() && MF.getFunction().hasMinSize() &&
-         ARM::GPRRegClass.contains(PhysReg);
+  if (!isThumb2() || !MF.getFunction().hasMinSize())
+    return;
+
+  Mask.resize(getRegisterInfo()->getNumRegs());
+  for (MCPhysReg Reg : ARM::GPRRegClass)
+    Mask.set(Reg);
 }
 
 ARMSubtarget::PushPopSplitVariation

diff  --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h
index f41be8308b3d4..d60b41c1b8324 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.h
+++ b/llvm/lib/Target/ARM/ARMSubtarget.h
@@ -510,8 +510,8 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
     return MVEVectorCostFactor;
   }
 
-  bool ignoreCSRForAllocationOrder(const MachineFunction &MF,
-                                   MCRegister PhysReg) const override;
+  void getCSRAllocationOrderMask(const MachineFunction &MF,
+                                 BitVector &Mask) const override;
   unsigned getGPRAllocationOrder(const MachineFunction &MF) const;
 };
 


        


More information about the llvm-commits mailing list