Skip to content

Conversation

@ppenzin
Copy link
Contributor

@ppenzin ppenzin commented Dec 4, 2025

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from @mgudim's save_csr_in_ra3 (from #90819), and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim mgudim@ventanamicro.com

Mikhail Gudim added 2 commits December 3, 2025 13:03
Split up `determineCaleeSaves` into:

`const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const`:
      Return the list of registers which must be preserved by the function: the value on exit must be the same as the value on entry. A register from this list does not need to be saved / reloaded if the function did not use it.

`virtual void determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs, BitVector &UncondPrologCSRs) const`:
      Determines which of the registers reported by getMustPreserveRegisters() must be saved in prolog and reloaded in epilog regardless of wheather or not they were modified by the function.

`virtual void determineEarlyCalleeSaves(MachineFunction &MF, BitVector &EarlyCSRs)`:
      Returns the difference between getMustPreserveRegisters and determineUncondPrologCalleeSaves. These registers will be preserved by the code optimizer and do not need to be saved in prolog.

`virtual void determinePrologCalleeSaves(MachineFunction &MF,
                                             BitVector &PrologCSRs,
                                             RegScavenger *RS) const`:
      This method returns those registers in the difference of  getMustPreserveRegisters and determineEarlyCalleeSaves that were modified by the function and need to be saved in prolog.
Use `determinePrologCalleeSaves` instead.
@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-xtensa
@llvm/pr-subscribers-backend-loongarch
@llvm/pr-subscribers-backend-powerpc
@llvm/pr-subscribers-backend-sparc

@llvm/pr-subscribers-backend-mips

Author: Petr Penzin (ppenzin)

Changes

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim <mgudim@ventanamicro.com>


Patch is 66.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170609.diff

57 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+32-3)
  • (modified) llvm/include/llvm/CodeGen/TargetRegisterInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/TargetSubtargetInfo.h (+4)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/RegisterScavenging.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp (+78-28)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+8-8)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp (+2-2)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+8-7)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+1-1)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+3-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+33-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+3-1)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.cpp (+4-5)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp (+6-8)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.h (+2-2)
  • (modified) llvm/test/CodeGen/AArch64/arm64-spill-lr.ll (+1-1)
  • (added) llvm/test/CodeGen/RISCV/determine-callee-saves.mir (+79)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 75696faf114cc..c04cd33b3377a 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -375,13 +375,13 @@ class LLVM_ABI TargetFrameLowering {
   virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
                                                    int FI) const;
 
-  /// Returns the callee-saved registers as computed by determineCalleeSaves
-  /// in the BitVector \p SavedRegs.
+  /// Returns the callee-saved registers as computed by
+  /// determinePrologCalleeSaves in the BitVector \p SavedRegs.
   virtual void getCalleeSaves(const MachineFunction &MF,
                                   BitVector &SavedRegs) const;
 
   /// This method determines which of the registers reported by
-  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
+  /// getMustPreserveRegisters() should actually get saved.
   /// The default implementation checks populates the \p SavedRegs bitset with
   /// all registers which are modified in the function, targets may override
   /// this function to save additional registers.
@@ -390,9 +390,38 @@ class LLVM_ABI TargetFrameLowering {
   /// This method should not be called by any passes outside of PEI, because
   /// it may change state passed in by \p MF and \p RS. The preferred
   /// interface outside PEI is getCalleeSaves.
+  LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                  "determinePrologCalleeSaves")
   virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                                     RegScavenger *RS = nullptr) const;
 
+  /// Return the list of registers which must be preserved by the function: the
+  /// value on exit must be the same as the value on entry. A register from this
+  /// list does not need to be saved / reloaded if the function did not use it.
+  const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const;
+
+  /// This method determines which of the registers reported by
+  /// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
+  /// regardless of wheather or not they were modified by the function.
+  virtual void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const;
+
+  /// If the target has to do all saves / restores of "must preserve" registers
+  /// in prolog / epilog, this method returns empty set. Otherwise, this method
+  /// returns the difference between getMustPreserveRegisters and
+  /// determineUncondPrologCalleeSaves. These registers will be preserved by the
+  /// code optimizer and do not need to be saved in prolog.
+  virtual void determineEarlyCalleeSaves(MachineFunction &MF,
+                                         BitVector &EarlyCSRs) const;
+
+  /// This method returns those registers in the difference of
+  /// getMustPreserveRegisters and determineEarlyCalleeSaves that were modified
+  /// by the function and need to be saved in prolog.
+  virtual void determinePrologCalleeSaves(MachineFunction &MF,
+                                          BitVector &PrologCSRs,
+                                          RegScavenger *RS) const;
+
   /// processFunctionBeforeFrameFinalized - This method is called immediately
   /// before the specified function's frame layout (MF.getFrameInfo()) is
   /// finalized.  Once the frame is finalized, MO_FrameIndex operands are
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..f8453f8394ab7 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -1066,7 +1066,7 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// register is required, the first fixed stack object is reserved as its
   /// spill slot. This tells PEI not to create a new stack frame
   /// object for the given register. It should be called only after
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   virtual bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
                                     int &FrameIdx) const {
     return false;
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..57978c8585a6a 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -364,6 +364,10 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   }
 
   virtual bool isRegisterReservedByUser(Register R) const { return false; }
+
+  // Return true if the target can ensure before PrologEpilogInsertion that
+  // callee-saved registers are preserved.
+  virtual bool savesCSRsEarly() const { return false; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 41efe622417c8..2639edcfed0a2 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -681,7 +681,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSaves(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSaves(MF, SavedRegs, RS);
 
   // Assign stack slots for any callee-saved registers that must be spilled.
   assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
diff --git a/llvm/lib/CodeGen/RegisterScavenging.cpp b/llvm/lib/CodeGen/RegisterScavenging.cpp
index d8861672a348f..cc5da28a95d85 100644
--- a/llvm/lib/CodeGen/RegisterScavenging.cpp
+++ b/llvm/lib/CodeGen/RegisterScavenging.cpp
@@ -511,7 +511,7 @@ class ScavengerTest : public MachineFunctionPass {
     // well enough to initialize the scavenger with some emergency spillslots
     // for the target.
     BitVector SavedRegs;
-    TFL.determineCalleeSaves(MF, SavedRegs, &RS);
+    TFL.determinePrologCalleeSaves(MF, SavedRegs, &RS);
     TFL.processFunctionBeforeFrameFinalized(MF, &RS);
 
     // Let's scavenge the current function
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..6933b7614e01d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -180,7 +180,7 @@ class ShrinkWrapImpl {
       const TargetFrameLowering *TFI =
           MachineFunc->getSubtarget().getFrameLowering();
 
-      TFI->determineCalleeSaves(*MachineFunc, SavedRegs, RS);
+      TFI->determinePrologCalleeSaves(*MachineFunc, SavedRegs, RS);
 
       for (int Reg = SavedRegs.find_first(); Reg != -1;
            Reg = SavedRegs.find_next(Reg))
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index ebf6d1a52448e..95144109ed14a 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,36 +93,20 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
     CalleeSaves.set(Info.getReg());
 }
 
+LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                "determinePrologCalleeSaves")
 void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                                BitVector &SavedRegs,
                                                RegScavenger *RS) const {
-  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
-
-  // Resize before the early returns. Some backends expect that
-  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
-  // saved registers.
-  SavedRegs.resize(TRI.getNumRegs());
-
-  // Get the callee saved register list...
-  const MCPhysReg *CSRegs = nullptr;
-
-  // When interprocedural register allocation is enabled, callee saved register
-  // list should be empty, since caller saved registers are preferred over
-  // callee saved registers. Unless it has some risked CSR to be optimized out.
-  if (MF.getTarget().Options.EnableIPRA &&
-      isSafeForNoCSROpt(MF.getFunction()) &&
-      isProfitableForNoCSROpt(MF.getFunction()))
-    CSRegs = TRI.getIPRACSRegs(&MF);
-  else
-    CSRegs = MF.getRegInfo().getCalleeSavedRegs();
-
-  // Early exit if there are no callee saved registers.
-  if (!CSRegs || CSRegs[0] == 0)
-    return;
+  determinePrologCalleeSaves(MF, SavedRegs, RS);
+}
 
+const MCPhysReg *
+TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
   // In Naked functions we aren't going to save any registers.
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return;
+    return nullptr;
 
   // Noreturn+nounwind functions never restore CSR, so no saves are needed.
   // Purely noreturn functions may still return through throws, so those must
@@ -135,15 +119,81 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
         !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
         enableCalleeSaveSkip(MF))
-    return;
+    return nullptr;
+
+  // When interprocedural register allocation is enabled, callee saved register
+  // list should be empty, since caller saved registers are preferred over
+  // callee saved registers. Unless it has some risked CSR to be optimized out.
+  if (MF.getTarget().Options.EnableIPRA &&
+      isSafeForNoCSROpt(MF.getFunction()) &&
+      isProfitableForNoCSROpt(MF.getFunction()))
+    return TRI.getIPRACSRegs(&MF);
+  return MF.getRegInfo().getCalleeSavedRegs();
+}
 
+void TargetFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   // Functions which call __builtin_unwind_init get all their registers saved.
-  bool CallsUnwindInit = MF.callsUnwindInit();
+  if (MF.callsUnwindInit()) {
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      unsigned Reg = CSRegs[i];
+      UncondPrologCSRs.set(Reg);
+    }
+  }
+  return;
+}
+
+void TargetFrameLowering::determineEarlyCalleeSaves(
+    MachineFunction &MF, BitVector &EarlyCSRs) const {
+  const auto &ST = MF.getSubtarget();
+  if (!ST.savesCSRsEarly())
+    return;
+
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  BitVector UncondPrologCSRs(TRI.getNumRegs(), false);
+  determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+
+  EarlyCSRs.resize(TRI.getNumRegs());
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!UncondPrologCSRs[Reg])
+      EarlyCSRs.set(Reg);
+  }
+}
+
+void TargetFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                     BitVector &PrologCSRs,
+                                                     RegScavenger *RS) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+
+  // Resize before the early returns. Some backends expect that
+  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
+  // saved registers.
+  PrologCSRs.resize(TRI.getNumRegs());
+
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  determineUncondPrologCalleeSaves(MF, CSRegs, PrologCSRs);
+
+  BitVector EarlyCSRs(TRI.getNumRegs(), false);
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   for (unsigned i = 0; CSRegs[i]; ++i) {
     unsigned Reg = CSRegs[i];
-    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
-      SavedRegs.set(Reg);
+    if (MRI.isPhysRegModified(Reg) && !EarlyCSRs[Reg])
+      PrologCSRs.set(Reg);
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 7290b3f67c2e3..bd5f2d3547e3b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2482,9 +2482,9 @@ void AArch64FrameLowering::determineStackHazardSlot(
   }
 }
 
