Skip to content

Commit 4060d38

Browse files
authored
[BranchFolding] Merge debug locs on common hoisted code (#140063)
branch-folder hoists common instructions from TBB and FBB into their pred. Without this patch it achieves this by splicing the instructions from TBB and deleting the common ones in FBB. That moves the debug locations and debug instructions from TBB into the pred without modification, which is not ideal. The merged instructions should get merged debug locations for debugging and PGO purposes, which is handled in this patch. Debug instructions also need to be handled differently. That'll come in another patch. This issue was found by @omern1.
1 parent 838ddc2 commit 4060d38

File tree

2 files changed

+143
-1
lines changed

2 files changed

+143
-1
lines changed

llvm/lib/CodeGen/BranchFolding.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,38 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
20712071
if (!HasDups)
20722072
return false;
20732073

2074-
MBB->splice(Loc, TBB, TBB->begin(), TIB);
2074+
// Hoist the instructions from [T.begin, TIB) and then delete [F.begin, FIB).
2075+
// Merge the debug locations. FIXME: We should do something with the
2076+
// debug instructions too (from BOTH branches).
2077+
{
2078+
// TIB and FIB point to the end of the regions to hoist/merge in TBB and
2079+
// FBB.
2080+
MachineBasicBlock::iterator FE = FIB;
2081+
MachineBasicBlock::iterator FI = FBB->begin();
2082+
for (MachineBasicBlock::iterator TI :
2083+
make_early_inc_range(make_range(TBB->begin(), TIB))) {
2084+
// Move debug instructions and pseudo probes without modifying them.
2085+
// FIXME: This is the wrong thing to do for debug locations, which
2086+
// should at least be killed.
2087+
if (TI->isDebugOrPseudoInstr()) {
2088+
TI->moveBefore(&*Loc);
2089+
continue;
2090+
}
2091+
2092+
// Get the next non-meta instruction in FBB.
2093+
FI = skipDebugInstructionsForward(FI, FE, false);
2094+
// NOTE: The loop above checks CheckKillDead but we can't do that here as
2095+
// it modifies some kill markers after the check.
2096+
assert(TI->isIdenticalTo(*FI, MachineInstr::CheckDefs) &&
2097+
"Expected non-debug lockstep");
2098+
2099+
// Merge debug locs on hoisted instructions.
2100+
TI->setDebugLoc(
2101+
DILocation::getMergedLocation(TI->getDebugLoc(), FI->getDebugLoc()));
2102+
TI->moveBefore(&*Loc);
2103+
++FI;
2104+
}
2105+
}
20752106
FBB->erase(FBB->begin(), FIB);
20762107

20772108
if (UpdateLiveIns)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# RUN: llc %s --start-before=branch-folder --stop-after=branch-folder -o - | FileCheck %s
2+
3+
## Check that common instructions hoisted from `if.then` and `if.else` into
4+
## common pred `entry` get merged debug locations.
5+
6+
## FIXME: The debug instructions handling here is wrong.
7+
8+
# CHECK: bb.0
9+
# CHECK: CALL64pcrel32 @f, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $rax
10+
## --- Start splice from bb.2.if.else ---
11+
# CHECK-NEXT: DBG_VALUE 2, $noreg, ![[#]], !DIExpression(), debug-location ![[#]]
12+
# CHECK-NEXT: $edi = MOV32r0 implicit-def dead $eflags, debug-location !DILocation(line: 0, scope: ![[#]])
13+
## --- End splice --------------
14+
# CHECK-NEXT: TEST64rr killed renamable $rax, renamable $rax, implicit-def $eflags
15+
# CHECK-NEXT: JCC_1 %bb.2, 9, implicit killed $eflags
16+
# CHECK: bb.1
17+
18+
--- |
19+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
20+
target triple = "x86_64-unknown-linux-gnu"
21+
22+
declare dso_local noundef i64 @f() local_unnamed_addr
23+
24+
define dso_local noundef i32 @g() local_unnamed_addr !dbg !7 {
25+
%call = tail call noundef i64 @f()
26+
%cmp1 = icmp sgt i64 0, %call
27+
%conv2 = trunc i64 0 to i32
28+
br i1 %cmp1, label %if.then, label %if.else
29+
30+
if.then: ; preds = %0
31+
#dbg_value(i64 0, !11, !DIExpression(), !13)
32+
tail call void @_Z3fooii(i32 noundef %conv2, i32 noundef 0), !dbg !14
33+
#dbg_value(i64 1, !11, !DIExpression(), !13)
34+
br label %if.end, !dbg !15
35+
36+
if.else: ; preds = %0
37+
#dbg_value(i64 2, !11, !DIExpression(), !13)
38+
tail call void @_Z3barii(i32 noundef %conv2, i32 noundef 1), !dbg !16
39+
#dbg_value(i64 3, !11, !DIExpression(), !13)
40+
br label %if.end, !dbg !17
41+
42+
if.end: ; preds = %if.else, %if.then
43+
ret i32 2
44+
}
45+
46+
declare void @_Z3fooii(i32 noundef, i32 noundef) local_unnamed_addr
47+
48+
declare void @_Z3barii(i32 noundef, i32 noundef) local_unnamed_addr
49+
50+
!llvm.module.flags = !{!0, !1}
51+
!llvm.ident = !{!2}
52+
!llvm.dbg.cu = !{!3}
53+
!llvm.debugify = !{!5, !6}
54+
55+
!0 = !{i32 7, !"Dwarf Version", i32 5}
56+
!1 = !{i32 2, !"Debug Info Version", i32 3}
57+
!2 = !{!"clang version 21.0.0"}
58+
!3 = distinct !DICompileUnit(language: DW_LANG_C, file: !4, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
59+
!4 = !DIFile(filename: "test.nodbg.ll", directory: "/")
60+
!5 = !{i32 15}
61+
!6 = !{i32 7}
62+
!7 = distinct !DISubprogram(name: "g", linkageName: "g", scope: null, file: !4, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !3, retainedNodes: !10)
63+
!8 = !DISubroutineType(types: !9)
64+
!9 = !{}
65+
!10 = !{!11}
66+
!11 = !DILocalVariable(name: "1", scope: !7, file: !4, line: 3, type: !12)
67+
!12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
68+
!13 = !DILocation(line: 3, column: 1, scope: !7)
69+
!14 = !DILocation(line: 9, column: 1, scope: !7)
70+
!15 = !DILocation(line: 10, column: 1, scope: !7)
71+
!16 = !DILocation(line: 11, column: 1, scope: !7)
72+
!17 = !DILocation(line: 12, column: 1, scope: !7)
73+
...
74+
---
75+
name: g
76+
body: |
77+
bb.0 (%ir-block.0):
78+
successors: %bb.1(0x40000000), %bb.2(0x40000000)
79+
80+
frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
81+
frame-setup CFI_INSTRUCTION def_cfa_offset 16
82+
CALL64pcrel32 @f, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $rax
83+
TEST64rr killed renamable $rax, renamable $rax, implicit-def $eflags
84+
JCC_1 %bb.2, 9, implicit killed $eflags
85+
JMP_1 %bb.1
86+
87+
bb.1.if.then:
88+
successors: %bb.3(0x80000000)
89+
90+
DBG_VALUE 0, $noreg, !11, !DIExpression(), debug-location !13
91+
$edi = MOV32r0 implicit-def dead $eflags, debug-location !14
92+
$esi = MOV32r0 implicit-def dead $eflags, debug-location !14
93+
CALL64pcrel32 target-flags(x86-plt) @_Z3fooii, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit killed $esi, implicit-def $rsp, implicit-def $ssp, debug-location !14
94+
DBG_VALUE 1, $noreg, !11, !DIExpression(), debug-location !13
95+
JMP_1 %bb.3, debug-location !15
96+
97+
bb.2.if.else:
98+
successors: %bb.3(0x80000000)
99+
100+
DBG_VALUE 2, $noreg, !11, !DIExpression(), debug-location !13
101+
$edi = MOV32r0 implicit-def dead $eflags, debug-location !16
102+
$esi = MOV32ri 1, debug-location !16
103+
CALL64pcrel32 target-flags(x86-plt) @_Z3barii, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit killed $esi, implicit-def $rsp, implicit-def $ssp, debug-location !16
104+
DBG_VALUE 3, $noreg, !11, !DIExpression(), debug-location !13
105+
106+
bb.3.if.end:
107+
$eax = MOV32ri 2
108+
$rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
109+
frame-destroy CFI_INSTRUCTION def_cfa_offset 8
110+
RET 0, $eax
111+
...

0 commit comments

Comments
 (0)