Index: include/llvm/DebugInfo.h =================================================================== --- include/llvm/DebugInfo.h +++ include/llvm/DebugInfo.h @@ -211,6 +211,7 @@ StringRef getName() const; StringRef getFilename() const; StringRef getDirectory() const; + unsigned getDiscriminator() const { return getUnsignedField(6); } /// Generate a reference to this DIScope. Uses the type identifier instead /// of the actual MDNode if possible, to help type uniquing. @@ -692,6 +693,12 @@ 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 getScope().getDiscriminator(); } + DILocation copyWithNewDiscriminator(LLVMContext &Ctx); }; 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 @@ -1848,6 +1848,7 @@ StringRef Fn; StringRef Dir; unsigned Src = 1; + unsigned Discriminator = 0; if (S) { DIDescriptor Scope(S); @@ -1871,13 +1872,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,32 @@ return DIArray(getNodeField(DbgNode, 11)); } +/// addDiscriminator - Return a copy of this location with a new discriminator +/// computed for its scope. +DILocation DILocation::copyWithNewDiscriminator(LLVMContext &Ctx) { + // Compute a new discriminator for this file and line number. + std::pair Key(getFilename().data(), getLineNumber()); + unsigned NewDiscriminator = ++Ctx.pImpl->DiscriminatorTable[Key]; + + // Generate a new scope with the operands from the old one and a new + // operand with the value of the new discriminator. + SmallVector Elts; + MDNode *OldScope = getScope(); + for (unsigned I = 0; I < OldScope->getNumOperands(); ++I) + Elts.push_back(OldScope->getOperand(I)); + Elts.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), NewDiscriminator)); + MDNode *NewScope = MDNode::get(Ctx, Elts); + + // Create a copy of this DILocation with the new scope. + Elts.clear(); + 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); +} + /// 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,136 @@ +//===- 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/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(); + 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)) { + DILocation NewDIL = FirstDIL.copyWithNewDiscriminator(Ctx); + 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);