-void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                                BitVector &SavedRegs,
-                                                RegScavenger *RS) const {
+void AArch64FrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                      BitVector &SavedRegs,
+                                                      RegScavenger *RS) const {
   // All calls are tail calls in GHC calling conv, and functions have no
   // prologue/epilogue.
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
@@ -2654,7 +2654,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
   }
 
   LLVM_DEBUG({
-    dbgs() << "*** determineCalleeSaves\nSaved CSRs:";
+    dbgs() << "*** determinePrologCalleeSaves\nSaved CSRs:";
     for (unsigned Reg : SavedRegs.set_bits())
       dbgs() << ' ' << printReg(MCRegister(Reg), RegInfo);
     dbgs() << "\n";
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 32a9bd831989c..6ded0e13ba22d 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -94,8 +94,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
                                    unsigned &MinCSFrameIndex,
                                    unsigned &MaxCSFrameIndex) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS) const override;
 
   /// Returns true if the target will correctly handle shrink wrapping.
   bool enableShrinkWrapping(const MachineFunction &MF) const override {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 00e0c2511aaf0..f1101605303b6 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -77,7 +77,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned TailCallReservedStack = 0;
 
   /// HasStackFrame - True if this function has a stack frame. Set by
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   bool HasStackFrame = false;
 
   /// Amount of stack frame size, not including callee-saved registers.
@@ -379,7 +379,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 #ifndef NDEBUG
     // Make sure the calculated size derived from the CalleeSavedInfo
     // equals the cached size that was calculated elsewhere (e.g. in
-    // determineCalleeSaves).
+    // determinePrologCalleeSaves).
     ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
 #endif
 
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index ffbb111d42221..cfde9651aa45f 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1691,9 +1691,9 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
 }
 
 // Only report VGPRs to generic code.
-void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                           BitVector &SavedVGPRs,
-                                           RegScavenger *RS) const {
+void SIFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                 BitVector &SavedVGPRs,
+                                                 RegScavenger *RS) const {
   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
 
   // If this is a function with the amdgpu_cs_chain[_preserve] calling
@@ -1702,7 +1702,7 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (MFI->isChainFunction() && !MF.getFrameInfo().hasTailCall())
     return;
 
-  TargetFrameLowering::determineCalleeSaves(MF, SavedVGPRs, RS);
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedVGPRs, RS);
 
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   const SIRegisterInfo *TRI = ST.getRegisterInfo();
@@ -1797,10 +1797,10 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedVGPRs.reset(Reg.first);
 }
 
-void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF,
-                                               BitVector &SavedRegs,
-                                               RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+void SIFrameLowering::determinePrologCalleeSavesSGPR(MachineFunction &MF,
+                                                     BitVector &SavedRegs,
+                                                     RegScavenger *RS) const {
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
   if (MFI->isEntryFunction())
     return;
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index a72772987262e..1d5ea69f00b42 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -30,10 +30,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
-  void determineCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
-                                RegScavenger *RS = nullptr) const;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS = nullptr) const override;
+  void determinePrologCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
+                                      RegScavenger *RS = nullptr) const;
   void determinePrologEpilogSGPRSaves(MachineFunction &MF, BitVector &SavedRegs,
                                       bool NeedExecCopyReservedReg) const;
   void emitCSRSpillStores(MachineFunction &MF, MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cbd08f0fb5dff..ad14822f89f06 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -257,7 +257,7 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSavesSGPR(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSavesSGPR(MF, SavedRegs, RS);
 
   // Add the code to save and restore the callee saved registers.
   if (!F.hasFnAttribute(Attribute::Naked)) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 9abda275d7e42..cac608d3e87be 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -388,8 +388,8 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
       SpillPhysVGPRs[Idx] = NewReg;
     }
 
-    // The generic `determineCalleeSaves` might have set the old register if it
-    // is in the CSR range.
+    // The generic `determinePrologCalleeSaves` might have set the old register
+    // if it is in the CSR range.
     SavedVGPRs.reset(Reg);
 
     for (MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 9f6a79e3210c4..83ce075dc9663 100644
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-systemz

Author: Petr Penzin (ppenzin)

Changes

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim <mgudim@ventanamicro.com>


Patch is 66.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170609.diff

57 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+32-3)
  • (modified) llvm/include/llvm/CodeGen/TargetRegisterInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/TargetSubtargetInfo.h (+4)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/RegisterScavenging.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp (+78-28)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+8-8)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp (+2-2)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+8-7)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+1-1)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+3-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+33-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+3-1)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.cpp (+4-5)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp (+6-8)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.h (+2-2)
  • (modified) llvm/test/CodeGen/AArch64/arm64-spill-lr.ll (+1-1)
  • (added) llvm/test/CodeGen/RISCV/determine-callee-saves.mir (+79)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 75696faf114cc..c04cd33b3377a 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -375,13 +375,13 @@ class LLVM_ABI TargetFrameLowering {
   virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
                                                    int FI) const;
 
-  /// Returns the callee-saved registers as computed by determineCalleeSaves
-  /// in the BitVector \p SavedRegs.
+  /// Returns the callee-saved registers as computed by
+  /// determinePrologCalleeSaves in the BitVector \p SavedRegs.
   virtual void getCalleeSaves(const MachineFunction &MF,
                                   BitVector &SavedRegs) const;
 
   /// This method determines which of the registers reported by
-  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
+  /// getMustPreserveRegisters() should actually get saved.
   /// The default implementation checks populates the \p SavedRegs bitset with
   /// all registers which are modified in the function, targets may override
   /// this function to save additional registers.
@@ -390,9 +390,38 @@ class LLVM_ABI TargetFrameLowering {
   /// This method should not be called by any passes outside of PEI, because
   /// it may change state passed in by \p MF and \p RS. The preferred
   /// interface outside PEI is getCalleeSaves.
+  LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                  "determinePrologCalleeSaves")
   virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                                     RegScavenger *RS = nullptr) const;
 
+  /// Return the list of registers which must be preserved by the function: the
+  /// value on exit must be the same as the value on entry. A register from this
+  /// list does not need to be saved / reloaded if the function did not use it.
+  const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const;
+
+  /// This method determines which of the registers reported by
+  /// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
+  /// regardless of wheather or not they were modified by the function.
+  virtual void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const;
+
+  /// If the target has to do all saves / restores of "must preserve" registers
+  /// in prolog / epilog, this method returns empty set. Otherwise, this method
+  /// returns the difference between getMustPreserveRegisters and
+  /// determineUncondPrologCalleeSaves. These registers will be preserved by the
+  /// code optimizer and do not need to be saved in prolog.
+  virtual void determineEarlyCalleeSaves(MachineFunction &MF,
+                                         BitVector &EarlyCSRs) const;
+
+  /// This method returns those registers in the difference of
+  /// getMustPreserveRegisters and determineEarlyCalleeSaves that were modified
+  /// by the function and need to be saved in prolog.
+  virtual void determinePrologCalleeSaves(MachineFunction &MF,
+                                          BitVector &PrologCSRs,
+                                          RegScavenger *RS) const;
+
   /// processFunctionBeforeFrameFinalized - This method is called immediately
   /// before the specified function's frame layout (MF.getFrameInfo()) is
   /// finalized.  Once the frame is finalized, MO_FrameIndex operands are
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..f8453f8394ab7 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -1066,7 +1066,7 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// register is required, the first fixed stack object is reserved as its
   /// spill slot. This tells PEI not to create a new stack frame
   /// object for the given register. It should be called only after
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   virtual bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
                                     int &FrameIdx) const {
     return false;
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..57978c8585a6a 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -364,6 +364,10 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   }
 
   virtual bool isRegisterReservedByUser(Register R) const { return false; }
+
+  // Return true if the target can ensure before PrologEpilogInsertion that
+  // callee-saved registers are preserved.
+  virtual bool savesCSRsEarly() const { return false; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 41efe622417c8..2639edcfed0a2 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -681,7 +681,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSaves(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSaves(MF, SavedRegs, RS);
 
   // Assign stack slots for any callee-saved registers that must be spilled.
   assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
diff --git a/llvm/lib/CodeGen/RegisterScavenging.cpp b/llvm/lib/CodeGen/RegisterScavenging.cpp
index d8861672a348f..cc5da28a95d85 100644
--- a/llvm/lib/CodeGen/RegisterScavenging.cpp
+++ b/llvm/lib/CodeGen/RegisterScavenging.cpp
@@ -511,7 +511,7 @@ class ScavengerTest : public MachineFunctionPass {
     // well enough to initialize the scavenger with some emergency spillslots
     // for the target.
     BitVector SavedRegs;
-    TFL.determineCalleeSaves(MF, SavedRegs, &RS);
+    TFL.determinePrologCalleeSaves(MF, SavedRegs, &RS);
     TFL.processFunctionBeforeFrameFinalized(MF, &RS);
 
     // Let's scavenge the current function
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..6933b7614e01d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -180,7 +180,7 @@ class ShrinkWrapImpl {
       const TargetFrameLowering *TFI =
           MachineFunc->getSubtarget().getFrameLowering();
 
-      TFI->determineCalleeSaves(*MachineFunc, SavedRegs, RS);
+      TFI->determinePrologCalleeSaves(*MachineFunc, SavedRegs, RS);
 
       for (int Reg = SavedRegs.find_first(); Reg != -1;
            Reg = SavedRegs.find_next(Reg))
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index ebf6d1a52448e..95144109ed14a 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,36 +93,20 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
     CalleeSaves.set(Info.getReg());
 }
 
+LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                "determinePrologCalleeSaves")
 void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                                BitVector &SavedRegs,
                                                RegScavenger *RS) const {
-  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
-
-  // Resize before the early returns. Some backends expect that
-  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
-  // saved registers.
-  SavedRegs.resize(TRI.getNumRegs());
-
-  // Get the callee saved register list...
-  const MCPhysReg *CSRegs = nullptr;
-
-  // When interprocedural register allocation is enabled, callee saved register
-  // list should be empty, since caller saved registers are preferred over
-  // callee saved registers. Unless it has some risked CSR to be optimized out.
-  if (MF.getTarget().Options.EnableIPRA &&
-      isSafeForNoCSROpt(MF.getFunction()) &&
-      isProfitableForNoCSROpt(MF.getFunction()))
-    CSRegs = TRI.getIPRACSRegs(&MF);
-  else
-    CSRegs = MF.getRegInfo().getCalleeSavedRegs();
-
-  // Early exit if there are no callee saved registers.
-  if (!CSRegs || CSRegs[0] == 0)
-    return;
+  determinePrologCalleeSaves(MF, SavedRegs, RS);
+}
 
+const MCPhysReg *
+TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
   // In Naked functions we aren't going to save any registers.
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return;
+    return nullptr;
 
   // Noreturn+nounwind functions never restore CSR, so no saves are needed.
   // Purely noreturn functions may still return through throws, so those must
@@ -135,15 +119,81 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
         !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
         enableCalleeSaveSkip(MF))
