[llvm] [RISCV][DebugInfo] Maintain CFI information during branch-folder (PR #200767)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 1 02:40:17 PDT 2026
https://github.com/sc-clulzze created https://github.com/llvm/llvm-project/pull/200767
This is an extension to https://github.com/llvm/llvm-project/pull/191784, after that change CFI information about saves/restores of CSRs can be placed in multiple blocks, not only prologue/epilogue blocks. Branch-folder does not expect this, and when MBBs are split using common tail, all debug info inside this common tail is moved to a different block and ends up being separated from corresponding CSR reloads, which are left in old block. This change fixes it by moving needed CFIs out of common tail.
>From 69919871cb8ca53a0346fa356c2b0b2455679452 Mon Sep 17 00:00:00 2001
From: sc-clulzze <d.marakulin at syntacore.com>
Date: Thu, 21 May 2026 09:29:33 +0000
Subject: [PATCH] [RISCV][DebugInfo] Maintain CFI information during
branch-folder
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 3 ++
llvm/lib/CodeGen/BranchFolding.cpp | 34 +++++++++++++++++++++
llvm/lib/CodeGen/BranchFolding.h | 2 ++
llvm/lib/CodeGen/CFIFixup.cpp | 9 +-----
llvm/lib/CodeGen/MachineVerifier.cpp | 25 +++++++++++++++
llvm/lib/CodeGen/TargetInstrInfo.cpp | 29 ++++++++++++++++++
6 files changed, 94 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index fef1e4fc85786..a99a328405eb1 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -167,6 +167,9 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
/// (like a call or something with unmodeled side effects).
virtual bool isGlobalMemoryObject(const MachineInstr *MI) const;
+ std::optional<unsigned> isCFIRestoreOfCSR(const MachineInstr *MI) const;
+ std::optional<unsigned> isReloadOfCSR(const MachineInstr *MI) const;
+
/// Return true if the instruction is trivially rematerializable, meaning it
/// has no side effects and requires no operands that aren't always available.
/// This means the only allowed uses are constants and unallocatable physical
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 4917c5b90821f..371285ae14b6d 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -26,6 +26,7 @@
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/BranchFoldingPass.h"
#include "llvm/CodeGen/MBFIWrapper.h"
+#include "llvm/MC/MCDwarf.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
@@ -387,6 +388,37 @@ static unsigned ComputeCommonTailLength(MachineBasicBlock *MBB1,
return TailLen;
}
+void BranchFolder::tryFixupCFI(MachineBasicBlock::iterator OldInst) {
+ MachineBasicBlock *MBB = OldInst->getParent();
+ auto CIs = MBB->getParent()->getFrameInstructions();
+ SmallSet<unsigned, 16> Restores;
+ auto MI = MBB->begin();
+ for (; MI != OldInst; ++MI) {
+ if (auto Id = TII->isReloadOfCSR(&*MI))
+ Restores.insert(*Id);
+ if (auto Id = TII->isCFIRestoreOfCSR(&*MI)) {
+ auto RestoredId = find_if(Restores, [&](auto Id2) {
+ return TRI->regsOverlap(*Id, Id2);
+ });
+ assert(Restores.contains(*RestoredId) && "Must've seen reload of register before CFI restore.");
+ Restores.erase(*RestoredId);
+ }
+ }
+ if (Restores.empty())
+ return;
+ auto InsertPos = OldInst--;
+ for (auto E = MBB->end(); MI != E; ++MI) {
+ auto Id = TII->isCFIRestoreOfCSR(&*MI);
+ if (!Id)
+ continue;
+ for (auto Reg2 : Restores) {
+ if (TRI->regsOverlap(*Id, Reg2)) {
+ MI->moveBefore(&*InsertPos);
+ }
+ }
+ }
+}
+
void BranchFolder::replaceTailWithBranchTo(MachineBasicBlock::iterator OldInst,
MachineBasicBlock &NewDest) {
if (UpdateLiveIns) {
@@ -417,6 +449,7 @@ void BranchFolder::replaceTailWithBranchTo(MachineBasicBlock::iterator OldInst,
}
}
+ tryFixupCFI(OldInst);
TII->ReplaceTailWithBranchTo(OldInst, &NewDest);
++NumTailMerge;
}
@@ -769,6 +802,7 @@ bool BranchFolder::CreateCommonTailOnlyBlock(MachineBasicBlock *&PredBB,
// SuccBB is an inner loop, the common tail is still part of the inner loop.
const BasicBlock *BB = (SuccBB && MBB->succ_size() == 1) ?
SuccBB->getBasicBlock() : MBB->getBasicBlock();
+ tryFixupCFI(BBI);
MachineBasicBlock *newMBB = SplitMBBAt(*MBB, BBI, BB);
if (!newMBB) {
LLVM_DEBUG(dbgs() << "... failed!");
diff --git a/llvm/lib/CodeGen/BranchFolding.h b/llvm/lib/CodeGen/BranchFolding.h
index ff2bbe06c0488..66cc9094981f0 100644
--- a/llvm/lib/CodeGen/BranchFolding.h
+++ b/llvm/lib/CodeGen/BranchFolding.h
@@ -143,6 +143,8 @@ class TargetRegisterInfo;
void replaceTailWithBranchTo(MachineBasicBlock::iterator OldInst,
MachineBasicBlock &NewDest);
+ void tryFixupCFI(MachineBasicBlock::iterator OldInst);
+
/// Given a machine basic block and an iterator into it, split the MBB so
/// that the part before the iterator falls into the part starting at the
/// iterator. This returns the new MBB.
diff --git a/llvm/lib/CodeGen/CFIFixup.cpp b/llvm/lib/CodeGen/CFIFixup.cpp
index c538acb55049d..4a86e20c3a3f0 100644
--- a/llvm/lib/CodeGen/CFIFixup.cpp
+++ b/llvm/lib/CodeGen/CFIFixup.cpp
@@ -99,13 +99,6 @@ static bool isPrologueCFIInstruction(const MachineInstr &MI) {
MI.getFlag(MachineInstr::FrameSetup);
}
-static bool containsEpilogue(const MachineBasicBlock &MBB) {
- return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
- return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
- MI.getFlag(MachineInstr::FrameDestroy);
- });
-}
-
static MachineBasicBlock *
findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
// Even though we should theoretically traverse the blocks in post-order, we
@@ -159,7 +152,7 @@ computeBlockInfo(const MachineFunction &MF,
bool HasEpilogue = false;
if (Info.HasFrameOnEntry || HasPrologue)
- HasEpilogue = containsEpilogue(*MBB);
+ HasEpilogue = MBB->isReturnBlock();
// If the function has a call frame at the entry of the current block or the
// current block contains the prologue, then the function has a call frame
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index af38525af6a6b..ee8d030726246 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -355,6 +355,7 @@ struct MachineVerifier {
void verifyStackFrame();
/// Check that the stack protector is the top-most object in the stack.
void verifyStackProtector();
+ void verifyCFI();
void verifySlotIndexes() const;
void verifyProperties(const MachineFunction &MF);
@@ -712,6 +713,7 @@ void MachineVerifier::visitMachineFunctionBefore() {
MRI->verifyUseLists();
if (!MF->empty()) {
+ verifyCFI();
verifyStackFrame();
verifyStackProtector();
}
@@ -4185,3 +4187,26 @@ void MachineVerifier::verifyStackProtector() {
}
}
}
+
+void MachineVerifier::verifyCFI() {
+ auto CIs = MF->getFrameInstructions();
+ for (auto &MBB : *MF) {
+ SmallVector<unsigned, 16> FrameDestroyCFI;
+ SmallVector<unsigned, 16> Restores;
+ for (auto &MI : MBB) {
+ if (auto Id = TII->isReloadOfCSR(&MI))
+ Restores.push_back(*Id);
+ if (auto Id = TII->isCFIRestoreOfCSR(&MI))
+ FrameDestroyCFI.push_back(*Id);
+ }
+ if (Restores.size() != FrameDestroyCFI.size() || any_of(FrameDestroyCFI, [&](auto Reg) {
+ for (auto Reg2 : Restores)
+ if (TRI->regsOverlap(Reg, Reg2))
+ return false;
+ return true;
+ })) {
+ report("Invalid CFI informarion", MF);
+ OS << "\nCFI info does not match restores of CSRs.\n" << MBB << "\n";
+ }
+ }
+}
\ No newline at end of file
diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index f3666b05464b7..9fa80089370dc 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/InterleavedRange.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/MC/MCDwarf.h"
using namespace llvm;
@@ -2232,3 +2233,31 @@ bool TargetInstrInfo::isGlobalMemoryObject(const MachineInstr *MI) const {
return MI->isCall() || MI->hasUnmodeledSideEffects() ||
(MI->hasOrderedMemoryRef() && !MI->isDereferenceableInvariantLoad());
}
+
+std::optional<unsigned> TargetInstrInfo::isCFIRestoreOfCSR(const MachineInstr *MI) const {
+ if (!MI->isCFIInstruction() || !MI->getFlag(MachineInstr::FrameDestroy))
+ return std::nullopt;
+ const MachineFunction *MF = MI->getParent()->getParent();
+ auto CIs = MF->getFrameInstructions();
+ auto &MO = MI->getOperand(0);
+ MCCFIInstruction CI = CIs[MO.getCFIIndex()];
+ if (CI.getOperation() != MCCFIInstruction::OpRestore)
+ return std::nullopt;
+ auto Reg = TRI.getLLVMRegNum(CI.getRegister(), false);
+ if (!Reg || !TRI.isCalleeSavedPhysReg(*Reg, *MF))
+ return std::nullopt;
+ return Reg->id();
+}
+
+std::optional<unsigned> TargetInstrInfo::isReloadOfCSR(const MachineInstr *MI) const {
+ if (!MI->mayLoad() || !MI->getFlag(MachineInstr::FrameDestroy))
+ return std::nullopt;
+ const MachineOperand &MO = MI->getOperand(0);
+ if (!MO.isReg())
+ return std::nullopt;
+ Register Reg = MO.getReg();
+ const MachineFunction *MF = MI->getParent()->getParent();
+ if (!Reg.isPhysical() || !TRI.isCalleeSavedPhysReg(Reg, *MF))
+ return std::nullopt;
+ return Reg.id();
+}
More information about the llvm-commits
mailing list