Skip to content

Conversation

@ppenzin
Copy link
Contributor

@ppenzin ppenzin commented Dec 4, 2025

Add ability to emit CFIs if the registers were saved / restored before prolog / epilog insertion.

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

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

Add ability to emit CFIs if the registers were saved / restored
before prolog / epilog insertion.
@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-backend-risc-v

Author: Petr Penzin (ppenzin)

Changes

Add ability to emit CFIs if the registers were saved / restored before prolog / epilog insertion.

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

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


Full diff: https://github.com/llvm/llvm-project/pull/170610.diff

8 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetFrameLowering.h (+17-10)
  • (modified) llvm/lib/CodeGen/PrologEpilogInserter.cpp (+15-3)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+149)
  • (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+2)
  • (modified) llvm/lib/Target/RISCV/RISCVSubtarget.cpp (+7-8)
  • (modified) llvm/test/CodeGen/RISCV/O0-pipeline.ll (+1)
  • (modified) llvm/test/CodeGen/RISCV/O3-pipeline.ll (+1)
  • (added) llvm/test/CodeGen/RISCV/emit-early-cfis.mir (+108)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index c04cd33b3377a..fe3ebcd13b2bc 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -25,16 +25,17 @@ namespace llvm {
   class CalleeSavedInfo;
   class MachineFunction;
   class RegScavenger;
-
-namespace TargetStackID {
-enum Value {
-  Default = 0,
-  SGPRSpill = 1,
-  ScalableVector = 2,
-  WasmLocal = 3,
-  ScalablePredicateVector = 4,
-  NoAlloc = 255
-};
+  class ReachingDefInfo;
+
+  namespace TargetStackID {
+  enum Value {
+    Default = 0,
+    SGPRSpill = 1,
+    ScalableVector = 2,
+    WasmLocal = 3,
+    ScalablePredicateVector = 4,
+    NoAlloc = 255
+  };
 }
 
 /// Information about stack frame layout on the target.  It holds the direction
@@ -212,6 +213,12 @@ class LLVM_ABI TargetFrameLowering {
   /// for noreturn nounwind functions.
   virtual bool enableCalleeSaveSkip(const MachineFunction &MF) const;
 
+  /// If savesCSRsEarly is true, we don't really know where the CSRs are
+  /// saved. This function calculates where each CSR is at every point in the
+  /// function and inserts necessary CFIs. It has to run before frame indicies
+  /// are resolved.
+  virtual void emitCFIsEarly(MachineFunction &MF, ReachingDefInfo &RDA) const {}
+
   /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
   /// the function.
   virtual void emitPrologue(MachineFunction &MF,
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 2639edcfed0a2..b97c5cd4e98d5 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -36,6 +36,7 @@
 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/PEI.h"
+#include "llvm/CodeGen/ReachingDefAnalysis.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/CodeGen/TargetFrameLowering.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
@@ -79,6 +80,7 @@ namespace {
 
 class PEIImpl {
   RegScavenger *RS = nullptr;
+  ReachingDefInfo &RDI;
 
   // MinCSFrameIndex, MaxCSFrameIndex - Keeps the range of callee saved
   // stack frame indexes.
@@ -125,7 +127,8 @@ class PEIImpl {
   void insertZeroCallUsedRegs(MachineFunction &MF);
 
 public:
-  PEIImpl(MachineOptimizationRemarkEmitter *ORE) : ORE(ORE) {}
+  PEIImpl(ReachingDefInfo &RDI, MachineOptimizationRemarkEmitter *ORE)
+      : RDI(RDI), ORE(ORE) {}
   bool run(MachineFunction &MF);
 };
 
@@ -155,6 +158,7 @@ INITIALIZE_PASS_BEGIN(PEILegacy, DEBUG_TYPE, "Prologue/Epilogue Insertion",
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineOptimizationRemarkEmitterPass)
+INITIALIZE_PASS_DEPENDENCY(ReachingDefInfoWrapperPass)
 INITIALIZE_PASS_END(PEILegacy, DEBUG_TYPE,
                     "Prologue/Epilogue Insertion & Frame Finalization", false,
                     false)
@@ -171,6 +175,7 @@ void PEILegacy::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addPreserved<MachineLoopInfoWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineOptimizationRemarkEmitterPass>();
+  AU.addRequired<ReachingDefInfoWrapperPass>();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
@@ -361,7 +366,8 @@ bool PEIImpl::run(MachineFunction &MF) {
 bool PEILegacy::runOnMachineFunction(MachineFunction &MF) {
   MachineOptimizationRemarkEmitter *ORE =
       &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
-  return PEIImpl(ORE).run(MF);
+  auto &RDI = getAnalysis<ReachingDefInfoWrapperPass>().getRDI();
+  return PEIImpl(RDI, ORE).run(MF);
 }
 
 PreservedAnalyses
@@ -369,7 +375,8 @@ PrologEpilogInserterPass::run(MachineFunction &MF,
                               MachineFunctionAnalysisManager &MFAM) {
   MachineOptimizationRemarkEmitter &ORE =
       MFAM.getResult<MachineOptimizationRemarkEmitterAnalysis>(MF);
-  if (!PEIImpl(&ORE).run(MF))
+  auto &RDI = MFAM.getResult<ReachingDefAnalysis>(MF);
+  if (!PEIImpl(RDI, &ORE).run(MF))
     return PreservedAnalyses::all();
 
   return getMachineFunctionPassPreservedAnalyses()
@@ -1188,6 +1195,11 @@ void PEIImpl::calculateFrameObjectOffsets(MachineFunction &MF) {
 void PEIImpl::insertPrologEpilogCode(MachineFunction &MF) {
   const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
 
+  if (MF.getSubtarget().savesCSRsEarly()) {
+    RDI.reset();
+    TFI.emitCFIsEarly(MF, RDI);
+  }
+
   // Add prologue to the function...
   for (MachineBasicBlock *SaveBlock : SaveBlocks)
     TFI.emitPrologue(MF, *SaveBlock);
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index f780375454b2a..17f4d0beabe31 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -14,6 +14,7 @@
 #include "MCTargetDesc/RISCVBaseInfo.h"
 #include "RISCVMachineFunctionInfo.h"
 #include "RISCVSubtarget.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/CodeGen/CFIInstBuilder.h"
 #include "llvm/CodeGen/LivePhysRegs.h"
@@ -21,6 +22,7 @@
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/ReachingDefAnalysis.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/MC/MCDwarf.h"
@@ -2379,6 +2381,153 @@ bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
   return SuccMBB->isReturnBlock() && SuccMBB->size() == 1;
 }
 
+struct CFIBuildInfo {
+  MachineBasicBlock *MBB;
+  MachineInstr *InsertAfterMI; // nullptr means insert at MBB.begin()
+  DebugLoc DL;
+  unsigned CFIIndex;
+};
+
+class EarlyCFIEmitter {
+public:
+  EarlyCFIEmitter(MachineFunction &MF_, const ReachingDefInfo &RDI_,
+                  const RISCVInstrInfo &TII_, const RISCVRegisterInfo &TRI_,
+                  const RISCVFrameLowering &TFI_)
+      : MF{MF_}, RDI{RDI_}, TII{TII_}, TRI{TRI_}, TFI{TFI_} {};
+  void trackRegisterAndEmitCFIs(
+      Register Reg, int64_t DwarfEHRegNum, MachineInstr &MI,
+      SmallVectorImpl<CFIBuildInfo> &CFIBuildInfos,
+      SmallPtrSetImpl<MachineInstr *> &VisitedRestorePoints,
+      SmallPtrSetImpl<MachineInstr *> &VisitedDefs);
+
+private:
+  MachineFunction &MF;
+  const ReachingDefInfo &RDI;
+  const RISCVInstrInfo &TII;
+  const RISCVRegisterInfo &TRI;
+  const RISCVFrameLowering &TFI;
+};
+
+void EarlyCFIEmitter::trackRegisterAndEmitCFIs(
+    Register Reg, int64_t DwarfEHRegNum, MachineInstr &MI,
+    SmallVectorImpl<CFIBuildInfo> &CFIBuildInfos,
+    SmallPtrSetImpl<MachineInstr *> &VisitedRestorePoints,
+    SmallPtrSetImpl<MachineInstr *> &VisitedDefs) {
+  if (VisitedRestorePoints.find(&MI) != VisitedRestorePoints.end())
+    return;
+  VisitedRestorePoints.insert(&MI);
+
+  SmallPtrSet<MachineInstr *, 2> Defs;
+  RDI.getGlobalReachingDefs(&MI, Reg, Defs);
+  if (Defs.empty())
+    // it's a live-in register at the entry block.
+    return;
+
+  int FrameIndex = std::numeric_limits<int>::min();
+  for (MachineInstr *Def : Defs) {
+    if (VisitedDefs.find(Def) != VisitedDefs.end())
+      continue;
+    VisitedDefs.insert(Def);
+
+    MachineBasicBlock &MBB = *Def->getParent();
+    const DebugLoc &DL = Def->getDebugLoc();
+
+    if (Register StoredReg = TII.isStoreToStackSlot(*Def, FrameIndex)) {
+      assert(FrameIndex == Reg.stackSlotIndex());
+
+      Register FrameReg;
+      StackOffset Offset = TFI.getFrameIndexReference(MF, FrameIndex, FrameReg);
+      int64_t FixedOffset = Offset.getFixed();
+      int64_t ScalableOffset = Offset.getScalable();
+
+      std::string CommentBuffer;
+      llvm::raw_string_ostream Comment(CommentBuffer);
+      int DwarfEHFrameReg = TRI.getDwarfRegNum(FrameReg, true);
+      Register LLVMReg = *TRI.getLLVMRegNum(DwarfEHRegNum, true);
+      Comment << printReg(LLVMReg, &TRI) << " @";
+      Comment << printReg(FrameReg, &TRI) << " + ";
+      Comment << "vlenb * " << ScalableOffset << " + ";
+      Comment << FixedOffset;
+      unsigned CFIIndex = MF.addFrameInst(
+          MCCFIInstruction::createLLVMRegAtScalableOffsetFromReg(
+              nullptr, DwarfEHRegNum, DwarfEHFrameReg, ScalableOffset,
+              FixedOffset, SMLoc(), Comment.str()));
+
+      CFIBuildInfos.push_back({&MBB, Def, DL, CFIIndex});
+      trackRegisterAndEmitCFIs(StoredReg, DwarfEHRegNum, *Def, CFIBuildInfos,
+                               VisitedRestorePoints, VisitedDefs);
+    } else if (Register LoadedReg = TII.isLoadFromStackSlot(*Def, FrameIndex)) {
+      assert(LoadedReg == Reg);
+
+      unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRegister(
+          nullptr, DwarfEHRegNum, TRI.getDwarfRegNum(LoadedReg, true)));
+      CFIBuildInfos.push_back({&MBB, Def, DL, CFIIndex});
+      trackRegisterAndEmitCFIs(Register::index2StackSlot(FrameIndex),
+                               DwarfEHRegNum, *Def, CFIBuildInfos,
+                               VisitedRestorePoints, VisitedDefs);
+    } else if (auto DstSrc = TII.isCopyInstr(*Def)) {
+      Register DstReg = DstSrc->Destination->getReg();
+      Register SrcReg = DstSrc->Source->getReg();
+      assert(DstReg == Reg);
+
+      unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRegister(
+          nullptr, DwarfEHRegNum, TRI.getDwarfRegNum(DstReg, true)));
+      CFIBuildInfos.push_back({&MBB, Def, DL, CFIIndex});
+      trackRegisterAndEmitCFIs(SrcReg, DwarfEHRegNum, *Def, CFIBuildInfos,
+                               VisitedRestorePoints, VisitedDefs);
+    } else
+      llvm_unreachable("Unexpected instruction");
+  }
+  return;
+}
+
+void RISCVFrameLowering::emitCFIsEarly(MachineFunction &MF,
+                                       ReachingDefInfo &RDI) const {
+  BitVector EarlyCSRs;
+  determineEarlyCalleeSaves(MF, EarlyCSRs);
+
+  SmallVector<MachineInstr *, 4> RestorePoints;
+  for (MachineBasicBlock &MBB : MF) {
+    if (MBB.isReturnBlock())
+      RestorePoints.push_back(&MBB.back());
+  }
+  SmallVector<CFIBuildInfo, 32> CFIBuildInfos;
+  const RISCVInstrInfo &TII = *STI.getInstrInfo();
+  const RISCVRegisterInfo &TRI = *STI.getRegisterInfo();
+  EarlyCFIEmitter EarlyCFIE(MF, RDI, TII, TRI, *STI.getFrameLowering());
+  const MCPhysReg *CSRegs = MF.getRegInfo().getCalleeSavedRegs();
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned Reg = CSRegs[i];
+    if (!EarlyCSRs[Reg])
+      continue;
+    SmallPtrSet<MachineInstr *, 32> VisitedDefs;
+    for (MachineInstr *RestorePoint : RestorePoints) {
+      SmallPtrSet<MachineInstr *, 32> VisitedRestorePoints;
+      EarlyCFIE.trackRegisterAndEmitCFIs(Reg, TRI.getDwarfRegNum(Reg, true),
+                                         *RestorePoint, CFIBuildInfos,
+                                         VisitedRestorePoints, VisitedDefs);
+    }
+  }
+  for (CFIBuildInfo &Info : CFIBuildInfos) {
+    MachineBasicBlock *MBB = Info.MBB;
+    if (Info.InsertAfterMI) {
+      auto Bundler =
+          MIBundleBuilder(*MBB, ++(Info.InsertAfterMI->getIterator()));
+      Bundler.append(Info.InsertAfterMI->removeFromParent());
+      Bundler.append(
+          BuildMI(MBB, Info.DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
+              .addCFIIndex(Info.CFIIndex)
+              ->removeFromParent());
+      finalizeBundle(*MBB, Bundler.begin(), Bundler.end());
+    } else {
+      BuildMI(*MBB, MBB->begin(), Info.DL,
+              TII.get(TargetOpcode::CFI_INSTRUCTION))
+          .addCFIIndex(Info.CFIIndex);
+    }
+  }
+  return;
+}
+
 bool RISCVFrameLowering::isSupportedStackID(TargetStackID::Value ID) const {
   switch (ID) {
   case TargetStackID::Default:
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index b1835877ecd31..0658203def349 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -74,6 +74,8 @@ class RISCVFrameLowering : public TargetFrameLowering {
 
   bool enableShrinkWrapping(const MachineFunction &MF) const override;
 
+  void emitCFIsEarly(MachineFunction &MF, ReachingDefInfo &RDI) const override;
+
   bool isSupportedStackID(TargetStackID::Value ID) const override;
   TargetStackID::Value getStackIDForScalableVectors() const override;
 
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 3dcad527304a6..ef1576db80bd5 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -75,9 +75,10 @@ static cl::opt<bool> EnablePExtCodeGen(
              "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);
+static cl::opt<bool> RISCVSaveCSRsEarly(
+    "riscv-save-csrs-early",
+    cl::desc("Let register alloctor do csr saves/restores"), cl::init(false),
+    cl::Hidden);
 
 void RISCVSubtarget::anchor() {}
 
@@ -221,8 +222,8 @@ bool RISCVSubtarget::enableMachinePipeliner() const {
   return getSchedModel().hasInstrSchedModel();
 }
 
-  /// Enable use of alias analysis during code generation (during MI
-  /// scheduling, DAGCombine, etc.).
+/// Enable use of alias analysis during code generation (during MI
+/// scheduling, DAGCombine, etc.).
 bool RISCVSubtarget::useAA() const { return UseAA; }
 
 unsigned RISCVSubtarget::getMinimumJumpTableEntries() const {
@@ -270,6 +271,4 @@ bool RISCVSubtarget::useMIPSCCMovInsn() const {
   return UseMIPSCCMovInsn && HasVendorXMIPSCMov;
 }
 
-bool RISCVSubtarget::savesCSRsEarly() const {
-  return SaveCSREarly;
-}
+bool RISCVSubtarget::savesCSRsEarly() const { return RISCVSaveCSRsEarly; }
diff --git a/llvm/test/CodeGen/RISCV/O0-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
index 8714b286374a5..b308fc82a5489 100644
--- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
@@ -54,6 +54,7 @@
 ; CHECK-NEXT:       Fixup Statepoint Caller Saved
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis
 ; CHECK-NEXT:       Machine Optimization Remark Emitter
+; CHECK-NEXT:       Reaching Definitions Analysis
 ; CHECK-NEXT:       Prologue/Epilogue Insertion & Frame Finalization
 ; CHECK-NEXT:       Post-RA pseudo instruction expansion pass
 ; CHECK-NEXT:       RISC-V post-regalloc pseudo instruction expansion pass
diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
index 3e2de780524b6..5111971f18cc2 100644
--- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
@@ -175,6 +175,7 @@
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis
 ; CHECK-NEXT:       Machine Optimization Remark Emitter
 ; CHECK-NEXT:       Shrink Wrapping analysis
+; CHECK-NEXT:       Reaching Definitions Analysis
 ; CHECK-NEXT:       Prologue/Epilogue Insertion & Frame Finalization
 ; CHECK-NEXT:       Machine Late Instructions Cleanup Pass
 ; CHECK-NEXT:       Control Flow Optimizer
diff --git a/llvm/test/CodeGen/RISCV/emit-early-cfis.mir b/llvm/test/CodeGen/RISCV/emit-early-cfis.mir
new file mode 100644
index 0000000000000..6788f1d6548be
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/emit-early-cfis.mir
@@ -0,0 +1,108 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc %s -mtriple=riscv64 -riscv-save-csrs-early=true \
+# RUN: -run-pass=prologepilog -o - | FileCheck %s
+---
+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: $x18
+    ; CHECK-LABEL: name: test0
+    ; CHECK: liveins: $x18
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -16
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+    ; CHECK-NEXT: BUNDLE implicit $x18 {
+    ; CHECK-NEXT:   SD $x18, %stack.0, 0 :: (store (s64))
+    ; CHECK-NEXT:   CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_reg $x18, $x2, 0, 12
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: BUNDLE implicit-def $x18 {
+    ; CHECK-NEXT:   $x18 = LD %stack.0, 0 :: (load (s64))
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x18
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: $x2 = frame-destroy ADDI $x2, 16
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+    ; CHECK-NEXT: PseudoRET
+    SD $x18, %stack.0, 0 :: (store (s64))
+    $x18 = LD %stack.0, 0 :: (load (s64))
+    PseudoRET
+
+...
+
+---
+name:            test1
+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: $x18
+    ; CHECK-LABEL: name: test1
+    ; CHECK: liveins: $x18
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -16
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+    ; CHECK-NEXT: BUNDLE implicit-def $x5, implicit $x18 {
+    ; CHECK-NEXT:   $x5 = COPY $x18
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x5
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: BUNDLE implicit-def $x18, implicit $x5 {
+    ; CHECK-NEXT:   $x18 = COPY $x5
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x18
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: $x2 = frame-destroy ADDI $x2, 16
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+    ; CHECK-NEXT: PseudoRET
+    $x5 = COPY $x18
+    $x18 = COPY $x5
+    PseudoRET
+
+...
+
+---
+name:            test2
+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: $x18
+    ; CHECK-LABEL: name: test2
+    ; CHECK: liveins: $x18
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -16
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+    ; CHECK-NEXT: BUNDLE implicit-def $x5, implicit $x18 {
+    ; CHECK-NEXT:   $x5 = COPY $x18
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x5
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: BUNDLE implicit $x5 {
+    ; CHECK-NEXT:   SD $x5, %stack.0, 0 :: (store (s64))
+    ; CHECK-NEXT:   CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_reg $x18, $x2, 0, 12
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: BUNDLE implicit-def $x5 {
+    ; CHECK-NEXT:   $x5 = LD %stack.0, 0 :: (load (s64))
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x5
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: BUNDLE implicit-def $x18, implicit $x5 {
+    ; CHECK-NEXT:   $x18 = COPY $x5
+    ; CHECK-NEXT:   CFI_INSTRUCTION register $x18, $x18
+    ; CHECK-NEXT: }
+    ; CHECK-NEXT: $x2 = frame-destroy ADDI $x2, 16
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+    ; CHECK-NEXT: PseudoRET
+    $x5 = COPY $x18
+    SD $x5, %stack.0, 0 :: (store (s64))
+    $x5 = LD %stack.0, 0 :: (load (s64))
+    $x18 = COPY $x5
+    PseudoRET
+
+...

@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/lib/CodeGen/PrologEpilogInserter.cpp llvm/lib/Target/RISCV/RISCVFrameLowering.cpp llvm/lib/Target/RISCV/RISCVFrameLowering.h llvm/lib/Target/RISCV/RISCVSubtarget.cpp --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/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index fe3ebcd13..d5e42d873 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -36,7 +36,7 @@ namespace llvm {
     ScalablePredicateVector = 4,
     NoAlloc = 255
   };
-}
+  }
 
 /// Information about stack frame layout on the target.  It holds the direction
 /// of stack growth, the known stack alignment on entry to each function, and
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index ef1576db8..82d68ba96 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -75,10 +75,10 @@ static cl::opt<bool> EnablePExtCodeGen(
              "only partial codegen is currently supported)"),
     cl::init(false), cl::Hidden);
 
-static cl::opt<bool> RISCVSaveCSRsEarly(
-    "riscv-save-csrs-early",
-    cl::desc("Let register alloctor do csr saves/restores"), cl::init(false),
-    cl::Hidden);
+static cl::opt<bool>
+    RISCVSaveCSRsEarly("riscv-save-csrs-early",
+                       cl::desc("Let register alloctor do csr saves/restores"),
+                       cl::init(false), cl::Hidden);
 
 void RISCVSubtarget::anchor() {}
 

@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:400:3: note: 'determineCalleeSaves' has been explicitly marked deprecated here
400 |   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:1541:28: error: unused variable 'TRI' [-Werror,-Wunused-variable]
1541 |   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 [WIP] Users/ppenzin/ra saverestore early cfi [WIP][CodeGen] Enable early CFI 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