-    return;
+    return nullptr;
+
+  // When interprocedural register allocation is enabled, callee saved register
+  // list should be empty, since caller saved registers are preferred over
+  // callee saved registers. Unless it has some risked CSR to be optimized out.
+  if (MF.getTarget().Options.EnableIPRA &&
+      isSafeForNoCSROpt(MF.getFunction()) &&
+      isProfitableForNoCSROpt(MF.getFunction()))
+    return TRI.getIPRACSRegs(&MF);
+  return MF.getRegInfo().getCalleeSavedRegs();
+}
 
+void TargetFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   // Functions which call __builtin_unwind_init get all their registers saved.
-  bool CallsUnwindInit = MF.callsUnwindInit();
+  if (MF.callsUnwindInit()) {
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      unsigned Reg = CSRegs[i];
+      UncondPrologCSRs.set(Reg);
+    }
+  }
+  return;
+}
+
+void TargetFrameLowering::determineEarlyCalleeSaves(
+    MachineFunction &MF, BitVector &EarlyCSRs) const {
+  const auto &ST = MF.getSubtarget();
+  if (!ST.savesCSRsEarly())
+    return;
+
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  BitVector UncondPrologCSRs(TRI.getNumRegs(), false);
+  determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+
+  EarlyCSRs.resize(TRI.getNumRegs());
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!UncondPrologCSRs[Reg])
+      EarlyCSRs.set(Reg);
+  }
+}
+
+void TargetFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                     BitVector &PrologCSRs,
+                                                     RegScavenger *RS) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+
+  // Resize before the early returns. Some backends expect that
+  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
+  // saved registers.
+  PrologCSRs.resize(TRI.getNumRegs());
+
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  determineUncondPrologCalleeSaves(MF, CSRegs, PrologCSRs);
+
+  BitVector EarlyCSRs(TRI.getNumRegs(), false);
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   for (unsigned i = 0; CSRegs[i]; ++i) {
     unsigned Reg = CSRegs[i];
-    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
-      SavedRegs.set(Reg);
+    if (MRI.isPhysRegModified(Reg) && !EarlyCSRs[Reg])
+      PrologCSRs.set(Reg);
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 7290b3f67c2e3..bd5f2d3547e3b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2482,9 +2482,9 @@ void AArch64FrameLowering::determineStackHazardSlot(
   }
 }
 
-void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                                BitVector &SavedRegs,
-                                                RegScavenger *RS) const {
+void AArch64FrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                      BitVector &SavedRegs,
+                                                      RegScavenger *RS) const {
   // All calls are tail calls in GHC calling conv, and functions have no
   // prologue/epilogue.
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
@@ -2654,7 +2654,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
   }
 
   LLVM_DEBUG({
-    dbgs() << "*** determineCalleeSaves\nSaved CSRs:";
+    dbgs() << "*** determinePrologCalleeSaves\nSaved CSRs:";
     for (unsigned Reg : SavedRegs.set_bits())
       dbgs() << ' ' << printReg(MCRegister(Reg), RegInfo);
     dbgs() << "\n";
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 32a9bd831989c..6ded0e13ba22d 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -94,8 +94,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
                                    unsigned &MinCSFrameIndex,
                                    unsigned &MaxCSFrameIndex) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS) const override;
 
   /// Returns true if the target will correctly handle shrink wrapping.
   bool enableShrinkWrapping(const MachineFunction &MF) const override {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 00e0c2511aaf0..f1101605303b6 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -77,7 +77,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned TailCallReservedStack = 0;
 
   /// HasStackFrame - True if this function has a stack frame. Set by
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   bool HasStackFrame = false;
 
   /// Amount of stack frame size, not including callee-saved registers.
@@ -379,7 +379,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 #ifndef NDEBUG
     // Make sure the calculated size derived from the CalleeSavedInfo
     // equals the cached size that was calculated elsewhere (e.g. in
-    // determineCalleeSaves).
+    // determinePrologCalleeSaves).
     ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
 #endif
 
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index ffbb111d42221..cfde9651aa45f 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1691,9 +1691,9 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
 }
 
 // Only report VGPRs to generic code.
-void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                           BitVector &SavedVGPRs,
-                                           RegScavenger *RS) const {
+void SIFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                 BitVector &SavedVGPRs,
+                                                 RegScavenger *RS) const {
   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
 
   // If this is a function with the amdgpu_cs_chain[_preserve] calling
@@ -1702,7 +1702,7 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (MFI->isChainFunction() && !MF.getFrameInfo().hasTailCall())
     return;
 
-  TargetFrameLowering::determineCalleeSaves(MF, SavedVGPRs, RS);
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedVGPRs, RS);
 
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   const SIRegisterInfo *TRI = ST.getRegisterInfo();
@@ -1797,10 +1797,10 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedVGPRs.reset(Reg.first);
 }
 
-void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF,
-                                               BitVector &SavedRegs,
-                                               RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+void SIFrameLowering::determinePrologCalleeSavesSGPR(MachineFunction &MF,
+                                                     BitVector &SavedRegs,
+                                                     RegScavenger *RS) const {
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
   if (MFI->isEntryFunction())
     return;
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index a72772987262e..1d5ea69f00b42 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -30,10 +30,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
-  void determineCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
-                                RegScavenger *RS = nullptr) const;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS = nullptr) const override;
+  void determinePrologCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
+                                      RegScavenger *RS = nullptr) const;
   void determinePrologEpilogSGPRSaves(MachineFunction &MF, BitVector &SavedRegs,
                                       bool NeedExecCopyReservedReg) const;
   void emitCSRSpillStores(MachineFunction &MF, MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cbd08f0fb5dff..ad14822f89f06 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -257,7 +257,7 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSavesSGPR(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSavesSGPR(MF, SavedRegs, RS);
 
   // Add the code to save and restore the callee saved registers.
   if (!F.hasFnAttribute(Attribute::Naked)) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 9abda275d7e42..cac608d3e87be 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -388,8 +388,8 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
       SpillPhysVGPRs[Idx] = NewReg;
     }
 
-    // The generic `determineCalleeSaves` might have set the old register if it
-    // is in the CSR range.
+    // The generic `determinePrologCalleeSaves` might have set the old register
+    // if it is in the CSR range.
     SavedVGPRs.reset(Reg);
 
     for (MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 9f6a79e3210c4..83ce075dc9663 100644
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Petr Penzin (ppenzin)

Changes

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim <mgudim@ventanamicro.com>


Patch is 66.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170609.diff

57 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+32-3)
  • (modified) llvm/include/llvm/CodeGen/TargetRegisterInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/TargetSubtargetInfo.h (+4)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/RegisterScavenging.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp (+78-28)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+8-8)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp (+2-2)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+8-7)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+1-1)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+3-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+33-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+3-1)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.cpp (+4-5)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp (+6-8)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.h (+2-2)
  • (modified) llvm/test/CodeGen/AArch64/arm64-spill-lr.ll (+1-1)
  • (added) llvm/test/CodeGen/RISCV/determine-callee-saves.mir (+79)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 75696faf114cc..c04cd33b3377a 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -375,13 +375,13 @@ class LLVM_ABI TargetFrameLowering {
   virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
                                                    int FI) const;
 
-  /// Returns the callee-saved registers as computed by determineCalleeSaves
-  /// in the BitVector \p SavedRegs.
+  /// Returns the callee-saved registers as computed by
+  /// determinePrologCalleeSaves in the BitVector \p SavedRegs.
   virtual void getCalleeSaves(const MachineFunction &MF,
                                   BitVector &SavedRegs) const;
 
   /// This method determines which of the registers reported by
-  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
+  /// getMustPreserveRegisters() should actually get saved.
   /// The default implementation checks populates the \p SavedRegs bitset with
   /// all registers which are modified in the function, targets may override
   /// this function to save additional registers.
@@ -390,9 +390,38 @@ class LLVM_ABI TargetFrameLowering {
   /// This method should not be called by any passes outside of PEI, because
   /// it may change state passed in by \p MF and \p RS. The preferred
   /// interface outside PEI is getCalleeSaves.
+  LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                  "determinePrologCalleeSaves")
   virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                                     RegScavenger *RS = nullptr) const;
 
+  /// Return the list of registers which must be preserved by the function: the
+  /// value on exit must be the same as the value on entry. A register from this
+  /// list does not need to be saved / reloaded if the function did not use it.
+  const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const;
+
+  /// This method determines which of the registers reported by
+  /// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
+  /// regardless of wheather or not they were modified by the function.
+  virtual void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const;
+
+  /// If the target has to do all saves / restores of "must preserve" registers
+  /// in prolog / epilog, this method returns empty set. Otherwise, this method
+  /// returns the difference between getMustPreserveRegisters and
+  /// determineUncondPrologCalleeSaves. These registers will be preserved by the
+  /// code optimizer and do not need to be saved in prolog.
+  virtual void determineEarlyCalleeSaves(MachineFunction &MF,
+                                         BitVector &EarlyCSRs) const;
+
+  /// This method returns those registers in the difference of
+  /// getMustPreserveRegisters and determineEarlyCalleeSaves that were modified
+  /// by the function and need to be saved in prolog.
+  virtual void determinePrologCalleeSaves(MachineFunction &MF,
+                                          BitVector &PrologCSRs,
+                                          RegScavenger *RS) const;
+
   /// processFunctionBeforeFrameFinalized - This method is called immediately
   /// before the specified function's frame layout (MF.getFrameInfo()) is
   /// finalized.  Once the frame is finalized, MO_FrameIndex operands are
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..f8453f8394ab7 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -1066,7 +1066,7 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// register is required, the first fixed stack object is reserved as its
   /// spill slot. This tells PEI not to create a new stack frame
   /// object for the given register. It should be called only after
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   virtual bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
                                     int &FrameIdx) const {
     return false;
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..57978c8585a6a 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -364,6 +364,10 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   }
 
   virtual bool isRegisterReservedByUser(Register R) const { return false; }
