| //===-- DebugInfoProbe.cpp - DebugInfo Probe ------------------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements DebugInfoProbe. This probe can be used by a pass | |
| // manager to analyze how optimizer is treating debugging information. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #define DEBUG_TYPE "debuginfoprobe" | |
| #include "llvm/DebugInfoProbe.h" | |
| #include "llvm/Function.h" | |
| #include "llvm/IntrinsicInst.h" | |
| #include "llvm/Metadata.h" | |
| #include "llvm/PassManager.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/DebugLoc.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include <set> | |
| #include <string> | |
| using namespace llvm; | |
| static cl::opt<bool> | |
| EnableDebugInfoProbe("enable-debug-info-probe", cl::Hidden, | |
| cl::desc("Enable debug info probe")); | |
| // CreateInfoOutputFile - Return a file stream to print our output on. | |
| namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } | |
| //===----------------------------------------------------------------------===// | |
| // DebugInfoProbeImpl - This class implements a interface to monitor | |
| // how an optimization pass is preserving debugging information. | |
| namespace llvm { | |
| class DebugInfoProbeImpl { | |
| public: | |
| DebugInfoProbeImpl() : NumDbgLineLost(0),NumDbgValueLost(0) {} | |
| void initialize(StringRef PName, Function &F); | |
| void finalize(Function &F); | |
| void report(); | |
| private: | |
| unsigned NumDbgLineLost, NumDbgValueLost; | |
| std::string PassName; | |
| Function *TheFn; | |
| std::set<MDNode *> DbgVariables; | |
| std::set<Instruction *> MissingDebugLoc; | |
| }; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DebugInfoProbeImpl | |
| /// initialize - Collect information before running an optimization pass. | |
| void DebugInfoProbeImpl::initialize(StringRef PName, Function &F) { | |
| if (!EnableDebugInfoProbe) return; | |
| PassName = PName; | |
| DbgVariables.clear(); | |
| MissingDebugLoc.clear(); | |
| TheFn = &F; | |
| for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) | |
| for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); | |
| BI != BE; ++BI) { | |
| if (!isa<PHINode>(BI) && BI->getDebugLoc().isUnknown()) | |
| MissingDebugLoc.insert(BI); | |
| if (!isa<DbgInfoIntrinsic>(BI)) continue; | |
| Value *Addr = NULL; | |
| MDNode *Node = NULL; | |
| if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(BI)) { | |
| Addr = DDI->getAddress(); | |
| Node = DDI->getVariable(); | |
| } else if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(BI)) { | |
| Addr = DVI->getValue(); | |
| Node = DVI->getVariable(); | |
| } | |
| if (Addr) | |
| DbgVariables.insert(Node); | |
| } | |
| } | |
| /// report - Report findings. This should be invoked after finalize. | |
| void DebugInfoProbeImpl::report() { | |
| if (!EnableDebugInfoProbe) return; | |
| if (NumDbgLineLost || NumDbgValueLost) { | |
| raw_ostream *OutStream = CreateInfoOutputFile(); | |
| if (NumDbgLineLost) | |
| *OutStream << NumDbgLineLost | |
| << "\t times line number info lost by " | |
| << PassName << "\n"; | |
| if (NumDbgValueLost) | |
| *OutStream << NumDbgValueLost | |
| << "\t times variable info lost by " | |
| << PassName << "\n"; | |
| delete OutStream; | |
| } | |
| NumDbgLineLost = 0; | |
| NumDbgValueLost = 0; | |
| } | |
| /// finalize - Collect information after running an optimization pass. This | |
| /// must be used after initialization. | |
| void DebugInfoProbeImpl::finalize(Function &F) { | |
| if (!EnableDebugInfoProbe) return; | |
| assert (TheFn == &F && "Invalid function to measure!"); | |
| std::set<MDNode *>DbgVariables2; | |
| for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) | |
| for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); | |
| BI != BE; ++BI) { | |
| if (!isa<PHINode>(BI) && BI->getDebugLoc().isUnknown() && | |
| MissingDebugLoc.count(BI) == 0) { | |
| ++NumDbgLineLost; | |
| DEBUG(dbgs() << "DebugInfoProbe (" << PassName << "): --- "); | |
| DEBUG(BI->print(dbgs())); | |
| DEBUG(dbgs() << "\n"); | |
| } | |
| if (!isa<DbgInfoIntrinsic>(BI)) continue; | |
| Value *Addr = NULL; | |
| MDNode *Node = NULL; | |
| if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(BI)) { | |
| Addr = DDI->getAddress(); | |
| Node = DDI->getVariable(); | |
| } else if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(BI)) { | |
| Addr = DVI->getValue(); | |
| Node = DVI->getVariable(); | |
| } | |
| if (Addr) | |
| DbgVariables2.insert(Node); | |
| } | |
| for (std::set<MDNode *>::iterator I = DbgVariables.begin(), | |
| E = DbgVariables.end(); I != E; ++I) { | |
| if (DbgVariables2.count(*I) == 0 && (*I)->getNumOperands() >= 2) { | |
| DEBUG(dbgs() | |
| << "DebugInfoProbe(" | |
| << PassName | |
| << "): Losing dbg info for variable: "; | |
| if (MDString *MDS = dyn_cast_or_null<MDString>( | |
| (*I)->getOperand(2))) | |
| dbgs() << MDS->getString(); | |
| else | |
| dbgs() << "..."; | |
| dbgs() << "\n"); | |
| ++NumDbgValueLost; | |
| } | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DebugInfoProbe | |
| DebugInfoProbe::DebugInfoProbe() { | |
| pImpl = new DebugInfoProbeImpl(); | |
| } | |
| DebugInfoProbe::~DebugInfoProbe() { | |
| delete pImpl; | |
| } | |
| /// initialize - Collect information before running an optimization pass. | |
| void DebugInfoProbe::initialize(StringRef PName, Function &F) { | |
| pImpl->initialize(PName, F); | |
| } | |
| /// finalize - Collect information after running an optimization pass. This | |
| /// must be used after initialization. | |
| void DebugInfoProbe::finalize(Function &F) { | |
| pImpl->finalize(F); | |
| } | |
| /// report - Report findings. This should be invoked after finalize. | |
| void DebugInfoProbe::report() { | |
| pImpl->report(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DebugInfoProbeInfo | |
| /// ~DebugInfoProbeInfo - Report data collected by all probes before deleting | |
| /// them. | |
| DebugInfoProbeInfo::~DebugInfoProbeInfo() { | |
| if (!EnableDebugInfoProbe) return; | |
| for (StringMap<DebugInfoProbe*>::iterator I = Probes.begin(), | |
| E = Probes.end(); I != E; ++I) { | |
| I->second->report(); | |
| delete I->second; | |
| } | |
| } | |
| /// initialize - Collect information before running an optimization pass. | |
| void DebugInfoProbeInfo::initialize(Pass *P, Function &F) { | |
| if (!EnableDebugInfoProbe) return; | |
| if (P->getAsPMDataManager()) | |
| return; | |
| StringMapEntry<DebugInfoProbe *> &Entry = | |
| Probes.GetOrCreateValue(P->getPassName()); | |
| DebugInfoProbe *&Probe = Entry.getValue(); | |
| if (!Probe) | |
| Probe = new DebugInfoProbe(); | |
| Probe->initialize(P->getPassName(), F); | |
| } | |
| /// finalize - Collect information after running an optimization pass. This | |
| /// must be used after initialization. | |
| void DebugInfoProbeInfo::finalize(Pass *P, Function &F) { | |
| if (!EnableDebugInfoProbe) return; | |
| if (P->getAsPMDataManager()) | |
| return; | |
| StringMapEntry<DebugInfoProbe *> &Entry = | |
| Probes.GetOrCreateValue(P->getPassName()); | |
| DebugInfoProbe *&Probe = Entry.getValue(); | |
| assert (Probe && "DebugInfoProbe is not initialized!"); | |
| Probe->finalize(F); | |
| } |