[llvm] [BranchFolder] Prevent nested salvage in empty BB chains with pseudo probes (PR #206092)

Jinjie Huang via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 9 01:57:13 PDT 2026


https://github.com/Jinjie-Huang updated https://github.com/llvm/llvm-project/pull/206092

>From ad0343adbce72398c97179fb08bae183fe516f24 Mon Sep 17 00:00:00 2001
From: huangjinjie <huangjinjie at bytedance.com>
Date: Thu, 9 Jul 2026 15:57:05 +0800
Subject: [PATCH] Prevent nested salvage in empty BB chains with pseudo probes

---
 llvm/lib/CodeGen/BranchFolding.cpp            | 30 +++++++-
 llvm/lib/CodeGen/BranchFolding.h              |  1 +
 ...ranch-folder-pseudoprobe-debug-salvage.mir | 68 +++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/MIR/X86/branch-folder-pseudoprobe-debug-salvage.mir

diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 2fdd766102a7f..442e13bccc138 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -90,6 +90,11 @@ TailMergeSize("tail-merge-size",
               cl::desc("Min number of instructions to consider tail merging"),
               cl::init(3), cl::Hidden);
 
+static cl::opt<unsigned> EmptyBlockThreshold(
+    "branch-folder-empty-block-threshold",
+    cl::desc("Min number of empty blocks to skip predecessor debug salvage"),
+    cl::init(500), cl::Hidden);
+
 namespace {
 
   /// BranchFolderPass - Wrap branch folder in a machine function pass.
@@ -1248,9 +1253,22 @@ void BranchFolder::setCommonTailEdgeWeights(MachineBasicBlock &TailMBB) {
 //  Branch Optimization
 //===----------------------------------------------------------------------===//
 
+static bool IsEmptyBlock(MachineBasicBlock *MBB);
+
+static bool shouldSkipPredDebugSalvage(MachineFunction &MF) {
+  unsigned NumEmptyBlocks = 0;
+  for (MachineBasicBlock &MBB : MF)
+    if (IsEmptyBlock(&MBB))
+      if (++NumEmptyBlocks > EmptyBlockThreshold)
+        return true;
+  return false;
+}
+
 bool BranchFolder::OptimizeBranches(MachineFunction &MF) {
   bool MadeChange = false;
 
+  SkipPredDebugSalvage = shouldSkipPredDebugSalvage(MF);
+
   // Make sure blocks are numbered in order
   MF.RenumberBlocks();
   // Renumbering blocks alters EH scope membership, recalculate it.
@@ -1343,13 +1361,21 @@ static void copyDebugInfoToSuccessor(const TargetInstrInfo *TII,
 // to run a heavier analysis, such as the LiveDebugValues pass, before we do
 // branch folding.
 static void salvageDebugInfoFromEmptyBlock(const TargetInstrInfo *TII,
-                                           MachineBasicBlock &MBB) {
+                                           MachineBasicBlock &MBB,
+                                           bool SkipPredDebugSalvage) {
   assert(IsEmptyBlock(&MBB) && "Expected an empty block (except debug info).");
   // If this MBB is the only predecessor of a successor it is legal to copy
   // DBG_VALUE instructions to the beginning of the successor.
   for (MachineBasicBlock *SuccBB : MBB.successors())
     if (SuccBB->pred_size() == 1)
       copyDebugInfoToSuccessor(TII, MBB, *SuccBB);
+
+  // Avoid creating very long predecessor debug tails in functions with many
+  // empty blocks. Those tails make later backward terminator scans such as
+  // analyzeBranch() quadratic.
+  if (SkipPredDebugSalvage)
+    return;
+
   // If this MBB is the only successor of a predecessor it is legal to copy the
   // DBG_VALUE instructions to the end of the predecessor (just before the
   // terminators, assuming that the terminator isn't affecting the DBG_VALUE).
@@ -1389,7 +1415,7 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {
   // optimized away.
   if (IsEmptyBlock(MBB) && !MBB->isEHPad() && !MBB->hasAddressTaken() &&
       SameEHScope) {
-    salvageDebugInfoFromEmptyBlock(TII, *MBB);
+    salvageDebugInfoFromEmptyBlock(TII, *MBB, SkipPredDebugSalvage);
     // Dead block?  Leave for cleanup later.
     if (MBB->pred_empty()) return MadeChange;
 
diff --git a/llvm/lib/CodeGen/BranchFolding.h b/llvm/lib/CodeGen/BranchFolding.h
index ff2bbe06c0488..9c2d4c5b4138b 100644
--- a/llvm/lib/CodeGen/BranchFolding.h
+++ b/llvm/lib/CodeGen/BranchFolding.h
@@ -120,6 +120,7 @@ class TargetRegisterInfo;
     bool EnableTailMerge = false;
     bool EnableHoistCommonCode = false;
     bool UpdateLiveIns = false;
+    bool SkipPredDebugSalvage = false;
     unsigned MinCommonTailLength;
     const TargetInstrInfo *TII = nullptr;
     const MachineRegisterInfo *MRI = nullptr;
diff --git a/llvm/test/CodeGen/MIR/X86/branch-folder-pseudoprobe-debug-salvage.mir b/llvm/test/CodeGen/MIR/X86/branch-folder-pseudoprobe-debug-salvage.mir
new file mode 100644
index 0000000000000..40cb407134c25
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/branch-folder-pseudoprobe-debug-salvage.mir
@@ -0,0 +1,68 @@
+# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=branch-folder | FileCheck %s --check-prefix=KEEP
+# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=branch-folder -branch-folder-empty-block-threshold=1 | FileCheck %s --check-prefix=SKIP
+
+# Constructed a test case with an empty MBB chain of length 2 to verify that
+# when -branch-folder-empty-block-threshold is set to 1, debug instructions
+# are no longer salvaged into the predecessor.
+
+--- |
+  define void @pred_salvage() !dbg !4 {
+    ret void
+  }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: true, emissionKind: FullDebug)
+  !1 = !DIFile(filename: "branch-folder-pseudoprobe-debug-salvage.c", directory: "/tmp")
+  !2 = !{}
+  !3 = !{i32 2, !"Debug Info Version", i32 3}
+  !4 = distinct !DISubprogram(name: "pred_salvage", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+  !5 = !DISubroutineType(types: !6)
+  !6 = !{null}
+  !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !8 = !{!9}
+  !9 = !DILocalVariable(name: "debug_var", scope: !4, file: !1, line: 2, type: !7)
+  !10 = !DILocation(line: 2, column: 3, scope: !4)
+
+...
+---
+name:            pred_salvage
+tracksRegLiveness: false
+body:             |
+  ; KEEP-LABEL: name: pred_salvage
+  ; KEEP: bb.1:
+  ; KEEP: $eax = MOV32ri 42
+  ; KEEP-NEXT: DBG_VALUE 1, $noreg
+  ; KEEP: RET 0
+  ; SKIP-LABEL: name: pred_salvage
+  ; SKIP: bb.1:
+  ; SKIP: $eax = MOV32ri 42
+  ; SKIP-NOT: DBG_VALUE 1, $noreg
+  ; SKIP: RET 0
+  bb.0:
+    successors: %bb.1, %bb.3
+    TEST32rr $eax, $eax, implicit-def $eflags
+    JCC_1 %bb.3, 4, implicit $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    successors: %bb.2
+    $eax = MOV32ri 42
+    JMP_1 %bb.2
+
+  bb.2:
+    successors: %bb.5
+    DBG_VALUE 1, $noreg, !9, !DIExpression(), debug-location !10
+
+  bb.5:
+    successors: %bb.4
+
+  bb.4:
+    RET 0
+
+  bb.3:
+    successors: %bb.4
+    JMP_1 %bb.4
+
+...



More information about the llvm-commits mailing list