+
+  // Return true if the target can ensure before PrologEpilogInsertion that
+  // callee-saved registers are preserved.
+  virtual bool savesCSRsEarly() const { return false; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 41efe622417c8..2639edcfed0a2 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -681,7 +681,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSaves(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSaves(MF, SavedRegs, RS);
 
   // Assign stack slots for any callee-saved registers that must be spilled.
   assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
diff --git a/llvm/lib/CodeGen/RegisterScavenging.cpp b/llvm/lib/CodeGen/RegisterScavenging.cpp
index d8861672a348f..cc5da28a95d85 100644
--- a/llvm/lib/CodeGen/RegisterScavenging.cpp
+++ b/llvm/lib/CodeGen/RegisterScavenging.cpp
@@ -511,7 +511,7 @@ class ScavengerTest : public MachineFunctionPass {
     // well enough to initialize the scavenger with some emergency spillslots
     // for the target.
     BitVector SavedRegs;
-    TFL.determineCalleeSaves(MF, SavedRegs, &RS);
+    TFL.determinePrologCalleeSaves(MF, SavedRegs, &RS);
     TFL.processFunctionBeforeFrameFinalized(MF, &RS);
 
     // Let's scavenge the current function
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..6933b7614e01d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -180,7 +180,7 @@ class ShrinkWrapImpl {
       const TargetFrameLowering *TFI =
           MachineFunc->getSubtarget().getFrameLowering();
 
-      TFI->determineCalleeSaves(*MachineFunc, SavedRegs, RS);
+      TFI->determinePrologCalleeSaves(*MachineFunc, SavedRegs, RS);
 
       for (int Reg = SavedRegs.find_first(); Reg != -1;
            Reg = SavedRegs.find_next(Reg))
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index ebf6d1a52448e..95144109ed14a 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,36 +93,20 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
     CalleeSaves.set(Info.getReg());
 }
 
+LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                "determinePrologCalleeSaves")
 void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                                BitVector &SavedRegs,
                                                RegScavenger *RS) const {
-  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
-
-  // Resize before the early returns. Some backends expect that
-  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
-  // saved registers.
-  SavedRegs.resize(TRI.getNumRegs());
-
-  // Get the callee saved register list...
-  const MCPhysReg *CSRegs = nullptr;
-
-  // When interprocedural register allocation is enabled, callee saved register
-  // list should be empty, since caller saved registers are preferred over
-  // callee saved registers. Unless it has some risked CSR to be optimized out.
-  if (MF.getTarget().Options.EnableIPRA &&
-      isSafeForNoCSROpt(MF.getFunction()) &&
-      isProfitableForNoCSROpt(MF.getFunction()))
-    CSRegs = TRI.getIPRACSRegs(&MF);
-  else
-    CSRegs = MF.getRegInfo().getCalleeSavedRegs();
-
-  // Early exit if there are no callee saved registers.
-  if (!CSRegs || CSRegs[0] == 0)
-    return;
+  determinePrologCalleeSaves(MF, SavedRegs, RS);
+}
 
+const MCPhysReg *
+TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
   // In Naked functions we aren't going to save any registers.
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return;
+    return nullptr;
 
   // Noreturn+nounwind functions never restore CSR, so no saves are needed.
   // Purely noreturn functions may still return through throws, so those must
@@ -135,15 +119,81 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
         !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
         enableCalleeSaveSkip(MF))
-    return;
+    return nullptr;
+
+  // When interprocedural register allocation is enabled, callee saved register
+  // list should be empty, since caller saved registers are preferred over
+  // callee saved registers. Unless it has some risked CSR to be optimized out.
+  if (MF.getTarget().Options.EnableIPRA &&
+      isSafeForNoCSROpt(MF.getFunction()) &&
+      isProfitableForNoCSROpt(MF.getFunction()))
+    return TRI.getIPRACSRegs(&MF);
+  return MF.getRegInfo().getCalleeSavedRegs();
+}
 
+void TargetFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   // Functions which call __builtin_unwind_init get all their registers saved.
-  bool CallsUnwindInit = MF.callsUnwindInit();
+  if (MF.callsUnwindInit()) {
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      unsigned Reg = CSRegs[i];
+      UncondPrologCSRs.set(Reg);
+    }
+  }
+  return;
+}
+
+void TargetFrameLowering::determineEarlyCalleeSaves(
+    MachineFunction &MF, BitVector &EarlyCSRs) const {
+  const auto &ST = MF.getSubtarget();
+  if (!ST.savesCSRsEarly())
+    return;
+
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  BitVector UncondPrologCSRs(TRI.getNumRegs(), false);
+  determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+
+  EarlyCSRs.resize(TRI.getNumRegs());
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!UncondPrologCSRs[Reg])
+      EarlyCSRs.set(Reg);
+  }
+}
+
+void TargetFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                     BitVector &PrologCSRs,
+                                                     RegScavenger *RS) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+
+  // Resize before the early returns. Some backends expect that
+  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
+  // saved registers.
+  PrologCSRs.resize(TRI.getNumRegs());
+
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  determineUncondPrologCalleeSaves(MF, CSRegs, PrologCSRs);
+
+  BitVector EarlyCSRs(TRI.getNumRegs(), false);
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   for (unsigned i = 0; CSRegs[i]; ++i) {
     unsigned Reg = CSRegs[i];
-    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
-      SavedRegs.set(Reg);
+    if (MRI.isPhysRegModified(Reg) && !EarlyCSRs[Reg])
+      PrologCSRs.set(Reg);
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 7290b3f67c2e3..bd5f2d3547e3b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2482,9 +2482,9 @@ void AArch64FrameLowering::determineStackHazardSlot(
   }
 }
 
-void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                                BitVector &SavedRegs,
-                                                RegScavenger *RS) const {
+void AArch64FrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                      BitVector &SavedRegs,
+                                                      RegScavenger *RS) const {
   // All calls are tail calls in GHC calling conv, and functions have no
   // prologue/epilogue.
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
@@ -2654,7 +2654,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
   }
 
   LLVM_DEBUG({
-    dbgs() << "*** determineCalleeSaves\nSaved CSRs:";
+    dbgs() << "*** determinePrologCalleeSaves\nSaved CSRs:";
     for (unsigned Reg : SavedRegs.set_bits())
       dbgs() << ' ' << printReg(MCRegister(Reg), RegInfo);
     dbgs() << "\n";
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 32a9bd831989c..6ded0e13ba22d 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -94,8 +94,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
                                    unsigned &MinCSFrameIndex,
                                    unsigned &MaxCSFrameIndex) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS) const override;
 
   /// Returns true if the target will correctly handle shrink wrapping.
   bool enableShrinkWrapping(const MachineFunction &MF) const override {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 00e0c2511aaf0..f1101605303b6 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -77,7 +77,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned TailCallReservedStack = 0;
 
   /// HasStackFrame - True if this function has a stack frame. Set by
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   bool HasStackFrame = false;
 
   /// Amount of stack frame size, not including callee-saved registers.
@@ -379,7 +379,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 #ifndef NDEBUG
     // Make sure the calculated size derived from the CalleeSavedInfo
     // equals the cached size that was calculated elsewhere (e.g. in
-    // determineCalleeSaves).
+    // determinePrologCalleeSaves).
     ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
 #endif
 
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index ffbb111d42221..cfde9651aa45f 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1691,9 +1691,9 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
 }
 
 // Only report VGPRs to generic code.
-void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                           BitVector &SavedVGPRs,
-                                           RegScavenger *RS) const {
+void SIFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                 BitVector &SavedVGPRs,
+                                                 RegScavenger *RS) const {
   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
 
   // If this is a function with the amdgpu_cs_chain[_preserve] calling
@@ -1702,7 +1702,7 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (MFI->isChainFunction() && !MF.getFrameInfo().hasTailCall())
     return;
 
-  TargetFrameLowering::determineCalleeSaves(MF, SavedVGPRs, RS);
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedVGPRs, RS);
 
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   const SIRegisterInfo *TRI = ST.getRegisterInfo();
@@ -1797,10 +1797,10 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedVGPRs.reset(Reg.first);
 }
 
-void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF,
-                                               BitVector &SavedRegs,
-                                               RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+void SIFrameLowering::determinePrologCalleeSavesSGPR(MachineFunction &MF,
+                                                     BitVector &SavedRegs,
+                                                     RegScavenger *RS) const {
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
   if (MFI->isEntryFunction())
     return;
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index a72772987262e..1d5ea69f00b42 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -30,10 +30,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
-  void determineCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
-                                RegScavenger *RS = nullptr) const;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS = nullptr) const override;
+  void determinePrologCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
+                                      RegScavenger *RS = nullptr) const;
   void determinePrologEpilogSGPRSaves(MachineFunction &MF, BitVector &SavedRegs,
                                       bool NeedExecCopyReservedReg) const;
   void emitCSRSpillStores(MachineFunction &MF, MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cbd08f0fb5dff..ad14822f89f06 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -257,7 +257,7 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSavesSGPR(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSavesSGPR(MF, SavedRegs, RS);
 
   // Add the code to save and restore the callee saved registers.
   if (!F.hasFnAttribute(Attribute::Naked)) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 9abda275d7e42..cac608d3e87be 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -388,8 +388,8 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
       SpillPhysVGPRs[Idx] = NewReg;
     }
 
-    // The generic `determineCalleeSaves` might have set the old register if it
-    // is in the CSR range.
+    // The generic `determinePrologCalleeSaves` might have set the old register
+    // if it is in the CSR range.
     SavedVGPRs.reset(Reg);
 
     for (MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 9f6a79e3210c4..83ce075dc9663 100644
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-m68k

Author: Petr Penzin (ppenzin)

Changes

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim <mgudim@ventanamicro.com>


Patch is 66.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170609.diff

57 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+32-3)
  • (modified) llvm/include/llvm/CodeGen/TargetRegisterInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/TargetSubtargetInfo.h (+4)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/RegisterScavenging.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp (+78-28)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+8-8)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp (+2-2)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+8-7)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+1-1)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+3-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+33-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+3-1)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.cpp (+4-5)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp (+6-8)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.h (+2-2)
  • (modified) llvm/test/CodeGen/AArch64/arm64-spill-lr.ll (+1-1)
  • (added) llvm/test/CodeGen/RISCV/determine-callee-saves.mir (+79)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 75696faf114cc..c04cd33b3377a 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -375,13 +375,13 @@ class LLVM_ABI TargetFrameLowering {
   virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
                                                    int FI) const;
 
