[llvm] [AArch64] Stop reserved registers from being saved in prolog/epilog (PR #138448)

via llvm-commits llvm-commits at lists.llvm.org
Sun May 4 08:04:17 PDT 2025


https://github.com/yasuna-oribe updated https://github.com/llvm/llvm-project/pull/138448

>From 40dafea81469f94dc05ec932735dedf6be1bf7cc Mon Sep 17 00:00:00 2001
From: oribe yasuna <or at dmc.chat>
Date: Sun, 4 May 2025 10:35:35 +0000
Subject: [PATCH] [AArch64] Stop manually reserved registers from being saved
 in prolog/epilog

GCC's man page is clear on how -ffixed-reg must behave:
```
  Treat the register named reg as a fixed register; generated
  code should never refer to it (except perhaps as a stack pointer,
  frame pointer or in some other fixed role).
```

This implies prolog/epilog code also must not save/restore explicitly
fixed registers, even when it is callee-saved. Some projects rely on
this (GCC's) behavior.

For example,
```
void f() {
  register uint64_t x28 asm("x28") = 0xee;
  asm volatile("" : "+r"(x28)); // avoid mov being eliminated
}
```
should not touch x28 outside of `mov w28,#0xee`.

For riscv64 clang behaves the same as GCC.

Fixes #111379.
---
 .../lib/Target/AArch64/AArch64FrameLowering.cpp |  6 ++++++
 llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp | 17 +++++++++++++++++
 llvm/lib/Target/AArch64/AArch64RegisterInfo.h   |  2 ++
 3 files changed, 25 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 78ac57e3e92a6..a0dd66b1c8639 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -3619,6 +3619,12 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
     if (Reg == BasePointerReg)
       SavedRegs.set(Reg);
 
+    // Don't save manually reserved registers set through -ffixed-reg.
+    if (RegInfo->isUserReservedReg(MF, Reg)) {
+      SavedRegs.reset(Reg);
+      continue;
+    }
+
     bool RegUsed = SavedRegs.test(Reg);
     unsigned PairedReg = AArch64::NoRegister;
     const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index 52b362875b4ef..6882704f4d1ea 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -518,6 +518,18 @@ AArch64RegisterInfo::getStrictlyReservedRegs(const MachineFunction &MF) const {
   return Reserved;
 }
 
+BitVector
+AArch64RegisterInfo::getUserReservedRegs(const MachineFunction &MF) const {
+  BitVector Reserved(getNumRegs());
+  for (size_t i = 0; i < AArch64::GPR32commonRegClass.getNumRegs(); ++i) {
+    // ReserveXRegister is set for registers manually reserved
+    // through -ffixed-reg.
+    if (MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i))
+      markSuperRegs(Reserved, AArch64::GPR32commonRegClass.getRegister(i));
+  }
+  return Reserved;
+}
+
 BitVector
 AArch64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   BitVector Reserved(getNumRegs());
@@ -551,6 +563,11 @@ bool AArch64RegisterInfo::isReservedReg(const MachineFunction &MF,
   return getReservedRegs(MF)[Reg];
 }
 
+bool AArch64RegisterInfo::isUserReservedReg(const MachineFunction &MF,
+                                            MCRegister Reg) const {
+  return getUserReservedRegs(MF)[Reg];
+}
+
 bool AArch64RegisterInfo::isStrictlyReservedReg(const MachineFunction &MF,
                                                 MCRegister Reg) const {
   return getStrictlyReservedRegs(MF)[Reg];
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index ddee0d6a0dc38..cc94be611a2ea 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -35,6 +35,7 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
   }
 
   bool isReservedReg(const MachineFunction &MF, MCRegister Reg) const;
+  bool isUserReservedReg(const MachineFunction &MF, MCRegister Reg) const;
   bool isStrictlyReservedReg(const MachineFunction &MF, MCRegister Reg) const;
   bool isAnyArgRegReserved(const MachineFunction &MF) const;
   void emitReservedArgRegCallError(const MachineFunction &MF) const;
@@ -93,6 +94,7 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
   const uint32_t *getWindowsStackProbePreservedMask() const;
 
   BitVector getStrictlyReservedRegs(const MachineFunction &MF) const;
+  BitVector getUserReservedRegs(const MachineFunction &MF) const;
   BitVector getReservedRegs(const MachineFunction &MF) const override;
   std::optional<std::string>
   explainReservedReg(const MachineFunction &MF,



More information about the llvm-commits mailing list