Skip to content

Commit 65ca4ab

Browse files
committed
[DebugInfo] Don't apply is_stmt on MBB branches that preserve lines
This patch follows on from the changes made in 5fef40c, by adding an additional heuristic that prevents us from applying the start-of-MBB is_stmt flag when we can see that, for all direct branches to the MBB, the last line stepped on before the branch is the same as the first line of the MBB. This is mainly to prevent certain pathological cases, such as macros that expand to multiple basic blocks that all have the same source location, from giving us repeated steps on the same line. This approach is not comprehensive, since it relies on analyzeBranch to read edges.
1 parent 241f936 commit 65ca4ab

File tree

3 files changed

+182
-5
lines changed

3 files changed

+182
-5
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,10 +2061,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
20612061
unsigned LastAsmLine =
20622062
Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine();
20632063

2064-
bool PrevInstInSameSection =
2065-
(!PrevInstBB ||
2066-
PrevInstBB->getSectionID() == MI->getParent()->getSectionID());
2067-
if (DL == PrevInstLoc && PrevInstInSameSection) {
2064+
bool PrevInstInDiffBB = PrevInstBB && PrevInstBB != MI->getParent();
2065+
bool ForceIsStmt =
2066+
PrevInstInDiffBB && MBBsStartingWithIsStmt.contains(MI->getParent());
2067+
if (DL == PrevInstLoc && !ForceIsStmt) {
20682068
// If we have an ongoing unspecified location, nothing to do here.
20692069
if (!DL)
20702070
return;
@@ -2121,7 +2121,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
21212121
// If the line changed, we call that a new statement; unless we went to
21222122
// line 0 and came back, in which case it is not a new statement.
21232123
unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine() : LastAsmLine;
2124-
if (DL.getLine() && DL.getLine() != OldLine)
2124+
if (DL.getLine() && (DL.getLine() != OldLine || ForceIsStmt))
21252125
Flags |= DWARF2_FLAG_IS_STMT;
21262126

21272127
const MDNode *Scope = DL.getScope();
@@ -2229,6 +2229,119 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
22292229
// Record beginning of function.
22302230
PrologEndLoc = emitInitialLocDirective(
22312231
*MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID());
2232+
2233+
// Try to determine what line we would be stepped on before entering each MBB.
2234+
// This happens in the following ways:
2235+
// - If this block has a single predecessor, we determine the last line in
2236+
// the pred block and we have stepped from that.
2237+
// - If this block has multiple predecessors, we determine the last line in
2238+
// each of them; if they all agree then we have stepped from that line,
2239+
// otherwise we do not know what line we have stepped from.
2240+
// The last line in each MBB is determined as follows:
2241+
// - If the block contains at least one DebugLoc, we have stepped from the
2242+
// last one.
2243+
// - Otherwise, the last line is line 0.
2244+
// There is one extra rule however: if a predecessor branches to the current
2245+
// basic block, we only count DebugLocs on or before that branch, so if we're
2246+
// looking at the MBB %bb.0, which ends with:
2247+
// JCC_1 %bb.1, 0, !debug-location !1
2248+
// JMP_1 %bb.2, !debug-location !2
2249+
// We would consider !1 to be the last loc before %bb.1, and !2 before %bb.2.
2250+
// We also don't need to make this calculation for any block that doesn't have
2251+
// a non-0 line number on its first instruction, as we will always emit line 0
2252+
// without is_stmt for that block regardless.
2253+
MBBsStartingWithIsStmt.clear();
2254+
2255+
// First, collect the last stepped line for each MBB.
2256+
SmallDenseMap<std::pair<const MachineBasicBlock *, const MachineBasicBlock *>,
2257+
unsigned>
2258+
MBBExitLines;
2259+
const auto *TII = MF->getSubtarget().getInstrInfo();
2260+
2261+
// We only need to examine MBBs that could have is_stmt set by this logic.
2262+
// We use const_cast even though we won't actually modify MF, because some
2263+
// methods we need take a non-const MBB.
2264+
SetVector<MachineBasicBlock *> PredMBBsToExamine;
2265+
SmallVector<MachineBasicBlock *> PotentialIsStmtMBBs;
2266+
for (auto &MBB : *const_cast<MachineFunction *>(MF)) {
2267+
if (MBB.pred_empty() || !MBB.begin()->getDebugLoc())
2268+
continue;
2269+
unsigned StartLine = MBB.begin()->getDebugLoc()->getLine();
2270+
if (StartLine == 0)
2271+
continue;
2272+
PotentialIsStmtMBBs.push_back(&MBB);
2273+
for (auto Pred : MBB.predecessors())
2274+
PredMBBsToExamine.insert(&*Pred);
2275+
}
2276+
2277+
// For each predecessor MBB, we examine the last DebugLoc seen before each
2278+
// branch or logical fallthrough. We're generous with applying is_stmt; if
2279+
// there's an edge that TargetInstrInfo::analyzeBranch can't understand, we
2280+
// simply assume that is_stmt ought to be applied to the successors, since
2281+
// this rule is mainly intended to avoid excessive stepping on lines that
2282+
// expand to many lines of code.
2283+
for (auto *MBB : PredMBBsToExamine) {
2284+
assert(!MBB->empty() && "Shouldn't be processing empty blocks here.");
2285+
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
2286+
SmallVector<MachineOperand, 4> Cond;
2287+
if (TII->analyzeBranch(*MBB, TBB, FBB, Cond)) {
2288+
// We can't determine what DLs this branch's successors use, so skip it.
2289+
continue;
2290+
}
2291+
assert(TBB && "Bad result from analyzeBranch?");
2292+
auto MI = MBB->rbegin();
2293+
// For a conditional branch followed by unconditional branch where the
2294+
// unconditional branch has a DebugLoc, that loc is the outgoing loc to the
2295+
// false destination only; otherwise, both destinations share an outgoing
2296+
// loc.
2297+
if (!Cond.empty() && FBB != nullptr && MBB->back().getDebugLoc()) {
2298+
assert(MI->isBranch() && "Bad result from analyzeBranch?");
2299+
MBBExitLines.insert({{MBB, FBB}, MBB->back().getDebugLoc()->getLine()});
2300+
FBB = nullptr;
2301+
++MI;
2302+
} else if (!Cond.empty() && !FBB) {
2303+
// For a conditional branch that falls through to the next block, the
2304+
// fallthrough block is the false branch.
2305+
FBB = MBB->getLogicalFallThrough();
2306+
assert(FBB &&
2307+
"Block ending with just a conditional branch should fallthrough.");
2308+
}
2309+
2310+
// If we don't find an outgoing loc, this block will start with a line 0.
2311+
unsigned LastLine = 0;
2312+
while (MI != MBB->rend()) {
2313+
if (auto DL = MI->getDebugLoc()) {
2314+
LastLine = DL->getLine();
2315+
break;
2316+
}
2317+
++MI;
2318+
}
2319+
MBBExitLines.insert({{MBB, TBB}, LastLine});
2320+
if (FBB)
2321+
MBBExitLines.insert({{MBB, FBB}, LastLine});
2322+
}
2323+
2324+
// Now use the outgoing values to determine the incoming values for each
2325+
// block.
2326+
MBBsStartingWithIsStmt.insert(&*MF->begin());
2327+
for (auto *MBB : PotentialIsStmtMBBs) {
2328+
assert(!MBB->empty() && "Shouldn't be processing empty blocks here.");
2329+
if (!MBB->begin()->getDebugLoc())
2330+
continue;
2331+
unsigned StartLine = MBB->begin()->getDebugLoc()->getLine();
2332+
if (StartLine == 0)
2333+
continue;
2334+
for (auto Pred : MBB->predecessors()) {
2335+
auto LineIt = MBBExitLines.find({&*Pred, MBB});
2336+
// If there is no entry, it means there's a branch here that we couldn't
2337+
// track, so we can't be sure about what line we're arriving from;
2338+
// therefore assume that we should use is_stmt.
2339+
if (LineIt == MBBExitLines.end() || LineIt->second != StartLine) {
2340+
MBBsStartingWithIsStmt.insert(MBB);
2341+
break;
2342+
}
2343+
}
2344+
}
22322345
}
22332346

22342347
unsigned

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ class DwarfDebug : public DebugHandlerBase {
382382
SmallPtrSet<const MDNode *, 2>>;
383383
DenseMap<const DILocalScope *, MDNodeSet> LocalDeclsPerLS;
384384

385+
SmallDenseSet<const MachineBasicBlock *> MBBsStartingWithIsStmt;
386+
385387
/// If nonnull, stores the current machine function we're processing.
386388
const MachineFunction *CurFn = nullptr;
387389

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
;; Checks that when an instruction at the start of a BasicBlock has the same
2+
;; DebugLoc as the instruction at the end of the previous BasicBlock, we add
3+
;; is_stmt to the new line, to ensure that we still step on it if we arrive from
4+
;; a BasicBlock other than the immediately preceding one, unless all known
5+
;; predecessor BasicBlocks end with the same line.
6+
7+
; RUN: %llc_dwarf -mtriple=x86_64-unknown-linux -O0 -filetype=obj < %s | llvm-dwarfdump --debug-line - | FileCheck %s
8+
9+
; CHECK: {{0x[0-9a-f]+}} 13 5 {{.+}} is_stmt
10+
; CHECK-NEXT: {{0x[0-9a-f]+}} 13 5 {{.+}} is_stmt
11+
12+
define void @_Z1fi(i1 %cond) !dbg !21 {
13+
entry:
14+
br i1 %cond, label %if.then2, label %if.else4
15+
16+
if.then2: ; preds = %entry
17+
br label %if.end8, !dbg !24
18+
19+
if.else4: ; preds = %entry
20+
%0 = load i32, ptr null, align 4, !dbg !24
21+
%call5 = call i1 null(i32 %0)
22+
ret void
23+
24+
if.end8: ; preds = %if.then2
25+
ret void
26+
}
27+
28+
; CHECK: {{0x[0-9a-f]+}} 113 5 {{.+}} is_stmt
29+
; CHECK-NOT: {{0x[0-9a-f]+}} 113 5
30+
31+
define void @_Z1gi(i1 %cond) !dbg !31 {
32+
entry:
33+
br i1 %cond, label %if.then2, label %if.else4, !dbg !34
34+
35+
if.then2: ; preds = %entry
36+
br label %if.end8, !dbg !34
37+
38+
if.else4: ; preds = %entry
39+
%0 = load i32, ptr null, align 4, !dbg !34
40+
%call5 = call i1 null(i32 %0)
41+
ret void
42+
43+
if.end8: ; preds = %if.then2
44+
ret void
45+
}
46+
47+
!llvm.dbg.cu = !{!0}
48+
!llvm.module.flags = !{!20}
49+
50+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
51+
!1 = !DIFile(filename: "test.cpp", directory: "/home/gbtozers/dev/upstream-llvm")
52+
!20 = !{i32 2, !"Debug Info Version", i32 3}
53+
!21 = distinct !DISubprogram(name: "f", linkageName: "_Z1fi", scope: !1, file: !1, line: 7, type: !22, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
54+
!22 = distinct !DISubroutineType(types: !23)
55+
!23 = !{null}
56+
!24 = !DILocation(line: 13, column: 5, scope: !25)
57+
!25 = distinct !DILexicalBlock(scope: !21, file: !1, line: 11, column: 27)
58+
!31 = distinct !DISubprogram(name: "g", linkageName: "_Z1gi", scope: !1, file: !1, line: 107, type: !32, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
59+
!32 = distinct !DISubroutineType(types: !33)
60+
!33 = !{null}
61+
!34 = !DILocation(line: 113, column: 5, scope: !35)
62+
!35 = distinct !DILexicalBlock(scope: !31, file: !1, line: 111, column: 27)

0 commit comments

Comments
 (0)