Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 8381d3e

Browse files
[DebugInfo][Dexter] Unreachable line stepped onto after SimplifyCFG.
In SimplifyCFG when given a conditional branch that goes to BB1 and BB2, the hoisted common terminator instruction in the two blocks, caused debug line records associated with subsequent select instructions to become ambiguous. It causes the debugger to display unreachable source lines. Differential Revision: https://reviews.llvm.org/D53390 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346481 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 8e070ff commit 8381d3e

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

include/llvm/IR/Instruction.h

+8
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,14 @@ class Instruction : public User,
586586
static_cast<const Instruction *>(this)->getNextNonDebugInstruction());
587587
}
588588

589+
/// Return a pointer to the previous non-debug instruction in the same basic
590+
/// block as 'this', or nullptr if no such instruction exists.
591+
const Instruction *getPrevNonDebugInstruction() const;
592+
Instruction *getPrevNonDebugInstruction() {
593+
return const_cast<Instruction *>(
594+
static_cast<const Instruction *>(this)->getPrevNonDebugInstruction());
595+
}
596+
589597
/// Create a copy of 'this' instruction that is identical in all ways except
590598
/// the following:
591599
/// * The instruction has no parent

lib/IR/Instruction.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,13 @@ const Instruction *Instruction::getNextNonDebugInstruction() const {
602602
return nullptr;
603603
}
604604

605+
const Instruction *Instruction::getPrevNonDebugInstruction() const {
606+
for (const Instruction *I = getPrevNode(); I; I = I->getPrevNode())
607+
if (!isa<DbgInfoIntrinsic>(I))
608+
return I;
609+
return nullptr;
610+
}
611+
605612
bool Instruction::isAssociative() const {
606613
unsigned Opcode = getOpcode();
607614
if (isAssociative(Opcode))

lib/Transforms/Utils/SimplifyCFG.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,14 @@ static bool HoistThenElseCodeToIf(BranchInst *BI,
13721372
}
13731373
}
13741374

1375+
// As the parent basic block terminator is a branch instruction which is
1376+
// removed at the end of the current transformation, use its previous
1377+
// non-debug instruction, as the reference insertion point, which will
1378+
// provide the debug location for the instruction being hoisted. For BBs
1379+
// with only debug instructions, use an empty debug location.
1380+
Instruction *InsertPt =
1381+
BIParent->getTerminator()->getPrevNonDebugInstruction();
1382+
13751383
// Okay, it is safe to hoist the terminator.
13761384
Instruction *NT = I1->clone();
13771385
BIParent->getInstList().insert(BI->getIterator(), NT);
@@ -1381,6 +1389,14 @@ static bool HoistThenElseCodeToIf(BranchInst *BI,
13811389
NT->takeName(I1);
13821390
}
13831391

1392+
// The instruction NT being hoisted, is the terminator for the true branch,
1393+
// with debug location (DILocation) within that branch. We can't retain
1394+
// its original debug location value, otherwise 'select' instructions that
1395+
// are created from any PHI nodes, will take its debug location, giving
1396+
// the impression that those 'select' instructions are in the true branch,
1397+
// causing incorrect stepping, affecting the debug experience.
1398+
NT->setDebugLoc(InsertPt ? InsertPt->getDebugLoc() : DebugLoc());
1399+
13841400
IRBuilder<NoFolder> Builder(NT);
13851401
// Hoisting one of the terminators from our successor is a great thing.
13861402
// Unfortunately, the successors of the if/else blocks may have PHI nodes in

