Index: include/llvm/DIBuilder.h =================================================================== --- include/llvm/DIBuilder.h +++ include/llvm/DIBuilder.h @@ -630,12 +630,14 @@ /// createLexicalBlock - This creates a descriptor for a lexical block /// with the specified parent context. - /// @param Scope Parent lexical scope. - /// @param File Source file - /// @param Line Line number - /// @param Col Column number + /// @param Scope Parent lexical scope. + /// @param File Source file. + /// @param Line Line number. + /// @param Col Column number. + /// @param Discriminator DWARF path discriminator value. DILexicalBlock createLexicalBlock(DIDescriptor Scope, DIFile File, - unsigned Line, unsigned Col); + unsigned Line, unsigned Col, + unsigned Discriminator); /// \brief Create a descriptor for an imported module. /// @param Context The scope this module is imported into Index: include/llvm/DebugInfo.h =================================================================== --- include/llvm/DebugInfo.h +++ include/llvm/DebugInfo.h @@ -521,6 +521,7 @@ 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; }; @@ -692,6 +693,15 @@ 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(); + } + unsigned computeNewDiscriminator(LLVMContext &Ctx); + 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/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -1179,7 +1179,8 @@ } DILexicalBlock DIBuilder::createLexicalBlock(DIDescriptor Scope, DIFile File, - unsigned Line, unsigned Col) { + unsigned Line, unsigned Col, + unsigned Discriminator) { // Defeat MDNode uniquing for lexical blocks by using unique id. static unsigned int unique_id = 0; Value *Elts[] = { @@ -1188,6 +1189,7 @@ getNonCompileUnitScope(Scope), ConstantInt::get(Type::getInt32Ty(VMContext), Line), ConstantInt::get(Type::getInt32Ty(VMContext), Col), + ConstantInt::get(Type::getInt32Ty(VMContext), Discriminator), ConstantInt::get(Type::getInt32Ty(VMContext), unique_id++) }; DILexicalBlock R(MDNode::get(VMContext, Elts)); 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" @@ -599,7 +600,7 @@ /// \brief Verify that the lexical block descriptor is well formed. bool DILexicalBlock::Verify() const { - return isLexicalBlock() && DbgNode->getNumOperands() == 6; + return isLexicalBlock() && DbgNode->getNumOperands() == 7; } /// \brief Verify that the file-scoped lexical block descriptor is well formed. @@ -812,6 +813,30 @@ 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; + assert(DbgNode->getNumOperands() > 2 && + "There should be more than 2 operands in this DILocation"); + for (unsigned I = 0; I < DbgNode->getNumOperands(); ++I) { + if (I != 2) + Elts.push_back(DbgNode->getOperand(I)); + else + Elts.push_back(NewScope); + } + MDNode *NewDIL = MDNode::get(Ctx, Elts); + return DILocation(NewDIL); +} + +/// computeNewDiscriminator - Generate a new discriminator value for this +/// file and line location. +unsigned DILocation::computeNewDiscriminator(LLVMContext &Ctx) { + std::pair Key(getFilename().data(), getLineNumber()); + return ++Ctx.pImpl->DiscriminatorTable[Key]; +} + /// 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,148 @@ +//===- 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. + StringRef Filename = FirstDIL.getFilename(); + unsigned LineNumber = FirstDIL.getLineNumber(); + unsigned ColumnNumber = FirstDIL.getColumnNumber(); + DIScope Scope = FirstDIL.getScope(); + DIFile File = Builder.createFile(Filename, Scope.getDirectory()); + unsigned Discriminator = FirstDIL.computeNewDiscriminator(Ctx); + DILexicalBlock NewScope = Builder.createLexicalBlock( + Scope, File, LineNumber, ColumnNumber, Discriminator); + 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);