Skip to content

Commit f05b45f

Browse files
author
Diego Novillo
committed
Pass to emit DWARF path discriminators.
DWARF discriminators are used to distinguish multiple control flow paths on the same source location. When this happens, instructions across basic block boundaries will share the same debug location. This pass detects this situation and creates a new lexical scope to one of the two instructions. This lexical scope is a child scope of the original and contains a new discriminator value. This discriminator is then picked up from MCObjectStreamer::EmitDwarfLocDirective to be written on the object file. This fixes http://llvm.org/bugs/show_bug.cgi?id=18270. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202752 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 9efaf2f commit f05b45f

File tree

11 files changed

+488
-1
lines changed

11 files changed

+488
-1
lines changed

include/llvm/DebugInfo.h

+21
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,27 @@ class DILocation : public DIDescriptor {
701701
StringRef getFilename() const { return getScope().getFilename(); }
702702
StringRef getDirectory() const { return getScope().getDirectory(); }
703703
bool Verify() const;
704+
bool atSameLineAs(const DILocation &Other) const {
705+
return (getLineNumber() == Other.getLineNumber() &&
706+
getFilename() == Other.getFilename());
707+
}
708+
/// getDiscriminator - DWARF discriminators are used to distinguish
709+
/// identical file locations for instructions that are on different
710+
/// basic blocks. If two instructions are inside the same lexical block
711+
/// and are in different basic blocks, we create a new lexical block
712+
/// with identical location as the original but with a different
713+
/// discriminator value (lib/Transforms/Util/AddDiscriminators.cpp
714+
/// for details).
715+
unsigned getDiscriminator() const {
716+
// Since discriminators are associated with lexical blocks, make
717+
// sure this location is a lexical block before retrieving its
718+
// value.
719+
return getScope().isLexicalBlock()
720+
? getFieldAs<DILexicalBlock>(2).getDiscriminator()
721+
: 0;
722+
}
723+
unsigned computeNewDiscriminator(LLVMContext &Ctx);
724+
DILocation copyWithNewScope(LLVMContext &Ctx, DILexicalBlock NewScope);
704725
};
705726

706727
class DIObjCProperty : public DIDescriptor {

include/llvm/InitializePasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void initializeCodeGen(PassRegistry&);
6363
void initializeTarget(PassRegistry&);
6464

6565
void initializeAAEvalPass(PassRegistry&);
66+
void initializeAddDiscriminatorsPass(PassRegistry&);
6667
void initializeADCEPass(PassRegistry&);
6768
void initializeAliasAnalysisAnalysisGroup(PassRegistry&);
6869
void initializeAliasAnalysisCounterPass(PassRegistry&);

include/llvm/Transforms/Scalar.h

+5
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,11 @@ FunctionPass *createSampleProfileLoaderPass(StringRef Name);
376376
//
377377
FunctionPass *createScalarizerPass();
378378

379+
//===----------------------------------------------------------------------===//
380+
//
381+
// AddDiscriminators - Add DWARF path discriminators to the IR.
382+
FunctionPass *createAddDiscriminatorsPass();
383+
379384
} // End llvm namespace
380385

381386
#endif

lib/IR/DebugInfo.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/IR/Instructions.h"
2323
#include "llvm/IR/IntrinsicInst.h"
2424
#include "llvm/IR/Intrinsics.h"
25+
#include "LLVMContextImpl.h"
2526
#include "llvm/IR/Module.h"
2627
#include "llvm/Support/Debug.h"
2728
#include "llvm/Support/Dwarf.h"
@@ -818,6 +819,29 @@ DIArray DICompileUnit::getImportedEntities() const {
818819
return DIArray(getNodeField(DbgNode, 11));
819820
}
820821