-  /// Returns the callee-saved registers as computed by determineCalleeSaves
-  /// in the BitVector \p SavedRegs.
+  /// Returns the callee-saved registers as computed by
+  /// determinePrologCalleeSaves in the BitVector \p SavedRegs.
   virtual void getCalleeSaves(const MachineFunction &MF,
                                   BitVector &SavedRegs) const;
 
   /// This method determines which of the registers reported by
-  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
+  /// getMustPreserveRegisters() should actually get saved.
   /// The default implementation checks populates the \p SavedRegs bitset with
   /// all registers which are modified in the function, targets may override
   /// this function to save additional registers.
@@ -390,9 +390,38 @@ class LLVM_ABI TargetFrameLowering {
   /// This method should not be called by any passes outside of PEI, because
   /// it may change state passed in by \p MF and \p RS. The preferred
   /// interface outside PEI is getCalleeSaves.
+  LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                  "determinePrologCalleeSaves")
   virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                                     RegScavenger *RS = nullptr) const;
 
+  /// Return the list of registers which must be preserved by the function: the
+  /// value on exit must be the same as the value on entry. A register from this
+  /// list does not need to be saved / reloaded if the function did not use it.
+  const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const;
+
+  /// This method determines which of the registers reported by
+  /// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
+  /// regardless of wheather or not they were modified by the function.
+  virtual void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const;
+
+  /// If the target has to do all saves / restores of "must preserve" registers
+  /// in prolog / epilog, this method returns empty set. Otherwise, this method
+  /// returns the difference between getMustPreserveRegisters and
+  /// determineUncondPrologCalleeSaves. These registers will be preserved by the
+  /// code optimizer and do not need to be saved in prolog.
+  virtual void determineEarlyCalleeSaves(MachineFunction &MF,
+                                         BitVector &EarlyCSRs) const;
+
+  /// This method returns those registers in the difference of
+  /// getMustPreserveRegisters and determineEarlyCalleeSaves that were modified
+  /// by the function and need to be saved in prolog.
+  virtual void determinePrologCalleeSaves(MachineFunction &MF,
+                                          BitVector &PrologCSRs,
+                                          RegScavenger *RS) const;
+
   /// processFunctionBeforeFrameFinalized - This method is called immediately
   /// before the specified function's frame layout (MF.getFrameInfo()) is
   /// finalized.  Once the frame is finalized, MO_FrameIndex operands are
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..f8453f8394ab7 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -1066,7 +1066,7 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// register is required, the first fixed stack object is reserved as its
   /// spill slot. This tells PEI not to create a new stack frame
   /// object for the given register. It should be called only after
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   virtual bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
                                     int &FrameIdx) const {
     return false;
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..57978c8585a6a 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -364,6 +364,10 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   }
 
   virtual bool isRegisterReservedByUser(Register R) const { return false; }
+
+  // Return true if the target can ensure before PrologEpilogInsertion that
+  // callee-saved registers are preserved.
+  virtual bool savesCSRsEarly() const { return false; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 41efe622417c8..2639edcfed0a2 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -681,7 +681,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSaves(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSaves(MF, SavedRegs, RS);
 
   // Assign stack slots for any callee-saved registers that must be spilled.
   assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
diff --git a/llvm/lib/CodeGen/RegisterScavenging.cpp b/llvm/lib/CodeGen/RegisterScavenging.cpp
index d8861672a348f..cc5da28a95d85 100644
--- a/llvm/lib/CodeGen/RegisterScavenging.cpp
+++ b/llvm/lib/CodeGen/RegisterScavenging.cpp
@@ -511,7 +511,7 @@ class ScavengerTest : public MachineFunctionPass {
     // well enough to initialize the scavenger with some emergency spillslots
     // for the target.
     BitVector SavedRegs;
-    TFL.determineCalleeSaves(MF, SavedRegs, &RS);
+    TFL.determinePrologCalleeSaves(MF, SavedRegs, &RS);
     TFL.processFunctionBeforeFrameFinalized(MF, &RS);
 
     // Let's scavenge the current function
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..6933b7614e01d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -180,7 +180,7 @@ class ShrinkWrapImpl {
       const TargetFrameLowering *TFI =
           MachineFunc->getSubtarget().getFrameLowering();
 
-      TFI->determineCalleeSaves(*MachineFunc, SavedRegs, RS);
+      TFI->determinePrologCalleeSaves(*MachineFunc, SavedRegs, RS);
 
       for (int Reg = SavedRegs.find_first(); Reg != -1;
            Reg = SavedRegs.find_next(Reg))
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index ebf6d1a52448e..95144109ed14a 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,36 +93,20 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
     CalleeSaves.set(Info.getReg());
 }
 
+LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                "determinePrologCalleeSaves")
 void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                                BitVector &SavedRegs,
                                                RegScavenger *RS) const {
-  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
-
-  // Resize before the early returns. Some backends expect that
-  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
-  // saved registers.
-  SavedRegs.resize(TRI.getNumRegs());
-
-  // Get the callee saved register list...
-  const MCPhysReg *CSRegs = nullptr;
-
-  // When interprocedural register allocation is enabled, callee saved register
-  // list should be empty, since caller saved registers are preferred over
-  // callee saved registers. Unless it has some risked CSR to be optimized out.
-  if (MF.getTarget().Options.EnableIPRA &&
-      isSafeForNoCSROpt(MF.getFunction()) &&
-      isProfitableForNoCSROpt(MF.getFunction()))
-    CSRegs = TRI.getIPRACSRegs(&MF);
-  else
-    CSRegs = MF.getRegInfo().getCalleeSavedRegs();
-
-  // Early exit if there are no callee saved registers.
-  if (!CSRegs || CSRegs[0] == 0)
-    return;
+  determinePrologCalleeSaves(MF, SavedRegs, RS);
+}
 
+const MCPhysReg *
+TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
   // In Naked functions we aren't going to save any registers.
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return;
+    return nullptr;
 
   // Noreturn+nounwind functions never restore CSR, so no saves are needed.
   // Purely noreturn functions may still return through throws, so those must
@@ -135,15 +119,81 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
         !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
         enableCalleeSaveSkip(MF))
-    return;
+    return nullptr;
+
+  // When interprocedural register allocation is enabled, callee saved register
+  // list should be empty, since caller saved registers are preferred over
+  // callee saved registers. Unless it has some risked CSR to be optimized out.
+  if (MF.getTarget().Options.EnableIPRA &&
+      isSafeForNoCSROpt(MF.getFunction()) &&
+      isProfitableForNoCSROpt(MF.getFunction()))
+    return TRI.getIPRACSRegs(&MF);
+  return MF.getRegInfo().getCalleeSavedRegs();
+}
 
+void TargetFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   // Functions which call __builtin_unwind_init get all their registers saved.
-  bool CallsUnwindInit = MF.callsUnwindInit();
+  if (MF.callsUnwindInit()) {
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      unsigned Reg = CSRegs[i];
+      UncondPrologCSRs.set(Reg);
+    }
+  }
+  return;
+}
+
+void TargetFrameLowering::determineEarlyCalleeSaves(
+    MachineFunction &MF, BitVector &EarlyCSRs) const {
+  const auto &ST = MF.getSubtarget();
+  if (!ST.savesCSRsEarly())
+    return;
+
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  BitVector UncondPrologCSRs(TRI.getNumRegs(), false);
+  determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+
+  EarlyCSRs.resize(TRI.getNumRegs());
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!UncondPrologCSRs[Reg])
+      EarlyCSRs.set(Reg);
+  }
+}
+
+void TargetFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                     BitVector &PrologCSRs,
+                                                     RegScavenger *RS) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+
+  // Resize before the early returns. Some backends expect that
+  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
+  // saved registers.
+  PrologCSRs.resize(TRI.getNumRegs());
+
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  determineUncondPrologCalleeSaves(MF, CSRegs, PrologCSRs);
+
+  BitVector EarlyCSRs(TRI.getNumRegs(), false);
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   for (unsigned i = 0; CSRegs[i]; ++i) {
     unsigned Reg = CSRegs[i];
-    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
-      SavedRegs.set(Reg);
+    if (MRI.isPhysRegModified(Reg) && !EarlyCSRs[Reg])
+      PrologCSRs.set(Reg);
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 7290b3f67c2e3..bd5f2d3547e3b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2482,9 +2482,9 @@ void AArch64FrameLowering::determineStackHazardSlot(
   }
 }
 
-void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                                BitVector &SavedRegs,
-                                                RegScavenger *RS) const {
+void AArch64FrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                      BitVector &SavedRegs,
+                                                      RegScavenger *RS) const {
   // All calls are tail calls in GHC calling conv, and functions have no
   // prologue/epilogue.
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
@@ -2654,7 +2654,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
   }
 
   LLVM_DEBUG({
-    dbgs() << "*** determineCalleeSaves\nSaved CSRs:";
+    dbgs() << "*** determinePrologCalleeSaves\nSaved CSRs:";
     for (unsigned Reg : SavedRegs.set_bits())
       dbgs() << ' ' << printReg(MCRegister(Reg), RegInfo);
     dbgs() << "\n";
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 32a9bd831989c..6ded0e13ba22d 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -94,8 +94,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
                                    unsigned &MinCSFrameIndex,
                                    unsigned &MaxCSFrameIndex) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS) const override;
 
   /// Returns true if the target will correctly handle shrink wrapping.
   bool enableShrinkWrapping(const MachineFunction &MF) const override {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 00e0c2511aaf0..f1101605303b6 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -77,7 +77,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned TailCallReservedStack = 0;
 
   /// HasStackFrame - True if this function has a stack frame. Set by
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   bool HasStackFrame = false;
 
   /// Amount of stack frame size, not including callee-saved registers.
@@ -379,7 +379,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 #ifndef NDEBUG
     // Make sure the calculated size derived from the CalleeSavedInfo
     // equals the cached size that was calculated elsewhere (e.g. in
-    // determineCalleeSaves).
+    // determinePrologCalleeSaves).
     ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
 #endif
 
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index ffbb111d42221..cfde9651aa45f 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1691,9 +1691,9 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
 }
 
 // Only report VGPRs to generic code.
