Index: include/llvm/DebugInfo.h =================================================================== --- include/llvm/DebugInfo.h +++ include/llvm/DebugInfo.h @@ -521,7 +521,9 @@ DIScope getContext() const { return getFieldAs(2); } unsigned getLineNumber() const { return getUnsignedField(3); } unsigned getColumnNumber() const { return getUnsignedField(4); } + unsigned getDiscriminator() const { return getUnsignedField(5); } bool Verify() const; + void assignDiscriminator(LLVMContext &Ctx); }; /// DILexicalBlockFile - This is a wrapper for a lexical block with @@ -692,6 +694,14 @@ StringRef getFilename() const { return getScope().getFilename(); } StringRef getDirectory() const { return getScope().getDirectory(); } bool Verify() const; + bool atSameLineAs(const DILocation &Other) const { + return (getLineNumber() == Other.getLineNumber() && + getFilename() == Other.getFilename()); + } + unsigned getDiscriminator() const { + return getFieldAs(2).getDiscriminator(); + } + DILocation copyWithNewScope(LLVMContext &Ctx, DILexicalBlock NewScope); }; class DIObjCProperty : public DIDescriptor { Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -63,6 +63,7 @@ void initializeTarget(PassRegistry&); void initializeAAEvalPass(PassRegistry&); +void initializeAddDiscriminatorsPass(PassRegistry&); void initializeADCEPass(PassRegistry&); void initializeAliasAnalysisAnalysisGroup(PassRegistry&); void initializeAliasAnalysisCounterPass(PassRegistry&); Index: include/llvm/Transforms/Scalar.h =================================================================== --- include/llvm/Transforms/Scalar.h +++ include/llvm/Transforms/Scalar.h @@ -382,6 +382,11 @@ // FunctionPass *createScalarizerPass(); +//===----------------------------------------------------------------------===// +// +// AddDiscriminators - Add DWARF path discriminators to the IR. +FunctionPass *createAddDiscriminatorsPass(); + } // End llvm namespace #endif Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1847,6 +1847,7 @@ StringRef Fn; StringRef Dir; unsigned Src = 1; + unsigned Discriminator = 0; if (S) { DIDescriptor Scope(S); @@ -1870,13 +1871,15 @@ DILexicalBlock DB(S); Fn = DB.getFilename(); Dir = DB.getDirectory(); + Discriminator = DB.getDiscriminator(); } else llvm_unreachable("Unexpected scope info"); Src = getOrCreateSourceID( Fn, Dir, Asm->OutStreamer.getContext().getDwarfCompileUnitID()); } - Asm->OutStreamer.EmitDwarfLocDirective(Src, Line, Col, Flags, 0, 0, Fn); + Asm->OutStreamer.EmitDwarfLocDirective(Src, Line, Col, Flags, 0, + Discriminator, Fn); } //===----------------------------------------------------------------------===// Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "LLVMContextImpl.h" #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" @@ -812,6 +813,31 @@ return DIArray(getNodeField(DbgNode, 11)); } +/// copyWithNewScope - Return a copy of this location with the given scope. +/// The scope is assigned a unique discriminator value. +DILocation DILocation::copyWithNewScope(LLVMContext &Ctx, + DILexicalBlock NewScope) { + SmallVector Elts; + for (unsigned I = 0; I < DbgNode->getNumOperands(); ++I) + Elts.push_back(DbgNode->getOperand(I)); + MDNode *NewDIL = MDNode::get(Ctx, Elts); + NewDIL->replaceOperandWith(2, NewScope); + return DILocation(NewDIL); +} + +/// assignDiscriminator - Compute a new discriminator for this lexical scope. +/// +/// Discriminator values are guaranteed to be unique for every file:line +/// pair. If another discriminator existed for the file and line in this +/// scope, a new one will be created. +void DILexicalBlock::assignDiscriminator(LLVMContext &Ctx) { + std::pair Key(getFilename().data(), getLineNumber()); + unsigned NewDiscriminator = ++Ctx.pImpl->DiscriminatorTable[Key]; + DILexicalBlock B(*this); + B->replaceOperandWith( + 5, ConstantInt::get(Type::getInt32Ty(Ctx), NewDiscriminator)); +} + /// fixupSubprogramName - Replace contains special characters used /// in a typical Objective-C names with '.' in a given string. static void fixupSubprogramName(DISubprogram Fn, SmallVectorImpl &Out) { Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -352,7 +352,12 @@ /// for an index. The ValueHandle ensures that ScopeINlinedAtIdx stays up /// to date. std::vector > ScopeInlinedAtRecords; - + + /// DiscriminatorTable - This table maps file:line locations to an + /// integer representing the next DWARF path discriminator to assign to + /// instructions in different blocks at the same location. + DenseMap, unsigned> DiscriminatorTable; + /// IntrinsicIDCache - Cache of intrinsic name (string) to numeric ID mappings /// requested in this context typedef DenseMap IntrinsicIDCacheTy; Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -263,6 +263,9 @@ unsigned Isa, unsigned Discriminator, StringRef FileName) { + if (::getenv("LLVM_HACK")) + errs() << "MCObjectStreamer::EmitDwarfLocDirective: " << Line << ":" + << Column << ":" << Discriminator << "\n"; // In case we see two .loc directives in a row, make sure the // first one gets a line entry. MCLineEntry::Make(this, getCurrentSection().first); Index: lib/Transforms/Scalar/SampleProfile.cpp =================================================================== --- lib/Transforms/Scalar/SampleProfile.cpp +++ lib/Transforms/Scalar/SampleProfile.cpp @@ -991,6 +991,7 @@ INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(PostDominatorTree) INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_DEPENDENCY(AddDiscriminators) INITIALIZE_PASS_END(SampleProfileLoader, "sample-profile", "Sample Profile loader", false, false) Index: lib/Transforms/Utils/AddDiscriminators.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/AddDiscriminators.cpp @@ -0,0 +1,147 @@ +//===- AddDiscriminators.cpp - Insert DWARF path discriminators -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file adds DWARF discriminators to the IR. Path discriminators are +// used to decide what CFG path was taken inside sub-graphs whose instructions +// share the same line and column number information. +// +// The main user of this is the sample profiler. Instruction samples are +// mapped to line number information. Since a single line may be spread +// out over several basic blocks, discriminators add more precise location +// for the samples. +// +// For example, +// +// 1 #define ASSERT(P) +// 2 if (!(P)) +// 3 abort() +// ... +// 100 while (true) { +// 101 ASSERT (sum < 0); +// 102 ... +// 130 } +// +// when converted to IR, this snippet looks something like: +// +// while.body: ; preds = %entry, %if.end +// %0 = load i32* %sum, align 4, !dbg !15 +// %cmp = icmp slt i32 %0, 0, !dbg !15 +// br i1 %cmp, label %if.end, label %if.then, !dbg !15 +// +// if.then: ; preds = %while.body +// call void @abort(), !dbg !15 +// br label %if.end, !dbg !15 +// +// Notice that all the instructions in blocks 'while.body' and 'if.then' +// have exactly the same debug information. When this program is sampled +// at runtime, the profiler will assume that all these instructions are +// equally frequent. This, in turn, will consider the edge while.body->if.then +// to be frequently taken (which is incorrect). +// +// By adding a discriminator value to the instructions in block 'if.then', +// we can distinguish instructions at line 101 with discriminator 0 from +// the instructions at line 101 with discriminator 1. +// +// For more details about DWARF discriminators, please visit +// http://wiki.dwarfstd.org/index.php?title=Path_Discriminators +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "add-discriminators" + +#include "llvm/Transforms/Scalar.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + struct AddDiscriminators : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + AddDiscriminators() : FunctionPass(ID) { + initializeAddDiscriminatorsPass(*PassRegistry::getPassRegistry()); + } + + virtual bool runOnFunction(Function &F); + }; +} + +char AddDiscriminators::ID = 0; +INITIALIZE_PASS_BEGIN(AddDiscriminators, "add-discriminators", + "Add DWARF path discriminators", false, false) +INITIALIZE_PASS_END(AddDiscriminators, "add-discriminators", + "Add DWARF path discriminators", false, false) + +FunctionPass *llvm::createAddDiscriminatorsPass() { + return new AddDiscriminators(); +} + +static bool hasDebugInfo(const Function &F) { + NamedMDNode *CUNodes = F.getParent()->getNamedMetadata("llvm.dbg.cu"); + return CUNodes != 0; +} + +/// \brief Assign DWARF discriminators. +/// +/// TODO - Document +bool AddDiscriminators::runOnFunction(Function &F) { + if (!hasDebugInfo(F)) + return false; + + bool Changed = false; + Module *M = F.getParent(); + LLVMContext &Ctx = M->getContext(); + DIBuilder Builder(*M); + for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) { + BasicBlock *B = I; + TerminatorInst *Last = B->getTerminator(); + DebugLoc LastLoc = Last->getDebugLoc(); + if (LastLoc.isUnknown()) + continue; + DILocation LastDIL(LastLoc.getAsMDNode(Ctx)); + + for (unsigned I = 0; I < Last->getNumSuccessors(); ++I) { + BasicBlock *Succ = Last->getSuccessor(I); + Instruction *First = Succ->getFirstNonPHIOrDbgOrLifetime(); + DebugLoc FirstLoc = First->getDebugLoc(); + if (FirstLoc.isUnknown()) + continue; + DILocation FirstDIL(FirstLoc.getAsMDNode(Ctx)); + + // If the first instruction of B's successor is at the same + // file location as B's last instruction, add a new discriminator + // for the first instruction's location. + if (FirstDIL.atSameLineAs(LastDIL)) { + // Create a new lexical scope and compute a new discriminator + // number for it. + DIScope Scope = FirstDIL.getScope(); + DIFile File = + Builder.createFile(FirstDIL.getFilename(), Scope.getDirectory()); + DILexicalBlock NewScope = Builder.createLexicalBlock( + Scope, File, FirstDIL.getLineNumber(), FirstDIL.getColumnNumber()); + NewScope.assignDiscriminator(Ctx); + + DILocation NewDIL = FirstDIL.copyWithNewScope(Ctx, NewScope); + DebugLoc newDebugLoc = DebugLoc::getFromDILocation(NewDIL); + First->setDebugLoc(newDebugLoc); + DEBUG(dbgs() << NewDIL.getFilename() << ":" << NewDIL.getLineNumber() + << ":" << NewDIL.getDiscriminator() << *First << "\n"); + Changed = true; + } + } + } + return Changed; +} Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMTransformUtils + AddDiscriminators.cpp ASanStackFrameLayout.cpp BasicBlockUtils.cpp BreakCriticalEdges.cpp Index: lib/Transforms/Utils/Utils.cpp =================================================================== --- lib/Transforms/Utils/Utils.cpp +++ lib/Transforms/Utils/Utils.cpp @@ -21,6 +21,7 @@ /// initializeTransformUtils - Initialize all passes in the TransformUtils /// library. void llvm::initializeTransformUtils(PassRegistry &Registry) { + initializeAddDiscriminatorsPass(Registry); initializeBreakCriticalEdgesPass(Registry); initializeInstNamerPass(Registry); initializeLCSSAPass(Registry);