| //===-- 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); |
| } |