-void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                           BitVector &SavedVGPRs,
-                                           RegScavenger *RS) const {
+void SIFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                 BitVector &SavedVGPRs,
+                                                 RegScavenger *RS) const {
   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
 
   // If this is a function with the amdgpu_cs_chain[_preserve] calling
@@ -1702,7 +1702,7 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (MFI->isChainFunction() && !MF.getFrameInfo().hasTailCall())
     return;
 
-  TargetFrameLowering::determineCalleeSaves(MF, SavedVGPRs, RS);
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedVGPRs, RS);
 
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   const SIRegisterInfo *TRI = ST.getRegisterInfo();
@@ -1797,10 +1797,10 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedVGPRs.reset(Reg.first);
 }
 
-void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF,
-                                               BitVector &SavedRegs,
-                                               RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+void SIFrameLowering::determinePrologCalleeSavesSGPR(MachineFunction &MF,
+                                                     BitVector &SavedRegs,
+                                                     RegScavenger *RS) const {
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
   if (MFI->isEntryFunction())
     return;
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index a72772987262e..1d5ea69f00b42 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -30,10 +30,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
-  void determineCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
-                                RegScavenger *RS = nullptr) const;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS = nullptr) const override;
+  void determinePrologCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
+                                      RegScavenger *RS = nullptr) const;
   void determinePrologEpilogSGPRSaves(MachineFunction &MF, BitVector &SavedRegs,
                                       bool NeedExecCopyReservedReg) const;
   void emitCSRSpillStores(MachineFunction &MF, MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cbd08f0fb5dff..ad14822f89f06 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -257,7 +257,7 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSavesSGPR(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSavesSGPR(MF, SavedRegs, RS);
 
   // Add the code to save and restore the callee saved registers.
   if (!F.hasFnAttribute(Attribute::Naked)) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 9abda275d7e42..cac608d3e87be 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -388,8 +388,8 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
       SpillPhysVGPRs[Idx] = NewReg;
     }
 
-    // The generic `determineCalleeSaves` might have set the old register if it
-    // is in the CSR range.
+    // The generic `determinePrologCalleeSaves` might have set the old register
+    // if it is in the CSR range.
     SavedVGPRs.reset(Reg);
 
     for (MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 9f6a79e3210c4..83ce075dc9663 100644
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-x86

Author: Petr Penzin (ppenzin)

Changes

Replace determineCalleeSaves with determinePrologCalleeSaves, provide additional functions for other potential points of save.

This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 3 out of 5.

Co-authored-by: Mikhail Gudim <mgudim@ventanamicro.com>


Patch is 66.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170609.diff

57 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+32-3)
  • (modified) llvm/include/llvm/CodeGen/TargetRegisterInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/TargetSubtargetInfo.h (+4)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/RegisterScavenging.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp (+78-28)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+8-8)
  • (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp (+2-2)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/ARC/ARCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+8-7)
  • (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+1-1)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/AVR/AVRFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/BPF/BPFFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/CSKY/CSKYFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Lanai/LanaiFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+3-4)
  • (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/M68k/M68kFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/Mips16FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Mips/MipsSEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/PowerPC/PPCFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+33-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+3-1)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+8)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.h (+2)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.cpp (+4-5)
  • (modified) llvm/lib/Target/Sparc/SparcFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp (+6-8)
  • (modified) llvm/lib/Target/SystemZ/SystemZFrameLowering.h (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/VE/VEFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/X86/X86FrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/XCore/XCoreFrameLowering.h (+2-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp (+4-4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFrameLowering.h (+2-2)
  • (modified) llvm/test/CodeGen/AArch64/arm64-spill-lr.ll (+1-1)
  • (added) llvm/test/CodeGen/RISCV/determine-callee-saves.mir (+79)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 75696faf114cc..c04cd33b3377a 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -375,13 +375,13 @@ class LLVM_ABI TargetFrameLowering {
   virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
                                                    int FI) const;
 
-  /// Returns the callee-saved registers as computed by determineCalleeSaves
-  /// in the BitVector \p SavedRegs.
+  /// Returns the callee-saved registers as computed by
+  /// determinePrologCalleeSaves in the BitVector \p SavedRegs.
   virtual void getCalleeSaves(const MachineFunction &MF,
                                   BitVector &SavedRegs) const;
 
   /// This method determines which of the registers reported by
-  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
+  /// getMustPreserveRegisters() should actually get saved.
   /// The default implementation checks populates the \p SavedRegs bitset with
   /// all registers which are modified in the function, targets may override
   /// this function to save additional registers.
@@ -390,9 +390,38 @@ class LLVM_ABI TargetFrameLowering {
   /// This method should not be called by any passes outside of PEI, because
   /// it may change state passed in by \p MF and \p RS. The preferred
   /// interface outside PEI is getCalleeSaves.
+  LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                  "determinePrologCalleeSaves")
   virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                                     RegScavenger *RS = nullptr) const;
 
+  /// Return the list of registers which must be preserved by the function: the
+  /// value on exit must be the same as the value on entry. A register from this
+  /// list does not need to be saved / reloaded if the function did not use it.
+  const MCPhysReg *getMustPreserveRegisters(MachineFunction &MF) const;
+
+  /// This method determines which of the registers reported by
+  /// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
+  /// regardless of wheather or not they were modified by the function.
+  virtual void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const;
+
+  /// If the target has to do all saves / restores of "must preserve" registers
+  /// in prolog / epilog, this method returns empty set. Otherwise, this method
+  /// returns the difference between getMustPreserveRegisters and
+  /// determineUncondPrologCalleeSaves. These registers will be preserved by the
+  /// code optimizer and do not need to be saved in prolog.
+  virtual void determineEarlyCalleeSaves(MachineFunction &MF,
+                                         BitVector &EarlyCSRs) const;
+
+  /// This method returns those registers in the difference of
+  /// getMustPreserveRegisters and determineEarlyCalleeSaves that were modified
+  /// by the function and need to be saved in prolog.
+  virtual void determinePrologCalleeSaves(MachineFunction &MF,
+                                          BitVector &PrologCSRs,
+                                          RegScavenger *RS) const;
+
   /// processFunctionBeforeFrameFinalized - This method is called immediately
   /// before the specified function's frame layout (MF.getFrameInfo()) is
   /// finalized.  Once the frame is finalized, MO_FrameIndex operands are
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..f8453f8394ab7 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -1066,7 +1066,7 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// register is required, the first fixed stack object is reserved as its
   /// spill slot. This tells PEI not to create a new stack frame
   /// object for the given register. It should be called only after
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   virtual bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
                                     int &FrameIdx) const {
     return false;
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 6f95f0fea6441..57978c8585a6a 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -364,6 +364,10 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   }
 
   virtual bool isRegisterReservedByUser(Register R) const { return false; }
+
+  // Return true if the target can ensure before PrologEpilogInsertion that
+  // callee-saved registers are preserved.
+  virtual bool savesCSRsEarly() const { return false; }
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 41efe622417c8..2639edcfed0a2 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -681,7 +681,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSaves(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSaves(MF, SavedRegs, RS);
 
   // Assign stack slots for any callee-saved registers that must be spilled.
   assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
diff --git a/llvm/lib/CodeGen/RegisterScavenging.cpp b/llvm/lib/CodeGen/RegisterScavenging.cpp
index d8861672a348f..cc5da28a95d85 100644
--- a/llvm/lib/CodeGen/RegisterScavenging.cpp
+++ b/llvm/lib/CodeGen/RegisterScavenging.cpp
@@ -511,7 +511,7 @@ class ScavengerTest : public MachineFunctionPass {
     // well enough to initialize the scavenger with some emergency spillslots
     // for the target.
     BitVector SavedRegs;
-    TFL.determineCalleeSaves(MF, SavedRegs, &RS);
+    TFL.determinePrologCalleeSaves(MF, SavedRegs, &RS);
     TFL.processFunctionBeforeFrameFinalized(MF, &RS);
 
     // Let's scavenge the current function
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 83581052560cb..6933b7614e01d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -180,7 +180,7 @@ class ShrinkWrapImpl {
       const TargetFrameLowering *TFI =
           MachineFunc->getSubtarget().getFrameLowering();
 
-      TFI->determineCalleeSaves(*MachineFunc, SavedRegs, RS);
+      TFI->determinePrologCalleeSaves(*MachineFunc, SavedRegs, RS);
 
       for (int Reg = SavedRegs.find_first(); Reg != -1;
            Reg = SavedRegs.find_next(Reg))
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index ebf6d1a52448e..95144109ed14a 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,36 +93,20 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
     CalleeSaves.set(Info.getReg());
 }
 
+LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+                "determinePrologCalleeSaves")
 void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                                BitVector &SavedRegs,
                                                RegScavenger *RS) const {
-  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
-
-  // Resize before the early returns. Some backends expect that
-  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
-  // saved registers.
-  SavedRegs.resize(TRI.getNumRegs());
-
-  // Get the callee saved register list...
-  const MCPhysReg *CSRegs = nullptr;
-
-  // When interprocedural register allocation is enabled, callee saved register
-  // list should be empty, since caller saved registers are preferred over
-  // callee saved registers. Unless it has some risked CSR to be optimized out.
-  if (MF.getTarget().Options.EnableIPRA &&
-      isSafeForNoCSROpt(MF.getFunction()) &&
-      isProfitableForNoCSROpt(MF.getFunction()))
-    CSRegs = TRI.getIPRACSRegs(&MF);
-  else
-    CSRegs = MF.getRegInfo().getCalleeSavedRegs();
-
-  // Early exit if there are no callee saved registers.
-  if (!CSRegs || CSRegs[0] == 0)
-    return;
+  determinePrologCalleeSaves(MF, SavedRegs, RS);
+}
 
+const MCPhysReg *
+TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
   // In Naked functions we aren't going to save any registers.
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return;
+    return nullptr;
 
   // Noreturn+nounwind functions never restore CSR, so no saves are needed.
   // Purely noreturn functions may still return through throws, so those must
@@ -135,15 +119,81 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
         !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
         enableCalleeSaveSkip(MF))