test/CodeGen/X86/pr39187-g.ll

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
; RUN: opt < %s -S -simplifycfg | FileCheck %s
2+
3+
; SimplifyCFG can hoist any common code in the 'then' and 'else' blocks to
4+
; the 'if' basic block.
5+
;
6+
; For the special case, when hoisting the terminator instruction, its debug
7+
; location keep references to its basic block, causing the debug information
8+
; to become ambiguous. It causes the debugger to display unreached lines.
9+
10+
; Change the debug location associated with the hoisted instruction, to
11+
; the debug location from the insertion point in the 'if' block.
12+
13+
; The insertion point is the previous non-debug instruction before the
14+
; terminator in the parent basic block of the hoisted instruction.
15+
16+
; IR with '-g':
17+
;
18+
; [...]
19+
; %frombool = zext i1 %cmp to i8, !dbg !26
20+
; call void @llvm.dbg.value(metadata i8 %frombool, metadata !15, metadata !DIExpression()), !dbg !26
21+
; call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !27
22+
; br i1 %cmp, label %if.then, label %if.else
23+
; [...]
24+
;
25+
; Insertion point is: %frombool = zext i1 %cmp to i8, !dbg !26
26+
27+
; IR generated with:
28+
; clang -S -g -gno-column-info -O2 -emit-llvm pr39187.cpp -o pr39187-g.ll -mllvm -opt-bisect-limit=10
29+
30+
; // pr39187.cpp
31+
; int main() {
32+
; volatile int foo = 0;
33+
;
34+
; int beards = 0;
35+
; bool cond = foo == 4;
36+
; int bar = 0;
37+
; if (cond)
38+
; beards = 8;
39+
; else
40+
; beards = 4;
41+
;
42+
; volatile bool face = cond;
43+
;
44+
; return face ? beards : 0;
45+
; }
46+
47+
; CHECK-LABEL: entry
48+
; CHECK: %foo = alloca i32, align 4
49+
; CHECK: %face = alloca i8, align 1
50+
; CHECK: %foo.0..sroa_cast = bitcast i32* %foo to i8*
51+
; CHECK: store volatile i32 0, i32* %foo, align 4
52+
; CHECK: %foo.0. = load volatile i32, i32* %foo, align 4, !dbg !16
53+
; CHECK: %cmp = icmp eq i32 %foo.0., 4, !dbg !16
54+
; CHECK: %frombool = zext i1 %cmp to i8, !dbg !16
55+
; CHECK: call void @llvm.dbg.value(metadata i8 %frombool, metadata !13, metadata !DIExpression()), !dbg !16
56+
; CHECK: call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression()), !dbg !17
57+
; CHECK: %. = select i1 %cmp, i32 8, i32 4, !dbg !16
58+
59+
; ModuleID = 'pr39187.cpp'
60+
source_filename = "pr39187.cpp"
61+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
62+
target triple = "x86_64-pc-linux-gnu"
63+
64+
; Function Attrs: norecurse nounwind uwtable
65+
define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 {
66+
entry:
67+
%foo = alloca i32, align 4
68+
%face = alloca i8, align 1
69+
%foo.0..sroa_cast = bitcast i32* %foo to i8*
70+
store volatile i32 0, i32* %foo, align 4
71+
%foo.0. = load volatile i32, i32* %foo, align 4, !dbg !26
72+
%cmp = icmp eq i32 %foo.0., 4, !dbg !26
73+
%frombool = zext i1 %cmp to i8, !dbg !26
74+
call void @llvm.dbg.value(metadata i8 %frombool, metadata !15, metadata !DIExpression()), !dbg !26
75+
call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !27
76+
br i1 %cmp, label %if.then, label %if.else
77+
78+
if.then: ; preds = %entry
79+
call void @llvm.dbg.value(metadata i32 8, metadata !14, metadata !DIExpression()), !dbg !25
80+
br label %if.end
81+
82+
if.else: ; preds = %entry
83+
call void @llvm.dbg.value(metadata i32 4, metadata !14, metadata !DIExpression()), !dbg !25
84+
br label %if.end
85+
86+
if.end: ; preds = %if.else, %if.then
87+
%beards.0 = phi i32 [ 8, %if.then ], [ 4, %if.else ]
88+
store volatile i8 %frombool, i8* %face, align 1
89+
%face.0. = load volatile i8, i8* %face, align 1
90+
%0 = and i8 %face.0., 1
91+
%tobool3 = icmp eq i8 %0, 0
92+
%cond4 = select i1 %tobool3, i32 0, i32 %beards.0
93+
ret i32 %cond4
94+
}
95+
96+
; Function Attrs: nounwind readnone speculatable
97+
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
98+
99+
!llvm.dbg.cu = !{!0}
100+
!llvm.module.flags = !{!3, !4, !5}
101+
!llvm.ident = !{!6}
102+
103+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 346301)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
104+
!1 = !DIFile(filename: "pr39187.cpp", directory: ".")
105+
!2 = !{}
106+
!3 = !{i32 2, !"Dwarf Version", i32 4}
107+
!4 = !{i32 2, !"Debug Info Version", i32 3}
108+
!5 = !{i32 1, !"wchar_size", i32 4}
109+
!6 = !{!"clang version 8.0.0 (trunk 346301)"}
110+
!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
111+
!8 = !DISubroutineType(types: !9)
112+
!9 = !{!10}
113+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
114+
!11 = !{!14, !15, !17}
115+
!14 = !DILocalVariable(name: "beards", scope: !7, file: !1, line: 4, type: !10)
116+
!15 = !DILocalVariable(name: "cond", scope: !7, file: !1, line: 5, type: !16)
117+
!16 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
118+
!17 = !DILocalVariable(name: "bar", scope: !7, file: !1, line: 6, type: !10)
119+
!25 = !DILocation(line: 4, scope: !7)
120+
!26 = !DILocation(line: 5, scope: !7)
121+
!27 = !DILocation(line: 6, scope: !7)

0 commit comments

Comments
 (0)