822+
/// copyWithNewScope - Return a copy of this location, replacing the
823+
/// current scope with the given one.
824+
DILocation DILocation::copyWithNewScope(LLVMContext &Ctx,
825+
DILexicalBlock NewScope) {
826+
SmallVector<Value *, 10> Elts;
827+
assert(Verify());
828+
for (unsigned I = 0; I < DbgNode->getNumOperands(); ++I) {
829+
if (I != 2)
830+
Elts.push_back(DbgNode->getOperand(I));
831+
else
832+
Elts.push_back(NewScope);
833+
}
834+
MDNode *NewDIL = MDNode::get(Ctx, Elts);
835+
return DILocation(NewDIL);
836+
}
837+
838+
/// computeNewDiscriminator - Generate a new discriminator value for this
839+
/// file and line location.
840+
unsigned DILocation::computeNewDiscriminator(LLVMContext &Ctx) {
841+
std::pair<const char *, unsigned> Key(getFilename().data(), getLineNumber());
842+
return ++Ctx.pImpl->DiscriminatorTable[Key];
843+
}
844+
821845
/// fixupSubprogramName - Replace contains special characters used
822846
/// in a typical Objective-C names with '.' in a given string.
823847
static void fixupSubprogramName(DISubprogram Fn, SmallVectorImpl<char> &Out) {

lib/IR/LLVMContextImpl.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,12 @@ class LLVMContextImpl {
352352
/// for an index. The ValueHandle ensures that ScopeINlinedAtIdx stays up
353353
/// to date.
354354
std::vector<std::pair<DebugRecVH, DebugRecVH> > ScopeInlinedAtRecords;
355-
355+
356+
/// DiscriminatorTable - This table maps file:line locations to an
357+
/// integer representing the next DWARF path discriminator to assign to
358+
/// instructions in different blocks at the same location.
359+
DenseMap<std::pair<const char *, unsigned>, unsigned> DiscriminatorTable;
360+
356361
/// IntrinsicIDCache - Cache of intrinsic name (string) to numeric ID mappings
357362
/// requested in this context
358363
typedef DenseMap<const Function*, unsigned> IntrinsicIDCacheTy;
+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
//===- AddDiscriminators.cpp - Insert DWARF path discriminators -----------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file adds DWARF discriminators to the IR. Path discriminators are
11+
// used to decide what CFG path was taken inside sub-graphs whose instructions
12+
// share the same line and column number information.
13+
//
14+
// The main user of this is the sample profiler. Instruction samples are
15+
// mapped to line number information. Since a single line may be spread
16+
// out over several basic blocks, discriminators add more precise location
17+
// for the samples.
18+
//
19+
// For example,
20+
//
21+
// 1 #define ASSERT(P)
22+
// 2 if (!(P))
23+
// 3 abort()
24+
// ...
25+
// 100 while (true) {
26+
// 101 ASSERT (sum < 0);
27+
// 102 ...
28+
// 130 }
29+
//
30+
// when converted to IR, this snippet looks something like:
31+
//
32+
// while.body: ; preds = %entry, %if.end
33+
// %0 = load i32* %sum, align 4, !dbg !15
34+
// %cmp = icmp slt i32 %0, 0, !dbg !15
35+
// br i1 %cmp, label %if.end, label %if.then, !dbg !15
36+
//
37+
// if.then: ; preds = %while.body
38+
// call void @abort(), !dbg !15
39+
// br label %if.end, !dbg !15
40+
//
41+
// Notice that all the instructions in blocks 'while.body' and 'if.then'
42+
// have exactly the same debug information. When this program is sampled
43+
// at runtime, the profiler will assume that all these instructions are
44+
// equally frequent. This, in turn, will consider the edge while.body->if.then
45+
// to be frequently taken (which is incorrect).
46+
//
47+
// By adding a discriminator value to the instructions in block 'if.then',
48+
// we can distinguish instructions at line 101 with discriminator 0 from
49+
// the instructions at line 101 with discriminator 1.
50+
//
51+
// For more details about DWARF discriminators, please visit
52+
// http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
53+
//===----------------------------------------------------------------------===//
54+
55+
#define DEBUG_TYPE "add-discriminators"
56+
57+
#include "llvm/Transforms/Scalar.h"
58+
#include "llvm/DebugInfo.h"
59+
#include "llvm/DIBuilder.h"
60+
#include "llvm/IR/BasicBlock.h"
61+
#include "llvm/IR/Instructions.h"
62+
#include "llvm/IR/LLVMContext.h"
63+
#include "llvm/IR/Constants.h"
64+
#include "llvm/IR/Module.h"
65+
#include "llvm/Pass.h"
66+
#include "llvm/Support/CommandLine.h"
67+
#include "llvm/Support/Debug.h"
68+
#include "llvm/Support/raw_ostream.h"
69+
70+
using namespace llvm;
71+
72+
namespace {
73+
struct AddDiscriminators : public FunctionPass {
74+
static char ID; // Pass identification, replacement for typeid
75+
AddDiscriminators() : FunctionPass(ID) {
76+
initializeAddDiscriminatorsPass(*PassRegistry::getPassRegistry());
77+
}
78+
79+
virtual bool runOnFunction(Function &F);
80+
};
81+
}
82+
83+
char AddDiscriminators::ID = 0;
84+
INITIALIZE_PASS_BEGIN(AddDiscriminators, "add-discriminators",
85+
"Add DWARF path discriminators", false, false)
86+
INITIALIZE_PASS_END(AddDiscriminators, "add-discriminators",
87+
"Add DWARF path discriminators", false, false)
88+
89+
// Command line option to disable discriminator generation even in the
90+
// presence of debug information. This is only needed when debugging
91+
// debug info generation issues.
92+
static cl::opt<bool>
93+
NoDiscriminators("no-discriminators", cl::init(false),
94+
cl::desc("Disable generation of discriminator information."));
95+
96+
FunctionPass *llvm::createAddDiscriminatorsPass() {
97+
return new AddDiscriminators();
98+
}
99+
100+
static bool hasDebugInfo(const Function &F) {
101+
NamedMDNode *CUNodes = F.getParent()->getNamedMetadata("llvm.dbg.cu");
102+
return CUNodes != 0;
103+
}
104+
105+
/// \brief Assign DWARF discriminators.
106+
///
107+
/// To assign discriminators, we examine the boundaries of every
108+
/// basic block and its successors. Suppose there is a basic block B1
109+
/// with successor B2. The last instruction I1 in B1 and the first
110+
/// instruction I2 in B2 are located at the same file and line number.
111+
/// This situation is illustrated in the following code snippet:
112+
///
113+
/// if (i < 10) x = i;
114+
///
115+
/// entry:
116+
/// br i1 %cmp, label %if.then, label %if.end, !dbg !10
117+
/// if.then:
118+
/// %1 = load i32* %i.addr, align 4, !dbg !10
119+
/// store i32 %1, i32* %x, align 4, !dbg !10
120+
/// br label %if.end, !dbg !10
121+
/// if.end:
122+
/// ret void, !dbg !12
123+
///
124+
/// Notice how the branch instruction in block 'entry' and all the
125+
/// instructions in block 'if.then' have the exact same debug location
126+
/// information (!dbg !10).
127+
///
128+
/// To distinguish instructions in block 'entry' from instructions in
129+
/// block 'if.then', we generate a new lexical block for all the
130+
/// instruction in block 'if.then' that share the same file and line
131+
/// location with the last instruction of block 'entry'.
132+
///
133+
/// This new lexical block will have the same location information as
134+
/// the previous one, but with a new DWARF discriminator value.
135+
///
136+
/// One of the main uses of this discriminator value is in runtime
137+
/// sample profilers. It allows the profiler to distinguish instructions
138+
/// at location !dbg !10 that execute on different basic blocks. This is
139+
/// important because while the predicate 'if (x < 10)' may have been
140+
/// executed millions of times, the assignment 'x = i' may have only
141+
/// executed a handful of times (meaning that the entry->if.then edge is
142+
/// seldom taken).
143+
///
144+
/// If we did not have discriminator information, the profiler would
145+
/// assign the same weight to both blocks 'entry' and 'if.then', which
146+
/// in turn will make it conclude that the entry->if.then edge is very
147+
/// hot.
148+
///
149+
/// To decide where to create new discriminator values, this function
150+
/// traverses the CFG and examines instruction at basic block boundaries.
151+
/// If the last instruction I1 of a block B1 is at the same file and line
152+
/// location as instruction I2 of successor B2, then it creates a new
153+
/// lexical block for I2 and all the instruction in B2 that share the same
154+
/// file and line location as I2. This new lexical block will have a
155+
/// different discriminator number than I1.
156+
bool AddDiscriminators::runOnFunction(Function &F) {
157+
// No need to do anything if there is no debug info for this function.
158+
// If the function has debug information, but the user has disabled
159+
// discriminators, do nothing.
160+
if (!hasDebugInfo(F) || NoDiscriminators) return false;
161+
162+
bool Changed = false;
163+
Module *M = F.getParent();
164+
LLVMContext &Ctx = M->getContext();
165+
DIBuilder Builder(*M);
166+
167+
// Traverse all the blocks looking for instructions in different
168+
// blocks that are at the same file:line location.
169+
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
170+
BasicBlock *B = I;
171+
TerminatorInst *Last = B->getTerminator();
172+
DebugLoc LastLoc = Last->getDebugLoc();
173+
if (LastLoc.isUnknown()) continue;
174+
DILocation LastDIL(LastLoc.getAsMDNode(Ctx));
175+
176+
for (unsigned I = 0; I < Last->getNumSuccessors(); ++I) {
177+
BasicBlock *Succ = Last->getSuccessor(I);
178+
Instruction *First = Succ->getFirstNonPHIOrDbgOrLifetime();
179+
DebugLoc FirstLoc = First->getDebugLoc();
180+
if (FirstLoc.isUnknown()) continue;
181+
DILocation FirstDIL(FirstLoc.getAsMDNode(Ctx));
182+
183+
// If the first instruction (First) of Succ is at the same file
184+
// location as B's last instruction (Last), add a new
185+
// discriminator for First's location and all the instructions
186+
// in Succ that share the same location with First.
187+
if (FirstDIL.atSameLineAs(LastDIL)) {
188+
// Create a new lexical scope and compute a new discriminator
189+
// number for it.
190+
StringRef Filename = FirstDIL.getFilename();
191+
unsigned LineNumber = FirstDIL.getLineNumber();
192+
unsigned ColumnNumber = FirstDIL.getColumnNumber();
193+
DIScope Scope = FirstDIL.getScope();
194+
DIFile File = Builder.createFile(Filename, Scope.getDirectory());
195+
unsigned Discriminator = FirstDIL.computeNewDiscriminator(Ctx);
196+
DILexicalBlock NewScope = Builder.createLexicalBlock(
197+
Scope, File, LineNumber, ColumnNumber, Discriminator);
198+
DILocation NewDIL = FirstDIL.copyWithNewScope(Ctx, NewScope);
199+
DebugLoc newDebugLoc = DebugLoc::getFromDILocation(NewDIL);
200+
201+
// Attach this new debug location to First and every
202+
// instruction following First that shares the same location.
203+
for (BasicBlock::iterator I1(*First), E1 = Succ->end(); I1 != E1;
204+
++I1) {
205+
if (I1->getDebugLoc() != FirstLoc) break;
206+
I1->setDebugLoc(newDebugLoc);
207+
DEBUG(dbgs() << NewDIL.getFilename() << ":" << NewDIL.getLineNumber()
208+
<< ":" << NewDIL.getColumnNumber() << ":"
209+
<< NewDIL.getDiscriminator() << *I1 << "\n");
210+
}
211+
DEBUG(dbgs() << "\n");
212+
Changed = true;
213+
}
214+
}
215+
}
216+
return Changed;
217+
}

lib/Transforms/Utils/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_llvm_library(LLVMTransformUtils
2+
AddDiscriminators.cpp
23
ASanStackFrameLayout.cpp
34
BasicBlockUtils.cpp
45
BreakCriticalEdges.cpp

lib/Transforms/Utils/Utils.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ using namespace llvm;
2121
/// initializeTransformUtils - Initialize all passes in the TransformUtils
2222
/// library.
2323
void llvm::initializeTransformUtils(PassRegistry &Registry) {
24+
initializeAddDiscriminatorsPass(Registry);
2425
initializeBreakCriticalEdgesPass(Registry);
2526
initializeInstNamerPass(Registry);
2627
initializeLCSSAPass(Registry);
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
; RUN: opt < %s -add-discriminators -S | FileCheck %s
2+
3+
; Basic DWARF discriminator test. All the instructions in block
4+
; 'if.then' should have a different discriminator value than
5+
; the conditional branch at the end of block 'entry'.
6+
;
7+
; Original code:
8+
;
9+
; void foo(int i) {
10+
; int x;
11+
; if (i < 10) x = i;
12+
; }
13+
14+
define void @foo(i32 %i) #0 {
15+
entry:
16+
%i.addr = alloca i32, align 4
17+
%x = alloca i32, align 4
18+
store i32 %i, i32* %i.addr, align 4
19+
%0 = load i32* %i.addr, align 4, !dbg !10
20+
%cmp = icmp slt i32 %0, 10, !dbg !10
21+
br i1 %cmp, label %if.then, label %if.end, !dbg !10
22+
23+
if.then: ; preds = %entry
24+
%1 = load i32* %i.addr, align 4, !dbg !10
25+
; CHECK: %1 = load i32* %i.addr, align 4, !dbg !12
26+
27+
store i32 %1, i32* %x, align 4, !dbg !10
28+
; CHECK: store i32 %1, i32* %x, align 4, !dbg !12
29+
30+
br label %if.end, !dbg !10
31+
; CHECK: br label %if.end, !dbg !12
32+
33+
if.end: ; preds = %if.then, %entry
34+
ret void, !dbg !12
35+
}
36+
37+
attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
38+
39+
!llvm.dbg.cu = !{!0}
40+
!llvm.module.flags = !{!7, !8}
41+
!llvm.ident = !{!9}
42+
43+
!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [basic.c] [DW_LANG_C99]
44+
!1 = metadata !{metadata !"basic.c", metadata !"."}
45+
!2 = metadata !{}
46+
!3 = metadata !{metadata !4}
47+
!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32)* @foo, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [foo]
48+
!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [basic.c]
49+
!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
50+
!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
51+
!8 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
52+
!9 = metadata !{metadata !"clang version 3.5 "}
53+
!10 = metadata !{i32 3, i32 0, metadata !11, null}
54+
!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 3, i32 0, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [basic.c]
55+
!12 = metadata !{i32 4, i32 0, metadata !4, null}
56+
57+
; CHECK: !12 = metadata !{i32 3, i32 0, metadata !13, null}
58+
; CHECK: !13 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 1, i32 0} ; [ DW_TAG_lexical_block ] [./basic.c]
59+
; CHECK: !14 = metadata !{i32 4, i32 0, metadata !4, null}

0 commit comments

Comments
 (0)