-    return;
+    return nullptr;
+
+  // When interprocedural register allocation is enabled, callee saved register
+  // list should be empty, since caller saved registers are preferred over
+  // callee saved registers. Unless it has some risked CSR to be optimized out.
+  if (MF.getTarget().Options.EnableIPRA &&
+      isSafeForNoCSROpt(MF.getFunction()) &&
+      isProfitableForNoCSROpt(MF.getFunction()))
+    return TRI.getIPRACSRegs(&MF);
+  return MF.getRegInfo().getCalleeSavedRegs();
+}
 
+void TargetFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   // Functions which call __builtin_unwind_init get all their registers saved.
-  bool CallsUnwindInit = MF.callsUnwindInit();
+  if (MF.callsUnwindInit()) {
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      unsigned Reg = CSRegs[i];
+      UncondPrologCSRs.set(Reg);
+    }
+  }
+  return;
+}
+
+void TargetFrameLowering::determineEarlyCalleeSaves(
+    MachineFunction &MF, BitVector &EarlyCSRs) const {
+  const auto &ST = MF.getSubtarget();
+  if (!ST.savesCSRsEarly())
+    return;
+
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  BitVector UncondPrologCSRs(TRI.getNumRegs(), false);
+  determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+
+  EarlyCSRs.resize(TRI.getNumRegs());
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!UncondPrologCSRs[Reg])
+      EarlyCSRs.set(Reg);
+  }
+}
+
+void TargetFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                     BitVector &PrologCSRs,
+                                                     RegScavenger *RS) const {
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+
+  // Resize before the early returns. Some backends expect that
+  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
+  // saved registers.
+  PrologCSRs.resize(TRI.getNumRegs());
+
+  // Get the callee saved register list...
+  const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
+  // Early exit if there are no callee saved registers.
+  if (!CSRegs || CSRegs[0] == 0)
+    return;
+
+  determineUncondPrologCalleeSaves(MF, CSRegs, PrologCSRs);
+
+  BitVector EarlyCSRs(TRI.getNumRegs(), false);
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   for (unsigned i = 0; CSRegs[i]; ++i) {
     unsigned Reg = CSRegs[i];
-    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
-      SavedRegs.set(Reg);
+    if (MRI.isPhysRegModified(Reg) && !EarlyCSRs[Reg])
+      PrologCSRs.set(Reg);
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 7290b3f67c2e3..bd5f2d3547e3b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2482,9 +2482,9 @@ void AArch64FrameLowering::determineStackHazardSlot(
   }
 }
 
-void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                                BitVector &SavedRegs,
-                                                RegScavenger *RS) const {
+void AArch64FrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                      BitVector &SavedRegs,
+                                                      RegScavenger *RS) const {
   // All calls are tail calls in GHC calling conv, and functions have no
   // prologue/epilogue.
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
@@ -2654,7 +2654,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
   }
 
   LLVM_DEBUG({
-    dbgs() << "*** determineCalleeSaves\nSaved CSRs:";
+    dbgs() << "*** determinePrologCalleeSaves\nSaved CSRs:";
     for (unsigned Reg : SavedRegs.set_bits())
       dbgs() << ' ' << printReg(MCRegister(Reg), RegInfo);
     dbgs() << "\n";
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 32a9bd831989c..6ded0e13ba22d 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -94,8 +94,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
                                    unsigned &MinCSFrameIndex,
                                    unsigned &MaxCSFrameIndex) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS) const override;
 
   /// Returns true if the target will correctly handle shrink wrapping.
   bool enableShrinkWrapping(const MachineFunction &MF) const override {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 00e0c2511aaf0..f1101605303b6 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -77,7 +77,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned TailCallReservedStack = 0;
 
   /// HasStackFrame - True if this function has a stack frame. Set by
-  /// determineCalleeSaves().
+  /// determinePrologCalleeSaves().
   bool HasStackFrame = false;
 
   /// Amount of stack frame size, not including callee-saved registers.
@@ -379,7 +379,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 #ifndef NDEBUG
     // Make sure the calculated size derived from the CalleeSavedInfo
     // equals the cached size that was calculated elsewhere (e.g. in
-    // determineCalleeSaves).
+    // determinePrologCalleeSaves).
     ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
 #endif
 
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index ffbb111d42221..cfde9651aa45f 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1691,9 +1691,9 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
 }
 
 // Only report VGPRs to generic code.
-void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                           BitVector &SavedVGPRs,
-                                           RegScavenger *RS) const {
+void SIFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
+                                                 BitVector &SavedVGPRs,
+                                                 RegScavenger *RS) const {
   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
 
   // If this is a function with the amdgpu_cs_chain[_preserve] calling
@@ -1702,7 +1702,7 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (MFI->isChainFunction() && !MF.getFrameInfo().hasTailCall())
     return;
 
-  TargetFrameLowering::determineCalleeSaves(MF, SavedVGPRs, RS);
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedVGPRs, RS);
 
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   const SIRegisterInfo *TRI = ST.getRegisterInfo();
@@ -1797,10 +1797,10 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedVGPRs.reset(Reg.first);
 }
 
-void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF,
-                                               BitVector &SavedRegs,
-                                               RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+void SIFrameLowering::determinePrologCalleeSavesSGPR(MachineFunction &MF,
+                                                     BitVector &SavedRegs,
+                                                     RegScavenger *RS) const {
+  TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
   if (MFI->isEntryFunction())
     return;
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index a72772987262e..1d5ea69f00b42 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -30,10 +30,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
-  void determineCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
-                                RegScavenger *RS = nullptr) const;
+  void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
+                                  RegScavenger *RS = nullptr) const override;
+  void determinePrologCalleeSavesSGPR(MachineFunction &MF, BitVector &SavedRegs,
+                                      RegScavenger *RS = nullptr) const;
   void determinePrologEpilogSGPRSaves(MachineFunction &MF, BitVector &SavedRegs,
                                       bool NeedExecCopyReservedReg) const;
   void emitCSRSpillStores(MachineFunction &MF, MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cbd08f0fb5dff..ad14822f89f06 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -257,7 +257,7 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
 
   // Determine which of the registers in the callee save list should be saved.
   BitVector SavedRegs;
-  TFI->determineCalleeSavesSGPR(MF, SavedRegs, RS);
+  TFI->determinePrologCalleeSavesSGPR(MF, SavedRegs, RS);
 
   // Add the code to save and restore the callee saved registers.
   if (!F.hasFnAttribute(Attribute::Naked)) {
diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 9abda275d7e42..cac608d3e87be 100644
--- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -388,8 +388,8 @@ void SIMachineFunctionInfo::shiftWwmVGPRsToLowestRange(
       SpillPhysVGPRs[Idx] = NewReg;
     }
 
-    // The generic `determineCalleeSaves` might have set the old register if it
-    // is in the CSR range.
+    // The generic `determinePrologCalleeSaves` might have set the old register
+    // if it is in the CSR range.
     SavedVGPRs.reset(Reg);
 
     for (MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 9f6a79e3210c4..83ce075dc9663 100644
-...
[truncated]

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions cpp,h -- llvm/include/llvm/CodeGen/TargetFrameLowering.h llvm/include/llvm/CodeGen/TargetRegisterInfo.h llvm/include/llvm/CodeGen/TargetSubtargetInfo.h llvm/lib/CodeGen/PrologEpilogInserter.cpp llvm/lib/CodeGen/RegisterScavenging.cpp llvm/lib/CodeGen/ShrinkWrap.cpp llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp llvm/lib/Target/AArch64/AArch64FrameLowering.cpp llvm/lib/Target/AArch64/AArch64FrameLowering.h llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h llvm/lib/Target/AMDGPU/SIFrameLowering.cpp llvm/lib/Target/AMDGPU/SIFrameLowering.h llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp llvm/lib/Target/ARC/ARCFrameLowering.cpp llvm/lib/Target/ARC/ARCFrameLowering.h llvm/lib/Target/ARM/ARMFrameLowering.cpp llvm/lib/Target/ARM/ARMFrameLowering.h llvm/lib/Target/ARM/ARMMachineFunctionInfo.h llvm/lib/Target/AVR/AVRFrameLowering.cpp llvm/lib/Target/AVR/AVRFrameLowering.h llvm/lib/Target/BPF/BPFFrameLowering.cpp llvm/lib/Target/BPF/BPFFrameLowering.h llvm/lib/Target/CSKY/CSKYFrameLowering.cpp llvm/lib/Target/CSKY/CSKYFrameLowering.h llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp llvm/lib/Target/Hexagon/HexagonFrameLowering.h llvm/lib/Target/Lanai/LanaiFrameLowering.cpp llvm/lib/Target/Lanai/LanaiFrameLowering.h llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp llvm/lib/Target/LoongArch/LoongArchFrameLowering.h llvm/lib/Target/M68k/M68kFrameLowering.cpp llvm/lib/Target/M68k/M68kFrameLowering.h llvm/lib/Target/Mips/Mips16FrameLowering.cpp llvm/lib/Target/Mips/Mips16FrameLowering.h llvm/lib/Target/Mips/MipsSEFrameLowering.cpp llvm/lib/Target/Mips/MipsSEFrameLowering.h llvm/lib/Target/PowerPC/PPCFrameLowering.cpp llvm/lib/Target/PowerPC/PPCFrameLowering.h llvm/lib/Target/RISCV/RISCVFrameLowering.cpp llvm/lib/Target/RISCV/RISCVFrameLowering.h llvm/lib/Target/RISCV/RISCVSubtarget.cpp llvm/lib/Target/RISCV/RISCVSubtarget.h llvm/lib/Target/Sparc/SparcFrameLowering.cpp llvm/lib/Target/Sparc/SparcFrameLowering.h llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp llvm/lib/Target/SystemZ/SystemZFrameLowering.h llvm/lib/Target/VE/VEFrameLowering.cpp llvm/lib/Target/VE/VEFrameLowering.h llvm/lib/Target/X86/X86FrameLowering.cpp llvm/lib/Target/X86/X86FrameLowering.h llvm/lib/Target/XCore/XCoreFrameLowering.cpp llvm/lib/Target/XCore/XCoreFrameLowering.h llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp llvm/lib/Target/Xtensa/XtensaFrameLowering.h --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index f78037545..e56e6125e 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -34,8 +34,9 @@ using namespace llvm;
 
 static cl::opt<std::string> UserDefinedUncondPrologCSRs(
     "riscv-user-defined-uncond-prolog-csrs",
-    cl::desc("Comma-separated list of registerst that have to be saved / restored in prolog / epilog. Used for testing only"), cl::init(""),
-    cl::Hidden);
+    cl::desc("Comma-separated list of registerst that have to be saved / "
+             "restored in prolog / epilog. Used for testing only"),
+    cl::init(""), cl::Hidden);
 
 static Align getABIStackAlignment(RISCVABI::ABI ABI) {
   if (ABI == RISCVABI::ABI_ILP32E)
@@ -1535,7 +1536,9 @@ static MCRegister getRVVBaseRegister(const RISCVRegisterInfo &TRI,
 #define GET_REGISTER_MATCHER
 #include "RISCVGenAsmMatcher.inc"
 
-void RISCVFrameLowering::determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs, BitVector &UncondPrologCSRs) const {
+void RISCVFrameLowering::determineUncondPrologCalleeSaves(
+    MachineFunction &MF, const MCPhysReg *CSRegs,
+    BitVector &UncondPrologCSRs) const {
   const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
 
   StringRef RegString(UserDefinedUncondPrologCSRs);
@@ -1554,17 +1557,18 @@ void RISCVFrameLowering::determineUncondPrologCalleeSaves(MachineFunction &MF, c
     UncondPrologCSRs.set(Reg.id());
   }
 
-  TargetFrameLowering::determineUncondPrologCalleeSaves(MF, CSRegs, UncondPrologCSRs);
+  TargetFrameLowering::determineUncondPrologCalleeSaves(MF, CSRegs,
+                                                        UncondPrologCSRs);
 }
 
 void RISCVFrameLowering::determinePrologCalleeSaves(MachineFunction &MF,
-                                              BitVector &SavedRegs,
-                                              RegScavenger *RS) const {
+                                                    BitVector &SavedRegs,
+                                                    RegScavenger *RS) const {
   TargetFrameLowering::determinePrologCalleeSaves(MF, SavedRegs, RS);
 
-  // In TargetFrameLowering::determinePrologCalleeSaves, any vector register is marked
-  // as saved if any of its subregister is clobbered, this is not correct in
-  // vector registers. We only want the vector register to be marked as saved
+  // In TargetFrameLowering::determinePrologCalleeSaves, any vector register is
+  // marked as saved if any of its subregister is clobbered, this is not correct
+  // in vector registers. We only want the vector register to be marked as saved
   // if all of its subregisters are clobbered.
   // For example:
   // Original behavior: If v24 is marked, v24m2, v24m4, v24m8 are also marked.
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index b1835877e..292105ef6 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -34,10 +34,12 @@ public:
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  void determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs, BitVector &UncondPrologCSRs) const override;
+  void
+  determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+                                   BitVector &UncondPrologCSRs) const override;
 
   void determinePrologCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS) const override;
+                                  RegScavenger *RS) const override;
 
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 3dcad5273..5a0f9421b 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -76,8 +76,8 @@ static cl::opt<bool> EnablePExtCodeGen(
     cl::init(false), cl::Hidden);
 
 static cl::opt<bool> SaveCSREarly("riscv-save-csrs-early",
-                                  cl::desc("Save CSRs early"),
-                                  cl::init(false), cl::Hidden);
+                                  cl::desc("Save CSRs early"), cl::init(false),
+                                  cl::Hidden);
 
 void RISCVSubtarget::anchor() {}
 
