// http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "add-discriminators"
-
#include "llvm/Transforms/Scalar.h"
-#include "llvm/DIBuilder.h"
-#include "llvm/DebugInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
using namespace llvm;
+#define DEBUG_TYPE "add-discriminators"
+
namespace {
- struct AddDiscriminators : public FunctionPass {
- static char ID; // Pass identification, replacement for typeid
- AddDiscriminators() : FunctionPass(ID) {
- initializeAddDiscriminatorsPass(*PassRegistry::getPassRegistry());
- }
+struct AddDiscriminators : public FunctionPass {
+ static char ID; // Pass identification, replacement for typeid
+ AddDiscriminators() : FunctionPass(ID) {
+ initializeAddDiscriminatorsPass(*PassRegistry::getPassRegistry());
+ }
- bool runOnFunction(Function &F) override;
- };
+ bool runOnFunction(Function &F) override;
+};
}
char AddDiscriminators::ID = 0;
// Command line option to disable discriminator generation even in the
// presence of debug information. This is only needed when debugging
// debug info generation issues.
-static cl::opt<bool>
-NoDiscriminators("no-discriminators", cl::init(false),
- cl::desc("Disable generation of discriminator information."));
+static cl::opt<bool> NoDiscriminators(
+ "no-discriminators", cl::init(false),
+ cl::desc("Disable generation of discriminator information."));
FunctionPass *llvm::createAddDiscriminatorsPass() {
return new AddDiscriminators();
static bool hasDebugInfo(const Function &F) {
NamedMDNode *CUNodes = F.getParent()->getNamedMetadata("llvm.dbg.cu");
- return CUNodes != 0;
+ return CUNodes != nullptr;
}
/// \brief Assign DWARF discriminators.
/// file and line location as I2. This new lexical block will have a
/// different discriminator number than I1.
bool AddDiscriminators::runOnFunction(Function &F) {
- // No need to do anything if there is no debug info for this function.
// If the function has debug information, but the user has disabled
// discriminators, do nothing.
- if (!hasDebugInfo(F) || NoDiscriminators) return false;
+ // Simlarly, if the function has no debug info, do nothing.
+ // Finally, if this module is built with dwarf versions earlier than 4,
+ // do nothing (discriminator support is a DWARF 4 feature).
+ if (NoDiscriminators || !hasDebugInfo(F) ||
+ F.getParent()->getDwarfVersion() < 4)
+ return false;
bool Changed = false;
Module *M = F.getParent();
LLVMContext &Ctx = M->getContext();
- DIBuilder Builder(*M);
+ DIBuilder Builder(*M, /*AllowUnresolved*/ false);
// Traverse all the blocks looking for instructions in different
// blocks that are at the same file:line location.
- 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 (BasicBlock &B : F) {
+ TerminatorInst *Last = B.getTerminator();
+ const DILocation *LastDIL = Last->getDebugLoc();
+ if (!LastDIL)
+ continue;
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));
+ const DILocation *FirstDIL = First->getDebugLoc();
+ if (!FirstDIL || FirstDIL->getDiscriminator())
+ continue;
// If the first instruction (First) of Succ is at the same file
// location as B's last instruction (Last), add a new
// discriminator for First's location and all the instructions
// in Succ that share the same location with First.
- if (FirstDIL.atSameLineAs(LastDIL)) {
+ if (!FirstDIL->canDiscriminate(*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);
+ StringRef Filename = FirstDIL->getFilename();
+ auto *Scope = FirstDIL->getScope();
+ auto *File = Builder.createFile(Filename, Scope->getDirectory());
+
+ // FIXME: Calculate the discriminator here, based on local information,
+ // and delete DILocation::computeNewDiscriminator(). The current
+ // solution gives different results depending on other modules in the
+ // same context. All we really need is to discriminate between
+ // FirstDIL and LastDIL -- a local map would suffice.
+ unsigned Discriminator = FirstDIL->computeNewDiscriminator();
+ auto *NewScope =
+ Builder.createLexicalBlockFile(Scope, File, Discriminator);
// Attach this new debug location to First and every
// instruction following First that shares the same location.
for (BasicBlock::iterator I1(*First), E1 = Succ->end(); I1 != E1;
++I1) {
- if (I1->getDebugLoc() != FirstLoc) break;
- I1->setDebugLoc(newDebugLoc);
- DEBUG(dbgs() << NewDIL.getFilename() << ":" << NewDIL.getLineNumber()
- << ":" << NewDIL.getColumnNumber() << ":"
- << NewDIL.getDiscriminator() << *I1 << "\n");
+ const DILocation *CurrentDIL = I1->getDebugLoc();
+ if (CurrentDIL && CurrentDIL->getLine() == FirstDIL->getLine() &&
+ CurrentDIL->getFilename() == FirstDIL->getFilename()) {
+ I1->setDebugLoc(DILocation::get(Ctx, CurrentDIL->getLine(),
+ CurrentDIL->getColumn(), NewScope,
+ CurrentDIL->getInlinedAt()));
+ DEBUG(dbgs() << CurrentDIL->getFilename() << ":"
+ << CurrentDIL->getLine() << ":"
+ << CurrentDIL->getColumn() << ":"
+ << CurrentDIL->getDiscriminator() << *I1 << "\n");
+ }
}
DEBUG(dbgs() << "\n");
Changed = true;
}
}
}
+
+ // Traverse all instructions and assign new discriminators to call
+ // instructions with the same lineno that are in the same basic block.
+ // Sample base profile needs to distinguish different function calls within
+ // a same source line for correct profile annotation.
+ for (BasicBlock &B : F) {
+ const DILocation *FirstDIL = NULL;
+ for (auto &I : B.getInstList()) {
+ CallInst *Current = dyn_cast<CallInst>(&I);
+ if (Current) {
+ DILocation *CurrentDIL = Current->getDebugLoc();
+ if (FirstDIL) {
+ if (CurrentDIL && CurrentDIL->getLine() == FirstDIL->getLine() &&
+ CurrentDIL->getFilename() == FirstDIL->getFilename()) {
+ auto *Scope = FirstDIL->getScope();
+ auto *File = Builder.createFile(FirstDIL->getFilename(),
+ Scope->getDirectory());
+ auto *NewScope = Builder.createLexicalBlockFile(
+ Scope, File, FirstDIL->computeNewDiscriminator());
+ Current->setDebugLoc(DILocation::get(
+ Ctx, CurrentDIL->getLine(), CurrentDIL->getColumn(), NewScope,
+ CurrentDIL->getInlinedAt()));
+ Changed = true;
+ } else {
+ FirstDIL = CurrentDIL;
+ }
+ } else {
+ FirstDIL = CurrentDIL;
+ }
+ }
+ }
+ }
return Changed;
}