[llvm] [AArch64] Avoid getMinimalPhysRegClass in callee-save frame lowering (PR #193438)
Cullen Rhodes via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 27 22:56:47 PDT 2026
https://github.com/c-rhodes updated https://github.com/llvm/llvm-project/pull/193438
>From 9a4b2befdd2525ac92ae21139b5d96787ca688a6 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Wed, 22 Apr 2026 07:19:31 +0000
Subject: [PATCH 1/2] [AArch64] Avoid getMinimalPhysRegClass in callee-save
frame lowering
getMinimalPhysRegClass is slow and the callee-save paths in frame
lowering that call it are hot. Which registers are callee-saved is
well-defined, selecting the register classes directly is a -0.22%
geomean improvement on stage1-aarch64-O0-g CTMark.
---
.../Target/AArch64/AArch64FrameLowering.cpp | 22 ++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 2c68e379205ce..012857356b033 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -345,6 +345,23 @@ static unsigned getStackHazardSize(const MachineFunction &MF) {
return MF.getSubtarget<AArch64Subtarget>().getStreamingHazardSize();
}
+static const TargetRegisterClass *
+getAArch64CalleeSavedRegClass(MCRegister Reg) {
+ if (AArch64::GPR64RegClass.contains(Reg))
+ return &AArch64::GPR64RegClass;
+ if (AArch64::FPR64RegClass.contains(Reg))
+ return &AArch64::FPR64RegClass;
+ if (AArch64::FPR128RegClass.contains(Reg))
+ return &AArch64::FPR128RegClass;
+ if (AArch64::ZPRRegClass.contains(Reg))
+ return &AArch64::ZPRRegClass;
+ if (AArch64::PPRRegClass.contains(Reg))
+ return &AArch64::PPRRegClass;
+ if (Reg == AArch64::VG)
+ return &AArch64::FIXED_REGSRegClass;
+ llvm_unreachable("Unsupported register class.");
+}
+
StackOffset
AArch64FrameLowering::getZPRStackSize(const MachineFunction &MF) const {
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
@@ -2623,8 +2640,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
unsigned PPRCSStackSize = 0;
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
for (unsigned Reg : SavedRegs.set_bits()) {
- auto *RC = TRI->getMinimalPhysRegClass(MCRegister(Reg));
- assert(RC && "expected register class!");
+ auto *RC = getAArch64CalleeSavedRegClass(MCRegister(Reg));
auto SpillSize = TRI->getSpillSize(*RC);
bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
@@ -2804,7 +2820,7 @@ bool AArch64FrameLowering::assignCalleeSavedSpillSlots(
int HazardSlotIndex = std::numeric_limits<int>::max();
for (auto &CS : CSI) {
MCRegister Reg = CS.getReg();
- const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
+ const TargetRegisterClass *RC = getAArch64CalleeSavedRegClass(Reg);
// Create a hazard slot as we switch between GPR and FPR CSRs.
if (AFI->isStackHazardIncludedInCalleeSaveArea() &&
>From 2038fc376d322e7c10dd908d823c95db211098dc Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Mon, 27 Apr 2026 19:18:38 +0000
Subject: [PATCH 2/2] address comments
---
.../Target/AArch64/AArch64FrameLowering.cpp | 22 +++----------------
.../lib/Target/AArch64/AArch64RegisterInfo.td | 15 ++++++++++++-
2 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 012857356b033..5a1ff324f948f 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -345,23 +345,6 @@ static unsigned getStackHazardSize(const MachineFunction &MF) {
return MF.getSubtarget<AArch64Subtarget>().getStreamingHazardSize();
}
-static const TargetRegisterClass *
-getAArch64CalleeSavedRegClass(MCRegister Reg) {
- if (AArch64::GPR64RegClass.contains(Reg))
- return &AArch64::GPR64RegClass;
- if (AArch64::FPR64RegClass.contains(Reg))
- return &AArch64::FPR64RegClass;
- if (AArch64::FPR128RegClass.contains(Reg))
- return &AArch64::FPR128RegClass;
- if (AArch64::ZPRRegClass.contains(Reg))
- return &AArch64::ZPRRegClass;
- if (AArch64::PPRRegClass.contains(Reg))
- return &AArch64::PPRRegClass;
- if (Reg == AArch64::VG)
- return &AArch64::FIXED_REGSRegClass;
- llvm_unreachable("Unsupported register class.");
-}
-
StackOffset
AArch64FrameLowering::getZPRStackSize(const MachineFunction &MF) const {
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
@@ -2640,7 +2623,8 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
unsigned PPRCSStackSize = 0;
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
for (unsigned Reg : SavedRegs.set_bits()) {
- auto *RC = getAArch64CalleeSavedRegClass(MCRegister(Reg));
+ auto *RC = TRI->getPhysRegBaseClass(MCRegister(Reg));
+ assert(RC && "expected register class!");
auto SpillSize = TRI->getSpillSize(*RC);
bool IsZPR = AArch64::ZPRRegClass.contains(Reg);
bool IsPPR = !IsZPR && AArch64::PPRRegClass.contains(Reg);
@@ -2820,7 +2804,7 @@ bool AArch64FrameLowering::assignCalleeSavedSpillSlots(
int HazardSlotIndex = std::numeric_limits<int>::max();
for (auto &CS : CSI) {
MCRegister Reg = CS.getReg();
- const TargetRegisterClass *RC = getAArch64CalleeSavedRegClass(Reg);
+ const TargetRegisterClass *RC = RegInfo->getPhysRegBaseClass(Reg);
// Create a hazard slot as we switch between GPR and FPR CSRs.
if (AFI->isStackHazardIncludedInCalleeSaveArea() &&
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index cd94a2590c6d2..d2f03bac88917 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -202,11 +202,13 @@ def GPR64common : RegisterClass<"AArch64", [i64], 64,
def GPR32 : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WZR)> {
let AltOrders = [(rotl GPR32, 8)];
let AltOrderSelect = [{ return 1; }];
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::GPR32RegClassID, 0, 32>";
}
def GPR64 : RegisterClass<"AArch64", [i64], 64, (add GPR64common, XZR)> {
let AltOrders = [(rotl GPR64, 8)];
let AltOrderSelect = [{ return 1; }];
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::GPR64RegClassID, 0, 32>";
}
@@ -214,11 +216,13 @@ def GPR64 : RegisterClass<"AArch64", [i64], 64, (add GPR64common, XZR)> {
def GPR32sp : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WSP)> {
let AltOrders = [(rotl GPR32sp, 8)];
let AltOrderSelect = [{ return 1; }];
+ let BaseClassOrder = 1;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::GPR32spRegClassID, 0, 32>";
}
def GPR64sp : RegisterClass<"AArch64", [i64], 64, (add GPR64common, SP)> {
let AltOrders = [(rotl GPR64sp, 8)];
let AltOrderSelect = [{ return 1; }];
+ let BaseClassOrder = 1;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::GPR64spRegClassID,0, 32>";
}
@@ -500,10 +504,12 @@ def Q31 : AArch64Reg<31, "q31", [D31, D31_HI], ["v31", ""]>, DwarfRegAlias<B31
def FPR8 : RegisterClass<"AArch64", [i8, aarch64mfp8], 8, (sequence "B%u", 0, 31)> {
let Size = 8;
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::FPR8RegClassID, 0, 32>";
}
def FPR16 : RegisterClass<"AArch64", [f16, bf16, i16], 16, (sequence "H%u", 0, 31)> {
let Size = 16;
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::FPR16RegClassID, 0, 32>";
}
@@ -511,11 +517,13 @@ def FPR16_lo : RegisterClass<"AArch64", [f16], 16, (trunc FPR16, 16)> {
let Size = 16;
}
def FPR32 : RegisterClass<"AArch64", [f32, i32], 32,(sequence "S%u", 0, 31)> {
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::FPR32RegClassID, 0, 32>";
}
def FPR64 : RegisterClass<"AArch64", [f64, i64, v2f32, v1f64, v8i8, v4i16, v2i32,
v1i64, v4f16, v4bf16],
64, (sequence "D%u", 0, 31)> {
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::FPR64RegClassID, 0, 32>";
}
def FPR64_lo : RegisterClass<"AArch64",
@@ -530,6 +538,7 @@ def FPR128 : RegisterClass<"AArch64",
[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64, f128,
v8f16, v8bf16],
128, (sequence "Q%u", 0, 31)> {
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::FPR128RegClassID, 0, 32>";
}
@@ -987,6 +996,7 @@ class PPRClass<int firstreg, int lastreg, int step = 1> : RegisterClass<"AArch64
}
def PPR : PPRClass<0, 15> {
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::PPRRegClassID, 0, 16>";
}
def PPR_3b : PPRClass<0, 7> { // Restricted 3 bit SVE predicate register class.
@@ -1190,6 +1200,7 @@ def ZPRMul2_Lo : ZPRClass<0, 14, 2>;
def ZPRMul2_Hi : ZPRClass<16, 30, 2>;
def ZPR : ZPRClass<0, 31> {
+ let BaseClassOrder = 0;
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPRRegClassID, 0, 32>";
}
def ZPR_4b : ZPRClass<0, 15> { // Restricted 4 bit SVE vector register class.
@@ -2010,5 +2021,7 @@ let isAllocatable = 0, GeneratePressureSet = 0 in {
def GeneralPurposeRegisters : RegisterCategory<[GPR64, GPR32]>;
-def FIXED_REGS : RegisterClass<"AArch64", [i64], 64, (add FP, SP, VG, FFR)>;
+def FIXED_REGS : RegisterClass<"AArch64", [i64], 64, (add FP, SP, VG, FFR)> {
+ let BaseClassOrder = 2;
+}
def FixedRegisters : RegisterCategory<[CCR, FIXED_REGS]>;
More information about the llvm-commits
mailing list