@@ -270,6 +270,4 @@ bool RISCVSubtarget::useMIPSCCMovInsn() const {
   return UseMIPSCCMovInsn && HasVendorXMIPSCMov;
 }
 
-bool RISCVSubtarget::savesCSRsEarly() const {
-  return SaveCSREarly;
-}
+bool RISCVSubtarget::savesCSRsEarly() const { return SaveCSREarly; }

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

🐧 Linux x64 Test Results

  • 3053 tests passed
  • 7 tests skipped

All tests passed but another part of the build failed. Click on a failure below to see the details.

lib/DWARFCFIChecker/CMakeFiles/LLVMDWARFCFIChecker.dir/DWARFCFIState.cpp.o
FAILED: lib/DWARFCFIChecker/CMakeFiles/LLVMDWARFCFIChecker.dir/DWARFCFIState.cpp.o
sccache /opt/llvm/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/DWARFCFIChecker -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/DWARFCFIChecker -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT lib/DWARFCFIChecker/CMakeFiles/LLVMDWARFCFIChecker.dir/DWARFCFIState.cpp.o -MF lib/DWARFCFIChecker/CMakeFiles/LLVMDWARFCFIChecker.dir/DWARFCFIState.cpp.o.d -o lib/DWARFCFIChecker/CMakeFiles/LLVMDWARFCFIChecker.dir/DWARFCFIState.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp:67:11: error: enumeration values 'OpLLVMDefCfaRegScalableOffset', 'OpLLVMRegAtScalableOffsetFromCfa', and 'OpLLVMRegAtScalableOffsetFromReg' not handled in switch [-Werror,-Wswitch]
67 |   switch (Directive.getOperation()) {
|           ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
lib/Target/AArch64/CMakeFiles/LLVMAArch64CodeGen.dir/AArch64FrameLowering.cpp.o
FAILED: lib/Target/AArch64/CMakeFiles/LLVMAArch64CodeGen.dir/AArch64FrameLowering.cpp.o
sccache /opt/llvm/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/Target/AArch64 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/AArch64 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17 -fvisibility=hidden  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT lib/Target/AArch64/CMakeFiles/LLVMAArch64CodeGen.dir/AArch64FrameLowering.cpp.o -MF lib/Target/AArch64/CMakeFiles/LLVMAArch64CodeGen.dir/AArch64FrameLowering.cpp.o.d -o lib/Target/AArch64/CMakeFiles/LLVMAArch64CodeGen.dir/AArch64FrameLowering.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp:2495:24: error: 'determineCalleeSaves' is deprecated: Use determinePrologCalleeSaves instead [-Werror,-Wdeprecated-declarations]
2495 |   TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|                        ^~~~~~~~~~~~~~~~~~~~
|                        determinePrologCalleeSaves
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include/llvm/CodeGen/TargetFrameLowering.h:393:3: note: 'determineCalleeSaves' has been explicitly marked deprecated here
393 |   LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
|   ^
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include/llvm/Support/Compiler.h:250:50: note: expanded from macro 'LLVM_DEPRECATED'
250 | #define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX)))
|                                                  ^
1 error generated.
lib/Target/RISCV/CMakeFiles/LLVMRISCVCodeGen.dir/RISCVFrameLowering.cpp.o
FAILED: lib/Target/RISCV/CMakeFiles/LLVMRISCVCodeGen.dir/RISCVFrameLowering.cpp.o
sccache /opt/llvm/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/Target/RISCV -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/RISCV -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17 -fvisibility=hidden  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT lib/Target/RISCV/CMakeFiles/LLVMRISCVCodeGen.dir/RISCVFrameLowering.cpp.o -MF lib/Target/RISCV/CMakeFiles/LLVMRISCVCodeGen.dir/RISCVFrameLowering.cpp.o.d -o lib/Target/RISCV/CMakeFiles/LLVMRISCVCodeGen.dir/RISCVFrameLowering.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp:1539:28: error: unused variable 'TRI' [-Werror,-Wunused-variable]
1539 |   const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
|                            ^~~
1 error generated.
tools/bolt/lib/Core/CMakeFiles/LLVMBOLTCore.dir/BinaryFunction.cpp.o
FAILED: tools/bolt/lib/Core/CMakeFiles/LLVMBOLTCore.dir/BinaryFunction.cpp.o
sccache /opt/llvm/bin/clang++ -DCMAKE_INSTALL_FULL_LIBDIR=\"/home/gha/actions-runner/_work/llvm-project/llvm-project/build/install/lib\" -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/bolt/lib/Core -I/home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/lib/Core -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/bolt/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/bolt/lib/Core/CMakeFiles/LLVMBOLTCore.dir/BinaryFunction.cpp.o -MF tools/bolt/lib/Core/CMakeFiles/LLVMBOLTCore.dir/BinaryFunction.cpp.o.d -o tools/bolt/lib/Core/CMakeFiles/LLVMBOLTCore.dir/BinaryFunction.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/lib/Core/BinaryFunction.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/lib/Core/BinaryFunction.cpp:2751:13: error: enumeration values 'OpLLVMDefCfaRegScalableOffset', 'OpLLVMRegAtScalableOffsetFromCfa', and 'OpLLVMRegAtScalableOffsetFromReg' not handled in switch [-Werror,-Wswitch]
2751 |     switch (Instr.getOperation()) {
|             ^~~~~~~~~~~~~~~~~~~~
/home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/lib/Core/BinaryFunction.cpp:2878:13: error: enumeration values 'OpLLVMDefCfaRegScalableOffset', 'OpLLVMRegAtScalableOffsetFromCfa', and 'OpLLVMRegAtScalableOffsetFromReg' not handled in switch [-Werror,-Wswitch]
2878 |     switch (Instr.getOperation()) {
|             ^~~~~~~~~~~~~~~~~~~~
/home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/lib/Core/BinaryFunction.cpp:3024:13: error: enumeration values 'OpLLVMDefCfaRegScalableOffset', 'OpLLVMRegAtScalableOffsetFromCfa', and 'OpLLVMRegAtScalableOffsetFromReg' not handled in switch [-Werror,-Wswitch]
3024 |     switch (Instr.getOperation()) {
|             ^~~~~~~~~~~~~~~~~~~~
3 errors generated.

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@ppenzin ppenzin changed the title Users/ppenzin/ra saverestore split calleesaves [WIP][CodeGen] Split determineCalleeSaves Dec 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants