[llvm] b60afea - [SimplifyCFG] Keep a debug location on calls cloned by `FoldBranchToCommonDest` (#224247)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 06:09:53 PDT 2026
Author: Akash Manna
Date: 2026-09-25T14:09:44+01:00
New Revision: b60afea0d31f4da34b9d867a00817a0e53dbdb05
URL: https://github.com/llvm/llvm-project/commit/b60afea0d31f4da34b9d867a00817a0e53dbdb05
DIFF: https://github.com/llvm/llvm-project/commit/b60afea0d31f4da34b9d867a00817a0e53dbdb05.diff
LOG: [SimplifyCFG] Keep a debug location on calls cloned by `FoldBranchToCommonDest` (#224247)
Fixes #220848
When folding a branch to a common destination, SimplifyCFG clones the
bonus instructions into the predecessor and resets their debug
locations, so the debugger doesn't step onto code from a branch that
wasn't taken. It did that with `setDebugLoc(DebugLoc::getDropped())` for
every instruction. That's fine for an `icmp`, but with
`-bonus-inst-threshold=2` a `speculatable` call can be a bonus
instruction too, and an inlinable call in a function with debug info
must have a `!dbg` location, otherwise the inliner can't set up the
inlined-at scope. The verifier rejects the module with "inlinable
function call in a function with debug info must have a !dbg location".
The clone now uses `Instruction::dropLocation()`, which is what
`speculativelyExecuteBB` in the same file already does. Non-call
instructions still lose their location as before, while calls get a line
0 location in the function's scope, so nothing misleading shows up when
stepping and the IR stays valid. `dropLocation()` needs the parent
function, so the clone is inserted into the predecessor before its
location is updated. An earlier attempt at this swap (674f57870f4c) was
reverted after buildbot crashes; the clone was still unparented when
`dropLocation()` ran there, which would explain them.
Added:
llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest-call-debugloc.ll
Modified:
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 248963f74adaf..7134ab2a7f40c 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -1181,13 +1181,14 @@ static void cloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(
continue;
Instruction *NewBonusInst = BonusInst.clone();
+ NewBonusInst->insertInto(PredBlock, PTI->getIterator());
if (!NewBonusInst->getDebugLoc().isSameSourceLocation(PTI->getDebugLoc())) {
// Unless the instruction has the same !dbg location as the original
// branch, drop it. When we fold the bonus instructions we want to make
// sure we reset their debug locations in order to avoid stepping on
// dead code caused by folding dead branches.
- NewBonusInst->setDebugLoc(DebugLoc::getDropped());
+ NewBonusInst->dropLocation();
} else if (const DebugLoc &DL = NewBonusInst->getDebugLoc()) {
mapAtomInstance(DL, VMap);
}
@@ -1202,7 +1203,6 @@ static void cloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(
// location the call is moved to.
NewBonusInst->dropUBImplyingAttrsAndMetadata();
- NewBonusInst->insertInto(PredBlock, PTI->getIterator());
auto Range = NewBonusInst->cloneDebugInfoFrom(&BonusInst);
RemapDbgRecordRange(NewBonusInst->getModule(), Range, VMap,
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
diff --git a/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest-call-debugloc.ll b/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest-call-debugloc.ll
new file mode 100644
index 0000000000000..2cd631e7a00d4
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest-call-debugloc.ll
@@ -0,0 +1,91 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=simplifycfg -bonus-inst-threshold=2 -S < %s | FileCheck %s
+
+; GH220848: a call cloned as a bonus instruction must keep a (line 0) !dbg
+; location, as the verifier requires one on inlinable calls.
+
+define i32 @speculate_call(ptr noundef nonnull %p) #0 !dbg !5 {
+; CHECK-LABEL: define i32 @speculate_call(
+; CHECK-SAME: ptr noundef nonnull [[P:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG3:![0-9]+]] {
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null, !dbg [[DBG6:![0-9]+]]
+; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32, !dbg [[DBG6]]
+; CHECK-NEXT: ret i32 [[CONV]], !dbg [[DBG6]]
+;
+ %cmp = icmp ne ptr %p, null, !dbg !8
+ %conv = zext i1 %cmp to i32, !dbg !8
+ ret i32 %conv, !dbg !8
+}
+
+declare void @sideeffect()
+
+define void @one_pred_with_spec_call(i8 noundef zeroext %v0, i8 noundef zeroext %v1, ptr noundef %p) !dbg !11 {
+; CHECK-LABEL: define void @one_pred_with_spec_call(
+; CHECK-SAME: i8 noundef zeroext [[V0:%.*]], i8 noundef zeroext [[V1:%.*]], ptr noundef [[P:%.*]]) !dbg [[DBG7:![0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne ptr [[P]], null, !dbg [[DBG8:![0-9]+]]
+; CHECK-NEXT: [[X:%.*]] = call i32 @speculate_call(ptr [[P]]) #[[ATTR1:[0-9]+]], !dbg [[DBG10:![0-9]+]]
+; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[V1]] to i32
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CONV]], 0
+; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[TOBOOL]], [[CMP]], !dbg [[DBG8]]
+; CHECK-NEXT: br i1 [[OR_COND]], label %[[RETURN:.*]], label %[[IF_END:.*]], !dbg [[DBG8]]
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: call void @sideeffect(), !dbg [[DBG11:![0-9]+]]
+; CHECK-NEXT: br label %[[RETURN]], !dbg [[DBG12:![0-9]+]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void, !dbg [[DBG12]]
+;
+entry:
+ %tobool = icmp ne ptr %p, null, !dbg !14
+ br i1 %tobool, label %if.then, label %if.end, !dbg !14
+
+if.then:
+ %x = call i32 @speculate_call(ptr noundef %p) #1, !dbg !16
+ %conv = zext i8 %v1 to i32, !dbg !17
+ %cmp = icmp eq i32 %conv, 0, !dbg !18
+ br i1 %cmp, label %return, label %if.end, !dbg !18
+
+if.end:
+ call void @sideeffect(), !dbg !19
+ br label %return, !dbg !20
+
+return:
+ ret void, !dbg !20
+}
+
+attributes #0 = { noinline nounwind speculatable willreturn memory(read) }
+attributes #1 = { nounwind willreturn memory(read) }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "case.c", directory: "")
+!2 = !{}
+!3 = !DISubroutineType(types: !2)
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "speculate_call", scope: !1, file: !1, line: 3, type: !3, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!6 = distinct !DILexicalBlock(scope: !11, file: !1, line: 9, column: 7)
+!7 = distinct !DILexicalBlock(scope: !6, file: !1, line: 9, column: 15)
+!8 = !DILocation(line: 3, column: 90, scope: !5)
+!11 = distinct !DISubprogram(name: "one_pred_with_spec_call", scope: !1, file: !1, line: 7, type: !3, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!14 = !DILocation(line: 9, column: 9, scope: !6)
+!15 = distinct !DILexicalBlock(scope: !7, file: !1, line: 12, column: 9)
+!16 = !DILocation(line: 10, column: 13, scope: !7)
+!17 = !DILocation(line: 12, column: 9, scope: !15)
+!18 = !DILocation(line: 12, column: 12, scope: !15)
+!19 = !DILocation(line: 15, column: 3, scope: !11)
+!20 = !DILocation(line: 16, column: 1, scope: !11)
+;.
+; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+; CHECK: [[META1]] = !DIFile(filename: "{{.*}}case.c", directory: {{.*}})
+; CHECK: [[DBG3]] = distinct !DISubprogram(name: "speculate_call", scope: [[META1]], file: [[META1]], line: 3, type: [[META4:![0-9]+]], scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]])
+; CHECK: [[META4]] = !DISubroutineType(types: [[META5:![0-9]+]])
+; CHECK: [[META5]] = !{}
+; CHECK: [[DBG6]] = !DILocation(line: 3, column: 90, scope: [[DBG3]])
+; CHECK: [[DBG7]] = distinct !DISubprogram(name: "one_pred_with_spec_call", scope: [[META1]], file: [[META1]], line: 7, type: [[META4]], scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]])
+; CHECK: [[DBG8]] = !DILocation(line: 9, column: 9, scope: [[META9:![0-9]+]])
+; CHECK: [[META9]] = distinct !DILexicalBlock(scope: [[DBG7]], file: [[META1]], line: 9, column: 7)
+; CHECK: [[DBG10]] = !DILocation(line: 0, scope: [[DBG7]])
+; CHECK: [[DBG11]] = !DILocation(line: 15, column: 3, scope: [[DBG7]])
+; CHECK: [[DBG12]] = !DILocation(line: 16, column: 1, scope: [[DBG7]])
+;.
More information about the llvm-commits
mailing list