[llvm] [CodeGen] Refactor `determineCalleeSaves`. (PR #166763)
Mikhail Gudim via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 13:05:34 PST 2026
https://github.com/mgudim updated https://github.com/llvm/llvm-project/pull/166763
>From 9b39443179cbdb2519ef1ef00bbe33c3397102e2 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 6 Nov 2025 03:49:12 -0800
Subject: [PATCH 01/11] [CodeGen] Refactor `determineCalleeSaves`.
It is possible that target makes sure that callee-saved registers are
preserved by some way other than saving / restoring registers in prolog / epilog.
To account for this possibility we 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 / restored in prolog / epilog.
`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 / restored in prolog / epilog.
---
.../llvm/CodeGen/TargetFrameLowering.h | 31 ++++-
.../llvm/CodeGen/TargetSubtargetInfo.h | 4 +
llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp | 106 +++++++++++++-----
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 34 ++++++
llvm/lib/Target/RISCV/RISCVFrameLowering.h | 4 +
llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 6 +
llvm/lib/Target/RISCV/RISCVSubtarget.h | 2 +
.../CodeGen/RISCV/determine-callee-saves.mir | 79 +++++++++++++
8 files changed, 237 insertions(+), 29 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/determine-callee-saves.mir
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 99034754e466b..f2a4489ee9f66 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -373,7 +373,7 @@ class LLVM_ABI TargetFrameLowering {
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.
@@ -382,9 +382,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 / restored in prolog / epilog.
+ 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 / restored in prolog / epilog.
+ 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/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/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/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 92fd7283dc2cd..476117a8acd42 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -32,6 +32,12 @@
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);
+
static Align getABIStackAlignment(RISCVABI::ABI ABI) {
if (ABI == RISCVABI::ABI_ILP32E)
return Align(4);
@@ -1580,6 +1586,34 @@ static MCRegister getRVVBaseRegister(const RISCVRegisterInfo &TRI,
return BaseReg;
}
+#define GET_REGISTER_MATCHER
+#include "RISCVGenAsmMatcher.inc"
+
+void RISCVFrameLowering::determineUncondPrologCalleeSaves(
+ MachineFunction &MF, const MCPhysReg *CSRegs,
+ BitVector &UncondPrologCSRs) const {
+ const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
+
+ StringRef RegString(UserDefinedUncondPrologCSRs);
+ SmallVector<llvm::StringRef, 4> RegNames;
+ llvm::SplitString(RegString, RegNames, ",");
+ for (auto &Name : RegNames) {
+ Register Reg = MatchRegisterName(Name);
+ if (!Reg)
+ Reg = MatchRegisterAltName(Name);
+ if (!Reg) {
+ std::string msg;
+ raw_string_ostream Msg(msg);
+ Msg << "Couldn't parse register: " << Name << "\n";
+ report_fatal_error(Twine(msg));
+ }
+ UncondPrologCSRs.set(Reg.id());
+ }
+
+ TargetFrameLowering::determineUncondPrologCalleeSaves(MF, CSRegs,
+ UncondPrologCSRs);
+}
+
void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index 84e48dbc05d67..5c6b110d690fa 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -34,6 +34,10 @@ class RISCVFrameLowering : public TargetFrameLowering {
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
+ void
+ determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
+ BitVector &UncondPrologCSRs) const override;
+
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS) const override;
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index bfc8a86cbfe36..802a0da6f897c 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -76,6 +76,10 @@ static cl::opt<bool> EnablePExtSIMDCodeGen(
"where only partial codegen is currently supported)"),
cl::init(false), cl::Hidden);
+static cl::opt<bool> SaveCSREarly("riscv-save-csrs-early",
+ cl::desc("Save CSRs early"), cl::init(false),
+ cl::Hidden);
+
void RISCVSubtarget::anchor() {}
RISCVSubtarget &
@@ -296,3 +300,5 @@ bool RISCVSubtarget::useMIPSLoadStorePairs() const {
bool RISCVSubtarget::useMIPSCCMovInsn() const {
return UseMIPSCCMovInsn && HasVendorXMIPSCMov;
}
+
+bool RISCVSubtarget::savesCSRsEarly() const { return SaveCSREarly; }
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index fea9aae716fb5..56647c8485ce5 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -442,6 +442,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
void overridePostRASchedPolicy(MachineSchedPolicy &Policy,
const SchedRegion &Region) const override;
+
+ bool savesCSRsEarly() const override;
};
} // namespace llvm
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
new file mode 100644
index 0000000000000..0027e18f905e7
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
@@ -0,0 +1,79 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=false \
+# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR
+#
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=false \
+# RUN: --riscv-user-defined-uncond-prolog-csrs="x19" \
+# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR_UNCONDX19
+#
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=true \
+# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR
+#
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=true \
+# RUN: --riscv-user-defined-uncond-prolog-csrs="x19" \
+# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR_UNCONDX19
+---
+name: test0
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; NOEARLYCSR-LABEL: name: test0
+ ; NOEARLYCSR: liveins: $x10, $x18
+ ; NOEARLYCSR-NEXT: {{ $}}
+ ; NOEARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; NOEARLYCSR-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.0)
+ ; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR-NEXT: $x18 = LD $x10, 0 :: (load (s64))
+ ; NOEARLYCSR-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR-NEXT: PseudoRET
+ ;
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: test0
+ ; NOEARLYCSR_UNCONDX19: liveins: $x10, $x18, $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 0 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x10, 0 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 0 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoRET
+ ;
+ ; EARLYCSR-LABEL: name: test0
+ ; EARLYCSR: liveins: $x10
+ ; EARLYCSR-NEXT: {{ $}}
+ ; EARLYCSR-NEXT: $x18 = LD $x10, 0 :: (load (s64))
+ ; EARLYCSR-NEXT: PseudoRET
+ ;
+ ; EARLYCSR_UNCONDX19-LABEL: name: test0
+ ; EARLYCSR_UNCONDX19: liveins: $x10, $x19
+ ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x10, 0 :: (load (s64))
+ ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19-NEXT: PseudoRET
+ $x18 = LD $x10, 0 :: (load (s64))
+ PseudoRET
+
+...
>From 4a2191ee4b057c83795fed4f1e524db86c3abffa Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 6 Nov 2025 04:56:01 -0800
Subject: [PATCH 02/11] commnet out "LLVM_DEPRECATED" because otherwise build
fails.
---
llvm/include/llvm/CodeGen/TargetFrameLowering.h | 4 ++--
llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index f2a4489ee9f66..bbd285dfcf227 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -382,8 +382,8 @@ 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")
+ // LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+ // "determinePrologCalleeSaves")
virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS = nullptr) const;
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index 95144109ed14a..b56794f4c88d7 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -93,8 +93,8 @@ void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
CalleeSaves.set(Info.getReg());
}
-LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
- "determinePrologCalleeSaves")
+// LLVM_DEPRECATED("Use determinePrologCalleeSaves instead",
+// "determinePrologCalleeSaves")
void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
>From b88a57b16df5301482b9c17eec383a96c62351f8 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 6 Nov 2025 05:12:24 -0800
Subject: [PATCH 03/11] fixed a warning
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 476117a8acd42..125e7bd59c46d 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1592,7 +1592,6 @@ static MCRegister getRVVBaseRegister(const RISCVRegisterInfo &TRI,
void RISCVFrameLowering::determineUncondPrologCalleeSaves(
MachineFunction &MF, const MCPhysReg *CSRegs,
BitVector &UncondPrologCSRs) const {
- const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
StringRef RegString(UserDefinedUncondPrologCSRs);
SmallVector<llvm::StringRef, 4> RegNames;
>From a0e17b004c2f02b88e04b2182b72947040e1b2d4 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 6 Nov 2025 06:07:19 -0800
Subject: [PATCH 04/11] updated test
---
.../CodeGen/RISCV/determine-callee-saves.mir | 46 ++++++++++++-------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
index 0027e18f905e7..ada45b172ce9a 100644
--- a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
@@ -19,6 +19,10 @@
---
name: test0
tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body: |
bb.0.entry:
liveins: $x10
@@ -27,10 +31,10 @@ body: |
; NOEARLYCSR-NEXT: {{ $}}
; NOEARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; NOEARLYCSR-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.0)
+ ; NOEARLYCSR-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.1)
; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
- ; NOEARLYCSR-NEXT: $x18 = LD $x10, 0 :: (load (s64))
- ; NOEARLYCSR-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; NOEARLYCSR-NEXT: $x18 = LD $x2, 4 :: (load (s64))
+ ; NOEARLYCSR-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
; NOEARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
@@ -39,25 +43,32 @@ body: |
; NOEARLYCSR_UNCONDX19-LABEL: name: test0
; NOEARLYCSR_UNCONDX19: liveins: $x10, $x18, $x19
; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.0)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 0 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x10, 0 :: (load (s64))
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
- ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 0 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 12 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; NOEARLYCSR_UNCONDX19-NEXT: PseudoRET
;
; EARLYCSR-LABEL: name: test0
; EARLYCSR: liveins: $x10
; EARLYCSR-NEXT: {{ $}}
- ; EARLYCSR-NEXT: $x18 = LD $x10, 0 :: (load (s64))
+ ; EARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR-NEXT: BUNDLE implicit-def $x18 {
+ ; EARLYCSR-NEXT: $x18 = LD %stack.0, 0 :: (load (s64))
+ ; EARLYCSR-NEXT: CFI_INSTRUCTION register $x18, $x18
+ ; EARLYCSR-NEXT: }
+ ; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR-NEXT: PseudoRET
;
; EARLYCSR_UNCONDX19-LABEL: name: test0
@@ -65,15 +76,18 @@ body: |
; EARLYCSR_UNCONDX19-NEXT: {{ $}}
; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x10, 0 :: (load (s64))
- ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: BUNDLE implicit-def $x18 {
+ ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD %stack.0, 0 :: (load (s64))
+ ; EARLYCSR_UNCONDX19-NEXT: CFI_INSTRUCTION register $x18, $x18
+ ; EARLYCSR_UNCONDX19-NEXT: }
+ ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR_UNCONDX19-NEXT: PseudoRET
- $x18 = LD $x10, 0 :: (load (s64))
+ $x18 = LD %stack.0, 0 :: (load (s64))
PseudoRET
...
>From c4e025e40aa87d7bd2462ac101c57e7c2d2481e6 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Fri, 7 Nov 2025 06:16:38 -0800
Subject: [PATCH 05/11] addressed review comments and fixed a test.
---
llvm/include/llvm/CodeGen/TargetFrameLowering.h | 2 +-
llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp | 6 +++---
llvm/test/CodeGen/RISCV/determine-callee-saves.mir | 10 ++--------
3 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index bbd285dfcf227..a85c1903cde68 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -390,7 +390,7 @@ class LLVM_ABI TargetFrameLowering {
/// 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;
+ const MCPhysReg *getMustPreserveRegisters(const MachineFunction &MF) const;
/// This method determines which of the registers reported by
/// getMustPreserveRegisters() must be saved in prolog and reloaded in epilog
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index b56794f4c88d7..8765837c76161 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -102,7 +102,7 @@ void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
}
const MCPhysReg *
-TargetFrameLowering::getMustPreserveRegisters(MachineFunction &MF) const {
+TargetFrameLowering::getMustPreserveRegisters(const 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))
@@ -146,11 +146,11 @@ void TargetFrameLowering::determineUncondPrologCalleeSaves(
void TargetFrameLowering::determineEarlyCalleeSaves(
MachineFunction &MF, BitVector &EarlyCSRs) const {
- const auto &ST = MF.getSubtarget();
+ const TargetSubtargetInfo &ST = MF.getSubtarget();
if (!ST.savesCSRsEarly())
return;
- const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+ const TargetRegisterInfo &TRI = *ST.getRegisterInfo();
// Get the callee saved register list...
const MCPhysReg *CSRegs = getMustPreserveRegisters(MF);
// Early exit if there are no callee saved registers.
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
index ada45b172ce9a..6d4e238f4fbef 100644
--- a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
@@ -63,10 +63,7 @@ body: |
; EARLYCSR-NEXT: {{ $}}
; EARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
; EARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR-NEXT: BUNDLE implicit-def $x18 {
- ; EARLYCSR-NEXT: $x18 = LD %stack.0, 0 :: (load (s64))
- ; EARLYCSR-NEXT: CFI_INSTRUCTION register $x18, $x18
- ; EARLYCSR-NEXT: }
+ ; EARLYCSR-NEXT: $x18 = LD $x2, 12 :: (load (s64))
; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR-NEXT: PseudoRET
@@ -78,10 +75,7 @@ body: |
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: BUNDLE implicit-def $x18 {
- ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD %stack.0, 0 :: (load (s64))
- ; EARLYCSR_UNCONDX19-NEXT: CFI_INSTRUCTION register $x18, $x18
- ; EARLYCSR_UNCONDX19-NEXT: }
+ ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 4 :: (load (s64))
; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
>From 0c07d9382b05636778dcd57e561d6a3bb0310627 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Mon, 15 Dec 2025 17:07:14 -0500
Subject: [PATCH 06/11] addressed review comments.
---
.../CodeGen/RISCV/determine-callee-saves.mir | 144 ++++++++++++++++--
1 file changed, 134 insertions(+), 10 deletions(-)
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
index 6d4e238f4fbef..dca4a235b823e 100644
--- a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
@@ -16,31 +16,51 @@
# RUN: --riscv-save-csrs-early=true \
# RUN: --riscv-user-defined-uncond-prolog-csrs="x19" \
# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR_UNCONDX19
+--- |
+ define void @use_callee_saved() {
+ entry:
+ ret void
+ }
+
+ define void @make_a_call() {
+ entry:
+ tail call void @bar()
+ ret void
+ }
+
+ define void @make_a_call_and_use_callee_saved() {
+ entry:
+ tail call void @bar()
+ ret void
+ }
+
+ declare void @bar(...)
+...
---
-name: test0
+name: use_callee_saved
tracksRegLiveness: true
stack:
- - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+ - { id: 0, name: '', type: default, offset: 0, size: 8, alignment: 8,
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body: |
bb.0.entry:
liveins: $x10
- ; NOEARLYCSR-LABEL: name: test0
+ ; NOEARLYCSR-LABEL: name: use_callee_saved
; NOEARLYCSR: liveins: $x10, $x18
; NOEARLYCSR-NEXT: {{ $}}
; NOEARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
; NOEARLYCSR-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.1)
; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
- ; NOEARLYCSR-NEXT: $x18 = LD $x2, 4 :: (load (s64))
+ ; NOEARLYCSR-NEXT: $x18 = LD $x2, 0 :: (load (s64))
; NOEARLYCSR-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
; NOEARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; NOEARLYCSR-NEXT: PseudoRET
;
- ; NOEARLYCSR_UNCONDX19-LABEL: name: test0
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: use_callee_saved
; NOEARLYCSR_UNCONDX19: liveins: $x10, $x18, $x19
; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
@@ -49,7 +69,7 @@ body: |
; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 12 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
@@ -58,24 +78,24 @@ body: |
; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; NOEARLYCSR_UNCONDX19-NEXT: PseudoRET
;
- ; EARLYCSR-LABEL: name: test0
+ ; EARLYCSR-LABEL: name: use_callee_saved
; EARLYCSR: liveins: $x10
; EARLYCSR-NEXT: {{ $}}
; EARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
; EARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR-NEXT: $x18 = LD $x2, 12 :: (load (s64))
+ ; EARLYCSR-NEXT: $x18 = LD $x2, 8 :: (load (s64))
; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR-NEXT: PseudoRET
;
- ; EARLYCSR_UNCONDX19-LABEL: name: test0
+ ; EARLYCSR_UNCONDX19-LABEL: name: use_callee_saved
; EARLYCSR_UNCONDX19: liveins: $x10, $x19
; EARLYCSR_UNCONDX19-NEXT: {{ $}}
; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 4 :: (load (s64))
+ ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 0 :: (load (s64))
; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
@@ -85,3 +105,107 @@ body: |
PseudoRET
...
+---
+name: make_a_call
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ ; NOEARLYCSR-LABEL: name: make_a_call
+ ; NOEARLYCSR: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call
+ ; NOEARLYCSR_UNCONDX19: liveins: $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR-LABEL: name: make_a_call
+ ; EARLYCSR: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR_UNCONDX19-LABEL: name: make_a_call
+ ; EARLYCSR_UNCONDX19: liveins: $x19
+ ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+
+...
+---
+name: make_a_call_and_use_callee_saved
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0.entry:
+ ; NOEARLYCSR-LABEL: name: make_a_call_and_use_callee_saved
+ ; NOEARLYCSR: liveins: $x18
+ ; NOEARLYCSR-NEXT: {{ $}}
+ ; NOEARLYCSR-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; NOEARLYCSR-NEXT: frame-setup SD killed $x18, $x2, 8 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR-NEXT: $x18 = LD $x2, 0 :: (load (s64))
+ ; NOEARLYCSR-NEXT: $x18 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call_and_use_callee_saved
+ ; NOEARLYCSR_UNCONDX19: liveins: $x18, $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR-LABEL: name: make_a_call_and_use_callee_saved
+ ; EARLYCSR: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR-NEXT: $x18 = LD $x2, 8 :: (load (s64))
+ ; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR_UNCONDX19-LABEL: name: make_a_call_and_use_callee_saved
+ ; EARLYCSR_UNCONDX19: liveins: $x19
+ ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 0 :: (load (s64))
+ ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ $x18 = LD %stack.0, 0 :: (load (s64))
+ PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+...
>From 296d15e40097559c97564be6d79209839b34c12b Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 16 Dec 2025 10:09:07 -0500
Subject: [PATCH 07/11] addressed review comments.
---
llvm/include/llvm/CodeGen/TargetFrameLowering.h | 2 +-
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index a85c1903cde68..b04d9a10e3caf 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -394,7 +394,7 @@ class LLVM_ABI TargetFrameLowering {
/// 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.
+ /// regardless of whether or not they were modified by the function.
virtual void
determineUncondPrologCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs,
BitVector &UncondPrologCSRs) const;
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 125e7bd59c46d..e8b4c608f158c 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1604,7 +1604,7 @@ void RISCVFrameLowering::determineUncondPrologCalleeSaves(
std::string msg;
raw_string_ostream Msg(msg);
Msg << "Couldn't parse register: " << Name << "\n";
- report_fatal_error(Twine(msg));
+ reportFatalUsageError(Twine(msg));
}
UncondPrologCSRs.set(Reg.id());
}
>From 07410fc6b279479fc26fda4ad27e7087362c53c3 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 16 Dec 2025 11:08:53 -0500
Subject: [PATCH 08/11] addressed review commits.
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index e8b4c608f158c..1aee650d6d0b3 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -34,9 +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 / "
+ cl::desc("Comma-separated list of registers that have to be saved / "
"restored in prolog / epilog. Used for testing only"),
- cl::init(""), cl::Hidden);
+ cl::init(""), cl::ReallyHidden);
static Align getABIStackAlignment(RISCVABI::ABI ABI) {
if (ABI == RISCVABI::ABI_ILP32E)
>From 0ffd8aed91c7e6d7e8d80fe622335e55a3b500f7 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 16 Dec 2025 15:21:33 -0500
Subject: [PATCH 09/11] addressed review comments.
---
llvm/include/llvm/CodeGen/TargetSubtargetInfo.h | 6 ++++--
llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp | 4 ++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 57978c8585a6a..bc3682fcb1be9 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -365,8 +365,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.
+ /// Returns `true` is the target must ensure that the registers returned by
+ /// TargetFrameLowering::determineEarlyCalleeSaves are preserved before
+ /// `PrologEpilogInserter`. Also see comments for
+ /// `TargetFrameLowering::determinePrologCalleeSaves`.
virtual bool savesCSRsEarly() const { return false; }
};
} // end namespace llvm
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index 8765837c76161..2cde68c0d3a94 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -137,7 +137,7 @@ void TargetFrameLowering::determineUncondPrologCalleeSaves(
// Functions which call __builtin_unwind_init get all their registers saved.
if (MF.callsUnwindInit()) {
for (unsigned i = 0; CSRegs[i]; ++i) {
- unsigned Reg = CSRegs[i];
+ MCRegister Reg = CSRegs[i];
UncondPrologCSRs.set(Reg);
}
}
@@ -162,7 +162,7 @@ void TargetFrameLowering::determineEarlyCalleeSaves(
EarlyCSRs.resize(TRI.getNumRegs());
for (unsigned i = 0; CSRegs[i]; ++i) {
- unsigned Reg = CSRegs[i];
+ MCRegister Reg = CSRegs[i];
if (!UncondPrologCSRs[Reg])
EarlyCSRs.set(Reg);
}
>From e659d8306d529f8f0bedd3002599e99215d6c214 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 16 Dec 2025 15:29:38 -0500
Subject: [PATCH 10/11] use twine to report error.
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 1aee650d6d0b3..0e8d935eefd04 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1601,10 +1601,7 @@ void RISCVFrameLowering::determineUncondPrologCalleeSaves(
if (!Reg)
Reg = MatchRegisterAltName(Name);
if (!Reg) {
- std::string msg;
- raw_string_ostream Msg(msg);
- Msg << "Couldn't parse register: " << Name << "\n";
- reportFatalUsageError(Twine(msg));
+ reportFatalUsageError(Twine("Couldn't parse register: ") + Name + "\n");
}
UncondPrologCSRs.set(Reg.id());
}
>From 9a4a2d7b88c58286f0904869bcf273e5746577e6 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at qti.qualcomm.com>
Date: Wed, 7 Jan 2026 14:21:35 -0800
Subject: [PATCH 11/11] use function attribute instead of cli option
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 13 +-
.../RISCV/determine-callee-saves-uncond.mir | 152 ++++++++++++++++++
.../CodeGen/RISCV/determine-callee-saves.mir | 106 +-----------
3 files changed, 162 insertions(+), 109 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/determine-callee-saves-uncond.mir
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 0e8d935eefd04..39b8c784de52e 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -32,12 +32,6 @@
using namespace llvm;
-static cl::opt<std::string> UserDefinedUncondPrologCSRs(
- "riscv-user-defined-uncond-prolog-csrs",
- cl::desc("Comma-separated list of registers that have to be saved / "
- "restored in prolog / epilog. Used for testing only"),
- cl::init(""), cl::ReallyHidden);
-
static Align getABIStackAlignment(RISCVABI::ABI ABI) {
if (ABI == RISCVABI::ABI_ILP32E)
return Align(4);
@@ -1593,7 +1587,12 @@ void RISCVFrameLowering::determineUncondPrologCalleeSaves(
MachineFunction &MF, const MCPhysReg *CSRegs,
BitVector &UncondPrologCSRs) const {
- StringRef RegString(UserDefinedUncondPrologCSRs);
+ const Function &F = MF.getFunction();
+ if (!F.hasFnAttribute("riscv-user-defined-uncond-prolog-csrs"))
+ return;
+ const AttributeList &Attrs = F.getAttributes();
+ StringRef RegString = Attrs.getFnAttr("riscv-user-defined-uncond-prolog-csrs")
+ .getValueAsString();
SmallVector<llvm::StringRef, 4> RegNames;
llvm::SplitString(RegString, RegNames, ",");
for (auto &Name : RegNames) {
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves-uncond.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves-uncond.mir
new file mode 100644
index 0000000000000..a1ab469ddc4c0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves-uncond.mir
@@ -0,0 +1,152 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=false \
+# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR_UNCONDX19
+
+# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
+# RUN: --riscv-save-csrs-early=true \
+# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR_UNCONDX19-
+
+--- |
+ define void @use_callee_saved() #0 {
+ entry:
+ ret void
+ }
+
+ define void @make_a_call() #0 {
+ entry:
+ tail call void @bar()
+ ret void
+ }
+
+ define void @make_a_call_and_use_callee_saved() #0 {
+ entry:
+ tail call void @bar()
+ ret void
+ }
+
+ attributes #0 = {"riscv-user-defined-uncond-prolog-csrs"="x19"}
+ declare void @bar(...)
+...
+---
+name: use_callee_saved
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: use_callee_saved
+ ; NOEARLYCSR_UNCONDX19: liveins: $x10, $x18, $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoRET
+ ;
+ ; EARLYCSR_UNCONDX19--LABEL: name: use_callee_saved
+ ; EARLYCSR_UNCONDX19-: liveins: $x10, $x19
+ ; EARLYCSR_UNCONDX19--NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19--NEXT: $x18 = LD $x2, 0 :: (load (s64))
+ ; EARLYCSR_UNCONDX19--NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19--NEXT: PseudoRET
+ $x18 = LD %stack.0, 0 :: (load (s64))
+ PseudoRET
+
+...
+---
+name: make_a_call
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call
+ ; NOEARLYCSR_UNCONDX19: liveins: $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR_UNCONDX19--LABEL: name: make_a_call
+ ; EARLYCSR_UNCONDX19-: liveins: $x19
+ ; EARLYCSR_UNCONDX19--NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19--NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19--NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+
+...
+---
+name: make_a_call_and_use_callee_saved
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: default, offset: 0, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0.entry:
+ ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call_and_use_callee_saved
+ ; NOEARLYCSR_UNCONDX19: liveins: $x18, $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
+ ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ ;
+ ; EARLYCSR_UNCONDX19--LABEL: name: make_a_call_and_use_callee_saved
+ ; EARLYCSR_UNCONDX19-: liveins: $x19
+ ; EARLYCSR_UNCONDX19--NEXT: {{ $}}
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
+ ; EARLYCSR_UNCONDX19--NEXT: $x18 = LD $x2, 0 :: (load (s64))
+ ; EARLYCSR_UNCONDX19--NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; EARLYCSR_UNCONDX19--NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; EARLYCSR_UNCONDX19--NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; EARLYCSR_UNCONDX19--NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+ $x18 = LD %stack.0, 0 :: (load (s64))
+ PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
+...
diff --git a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
index dca4a235b823e..68372d7342ad0 100644
--- a/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
+++ b/llvm/test/CodeGen/RISCV/determine-callee-saves.mir
@@ -1,21 +1,13 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+
# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
# RUN: --riscv-save-csrs-early=false \
-# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR
-#
-# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
-# RUN: --riscv-save-csrs-early=false \
-# RUN: --riscv-user-defined-uncond-prolog-csrs="x19" \
-# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR_UNCONDX19
-#
+# RUN: -o - | FileCheck %s -check-prefixes=NOEARLYCSR
+
# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
# RUN: --riscv-save-csrs-early=true \
# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR
-#
-# RUN: llc %s -mtriple=riscv64 -run-pass=prologepilog \
-# RUN: --riscv-save-csrs-early=true \
-# RUN: --riscv-user-defined-uncond-prolog-csrs="x19" \
-# RUN: -o - | FileCheck %s -check-prefixes=EARLYCSR_UNCONDX19
+
--- |
define void @use_callee_saved() {
entry:
@@ -60,24 +52,6 @@ body: |
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; NOEARLYCSR-NEXT: PseudoRET
;
- ; NOEARLYCSR_UNCONDX19-LABEL: name: use_callee_saved
- ; NOEARLYCSR_UNCONDX19: liveins: $x10, $x18, $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
- ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; NOEARLYCSR_UNCONDX19-NEXT: PseudoRET
- ;
; EARLYCSR-LABEL: name: use_callee_saved
; EARLYCSR: liveins: $x10
; EARLYCSR-NEXT: {{ $}}
@@ -87,20 +61,6 @@ body: |
; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR-NEXT: PseudoRET
- ;
- ; EARLYCSR_UNCONDX19-LABEL: name: use_callee_saved
- ; EARLYCSR_UNCONDX19: liveins: $x10, $x19
- ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 0 :: (load (s64))
- ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; EARLYCSR_UNCONDX19-NEXT: PseudoRET
$x18 = LD %stack.0, 0 :: (load (s64))
PseudoRET
@@ -113,34 +73,8 @@ body: |
; NOEARLYCSR-LABEL: name: make_a_call
; NOEARLYCSR: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
;
- ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call
- ; NOEARLYCSR_UNCONDX19: liveins: $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
- ;
; EARLYCSR-LABEL: name: make_a_call
; EARLYCSR: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
- ;
- ; EARLYCSR_UNCONDX19-LABEL: name: make_a_call
- ; EARLYCSR_UNCONDX19: liveins: $x19
- ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.0)
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.0)
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; EARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
...
@@ -167,24 +101,6 @@ body: |
; NOEARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; NOEARLYCSR-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
;
- ; NOEARLYCSR_UNCONDX19-LABEL: name: make_a_call_and_use_callee_saved
- ; NOEARLYCSR_UNCONDX19: liveins: $x18, $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x18, $x2, 24 :: (store (s64) into %stack.1)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 16 :: (store (s64) into %stack.2)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -8
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -16
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 8 :: (load (s64))
- ; NOEARLYCSR_UNCONDX19-NEXT: $x18 = frame-destroy LD $x2, 24 :: (load (s64) from %stack.1)
- ; NOEARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 16 :: (load (s64) from %stack.2)
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; NOEARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 32
- ; NOEARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; NOEARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
- ;
; EARLYCSR-LABEL: name: make_a_call_and_use_callee_saved
; EARLYCSR: $x2 = frame-setup ADDI $x2, -16
; EARLYCSR-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
@@ -192,20 +108,6 @@ body: |
; EARLYCSR-NEXT: $x2 = frame-destroy ADDI $x2, 16
; EARLYCSR-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
; EARLYCSR-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
- ;
- ; EARLYCSR_UNCONDX19-LABEL: name: make_a_call_and_use_callee_saved
- ; EARLYCSR_UNCONDX19: liveins: $x19
- ; EARLYCSR_UNCONDX19-NEXT: {{ $}}
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-setup ADDI $x2, -16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup SD killed $x19, $x2, 8 :: (store (s64) into %stack.1)
- ; EARLYCSR_UNCONDX19-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -8
- ; EARLYCSR_UNCONDX19-NEXT: $x18 = LD $x2, 0 :: (load (s64))
- ; EARLYCSR_UNCONDX19-NEXT: $x19 = frame-destroy LD $x2, 8 :: (load (s64) from %stack.1)
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; EARLYCSR_UNCONDX19-NEXT: $x2 = frame-destroy ADDI $x2, 16
- ; EARLYCSR_UNCONDX19-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; EARLYCSR_UNCONDX19-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
$x18 = LD %stack.0, 0 :: (load (s64))
PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32d_lp64d, implicit $x2
...
More information about the llvm-commits
mailing list