[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