12cab237bSDimitry Andric //===- Debugify.cpp - Attach synthetic debug info to everything -----------===//
22cab237bSDimitry Andric //
32cab237bSDimitry Andric // The LLVM Compiler Infrastructure
42cab237bSDimitry Andric //
52cab237bSDimitry Andric // This file is distributed under the University of Illinois Open Source
62cab237bSDimitry Andric // License. See LICENSE.TXT for details.
72cab237bSDimitry Andric //
82cab237bSDimitry Andric //===----------------------------------------------------------------------===//
92cab237bSDimitry Andric ///
102cab237bSDimitry Andric /// \file This pass attaches synthetic debug info to everything. It can be used
112cab237bSDimitry Andric /// to create targeted tests for debug info preservation.
122cab237bSDimitry Andric ///
132cab237bSDimitry Andric //===----------------------------------------------------------------------===//
142cab237bSDimitry Andric
154ba319b5SDimitry Andric #include "Debugify.h"
162cab237bSDimitry Andric #include "llvm/ADT/BitVector.h"
172cab237bSDimitry Andric #include "llvm/ADT/StringExtras.h"
182cab237bSDimitry Andric #include "llvm/IR/BasicBlock.h"
192cab237bSDimitry Andric #include "llvm/IR/Constants.h"
202cab237bSDimitry Andric #include "llvm/IR/DIBuilder.h"
212cab237bSDimitry Andric #include "llvm/IR/DebugInfo.h"
222cab237bSDimitry Andric #include "llvm/IR/Function.h"
232cab237bSDimitry Andric #include "llvm/IR/GlobalVariable.h"
242cab237bSDimitry Andric #include "llvm/IR/InstIterator.h"
252cab237bSDimitry Andric #include "llvm/IR/Instruction.h"
262cab237bSDimitry Andric #include "llvm/IR/Instructions.h"
272cab237bSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
282cab237bSDimitry Andric #include "llvm/IR/Module.h"
292cab237bSDimitry Andric #include "llvm/IR/Type.h"
302cab237bSDimitry Andric #include "llvm/Pass.h"
312cab237bSDimitry Andric #include "llvm/Support/raw_ostream.h"
322cab237bSDimitry Andric #include "llvm/Transforms/IPO.h"
332cab237bSDimitry Andric
342cab237bSDimitry Andric using namespace llvm;
352cab237bSDimitry Andric
362cab237bSDimitry Andric namespace {
372cab237bSDimitry Andric
384ba319b5SDimitry Andric cl::opt<bool> Quiet("debugify-quiet",
394ba319b5SDimitry Andric cl::desc("Suppress verbose debugify output"));
404ba319b5SDimitry Andric
dbg()414ba319b5SDimitry Andric raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
424ba319b5SDimitry Andric
getAllocSizeInBits(Module & M,Type * Ty)434ba319b5SDimitry Andric uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
444ba319b5SDimitry Andric return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
454ba319b5SDimitry Andric }
464ba319b5SDimitry Andric
isFunctionSkipped(Function & F)474ba319b5SDimitry Andric bool isFunctionSkipped(Function &F) {
484ba319b5SDimitry Andric return F.isDeclaration() || !F.hasExactDefinition();
494ba319b5SDimitry Andric }
504ba319b5SDimitry Andric
514ba319b5SDimitry Andric /// Find the basic block's terminating instruction.
524ba319b5SDimitry Andric ///
534ba319b5SDimitry Andric /// Special care is needed to handle musttail and deopt calls, as these behave
544ba319b5SDimitry Andric /// like (but are in fact not) terminators.
findTerminatingInstruction(BasicBlock & BB)554ba319b5SDimitry Andric Instruction *findTerminatingInstruction(BasicBlock &BB) {
564ba319b5SDimitry Andric if (auto *I = BB.getTerminatingMustTailCall())
574ba319b5SDimitry Andric return I;
584ba319b5SDimitry Andric if (auto *I = BB.getTerminatingDeoptimizeCall())
594ba319b5SDimitry Andric return I;
604ba319b5SDimitry Andric return BB.getTerminator();
614ba319b5SDimitry Andric }
624ba319b5SDimitry Andric
applyDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef Banner)634ba319b5SDimitry Andric bool applyDebugifyMetadata(Module &M,
644ba319b5SDimitry Andric iterator_range<Module::iterator> Functions,
654ba319b5SDimitry Andric StringRef Banner) {
662cab237bSDimitry Andric // Skip modules with debug info.
672cab237bSDimitry Andric if (M.getNamedMetadata("llvm.dbg.cu")) {
684ba319b5SDimitry Andric dbg() << Banner << "Skipping module with debug info\n";
692cab237bSDimitry Andric return false;
702cab237bSDimitry Andric }
712cab237bSDimitry Andric
722cab237bSDimitry Andric DIBuilder DIB(M);
732cab237bSDimitry Andric LLVMContext &Ctx = M.getContext();
742cab237bSDimitry Andric
752cab237bSDimitry Andric // Get a DIType which corresponds to Ty.
762cab237bSDimitry Andric DenseMap<uint64_t, DIType *> TypeCache;
772cab237bSDimitry Andric auto getCachedDIType = [&](Type *Ty) -> DIType * {
784ba319b5SDimitry Andric uint64_t Size = getAllocSizeInBits(M, Ty);
792cab237bSDimitry Andric DIType *&DTy = TypeCache[Size];
802cab237bSDimitry Andric if (!DTy) {
812cab237bSDimitry Andric std::string Name = "ty" + utostr(Size);
822cab237bSDimitry Andric DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
832cab237bSDimitry Andric }
842cab237bSDimitry Andric return DTy;
852cab237bSDimitry Andric };
862cab237bSDimitry Andric
872cab237bSDimitry Andric unsigned NextLine = 1;
882cab237bSDimitry Andric unsigned NextVar = 1;
892cab237bSDimitry Andric auto File = DIB.createFile(M.getName(), "/");
904ba319b5SDimitry Andric auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify",
914ba319b5SDimitry Andric /*isOptimized=*/true, "", 0);
922cab237bSDimitry Andric
932cab237bSDimitry Andric // Visit each instruction.
944ba319b5SDimitry Andric for (Function &F : Functions) {
954ba319b5SDimitry Andric if (isFunctionSkipped(F))
962cab237bSDimitry Andric continue;
972cab237bSDimitry Andric
982cab237bSDimitry Andric auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
99*b5893f02SDimitry Andric DISubprogram::DISPFlags SPFlags =
100*b5893f02SDimitry Andric DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;
101*b5893f02SDimitry Andric if (F.hasPrivateLinkage() || F.hasInternalLinkage())
102*b5893f02SDimitry Andric SPFlags |= DISubprogram::SPFlagLocalToUnit;
103*b5893f02SDimitry Andric auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,
104*b5893f02SDimitry Andric SPType, NextLine, DINode::FlagZero, SPFlags);
1052cab237bSDimitry Andric F.setSubprogram(SP);
1062cab237bSDimitry Andric for (BasicBlock &BB : F) {
1072cab237bSDimitry Andric // Attach debug locations.
1082cab237bSDimitry Andric for (Instruction &I : BB)
1092cab237bSDimitry Andric I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
1102cab237bSDimitry Andric
1114ba319b5SDimitry Andric // Inserting debug values into EH pads can break IR invariants.
1124ba319b5SDimitry Andric if (BB.isEHPad())
1132cab237bSDimitry Andric continue;
1142cab237bSDimitry Andric
1154ba319b5SDimitry Andric // Find the terminating instruction, after which no debug values are
1164ba319b5SDimitry Andric // attached.
1174ba319b5SDimitry Andric Instruction *LastInst = findTerminatingInstruction(BB);
1184ba319b5SDimitry Andric assert(LastInst && "Expected basic block with a terminator");
1194ba319b5SDimitry Andric
1204ba319b5SDimitry Andric // Maintain an insertion point which can't be invalidated when updates
1214ba319b5SDimitry Andric // are made.
1224ba319b5SDimitry Andric BasicBlock::iterator InsertPt = BB.getFirstInsertionPt();
1234ba319b5SDimitry Andric assert(InsertPt != BB.end() && "Expected to find an insertion point");
1244ba319b5SDimitry Andric Instruction *InsertBefore = &*InsertPt;
1254ba319b5SDimitry Andric
1264ba319b5SDimitry Andric // Attach debug values.
1274ba319b5SDimitry Andric for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {
1284ba319b5SDimitry Andric // Skip void-valued instructions.
1294ba319b5SDimitry Andric if (I->getType()->isVoidTy())
1304ba319b5SDimitry Andric continue;
1314ba319b5SDimitry Andric
1324ba319b5SDimitry Andric // Phis and EH pads must be grouped at the beginning of the block.
1334ba319b5SDimitry Andric // Only advance the insertion point when we finish visiting these.
1344ba319b5SDimitry Andric if (!isa<PHINode>(I) && !I->isEHPad())
1354ba319b5SDimitry Andric InsertBefore = I->getNextNode();
1362cab237bSDimitry Andric
1372cab237bSDimitry Andric std::string Name = utostr(NextVar++);
1384ba319b5SDimitry Andric const DILocation *Loc = I->getDebugLoc().get();
1392cab237bSDimitry Andric auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
1404ba319b5SDimitry Andric getCachedDIType(I->getType()),
1412cab237bSDimitry Andric /*AlwaysPreserve=*/true);
1424ba319b5SDimitry Andric DIB.insertDbgValueIntrinsic(I, LocalVar, DIB.createExpression(), Loc,
1434ba319b5SDimitry Andric InsertBefore);
1442cab237bSDimitry Andric }
1452cab237bSDimitry Andric }
1462cab237bSDimitry Andric DIB.finalizeSubprogram(SP);
1472cab237bSDimitry Andric }
1482cab237bSDimitry Andric DIB.finalize();
1492cab237bSDimitry Andric
1502cab237bSDimitry Andric // Track the number of distinct lines and variables.
1512cab237bSDimitry Andric NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
1522cab237bSDimitry Andric auto *IntTy = Type::getInt32Ty(Ctx);
1532cab237bSDimitry Andric auto addDebugifyOperand = [&](unsigned N) {
1542cab237bSDimitry Andric NMD->addOperand(MDNode::get(
1552cab237bSDimitry Andric Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N))));
1562cab237bSDimitry Andric };
1572cab237bSDimitry Andric addDebugifyOperand(NextLine - 1); // Original number of lines.
1582cab237bSDimitry Andric addDebugifyOperand(NextVar - 1); // Original number of variables.
1594ba319b5SDimitry Andric assert(NMD->getNumOperands() == 2 &&
1604ba319b5SDimitry Andric "llvm.debugify should have exactly 2 operands!");
1614ba319b5SDimitry Andric
1624ba319b5SDimitry Andric // Claim that this synthetic debug info is valid.
1634ba319b5SDimitry Andric StringRef DIVersionKey = "Debug Info Version";
1644ba319b5SDimitry Andric if (!M.getModuleFlag(DIVersionKey))
1654ba319b5SDimitry Andric M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION);
1664ba319b5SDimitry Andric
1672cab237bSDimitry Andric return true;
1682cab237bSDimitry Andric }
1692cab237bSDimitry Andric
1704ba319b5SDimitry Andric /// Return true if a mis-sized diagnostic is issued for \p DVI.
diagnoseMisSizedDbgValue(Module & M,DbgValueInst * DVI)1714ba319b5SDimitry Andric bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
1724ba319b5SDimitry Andric // The size of a dbg.value's value operand should match the size of the
1734ba319b5SDimitry Andric // variable it corresponds to.
1744ba319b5SDimitry Andric //
1754ba319b5SDimitry Andric // TODO: This, along with a check for non-null value operands, should be
1764ba319b5SDimitry Andric // promoted to verifier failures.
1774ba319b5SDimitry Andric Value *V = DVI->getValue();
1784ba319b5SDimitry Andric if (!V)
1794ba319b5SDimitry Andric return false;
1804ba319b5SDimitry Andric
1814ba319b5SDimitry Andric // For now, don't try to interpret anything more complicated than an empty
1824ba319b5SDimitry Andric // DIExpression. Eventually we should try to handle OP_deref and fragments.
1834ba319b5SDimitry Andric if (DVI->getExpression()->getNumElements())
1844ba319b5SDimitry Andric return false;
1854ba319b5SDimitry Andric
1864ba319b5SDimitry Andric Type *Ty = V->getType();
1874ba319b5SDimitry Andric uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);
1884ba319b5SDimitry Andric Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits();
1894ba319b5SDimitry Andric if (!ValueOperandSize || !DbgVarSize)
1904ba319b5SDimitry Andric return false;
1914ba319b5SDimitry Andric
1924ba319b5SDimitry Andric bool HasBadSize = false;
1934ba319b5SDimitry Andric if (Ty->isIntegerTy()) {
1944ba319b5SDimitry Andric auto Signedness = DVI->getVariable()->getSignedness();
1954ba319b5SDimitry Andric if (Signedness && *Signedness == DIBasicType::Signedness::Signed)
1964ba319b5SDimitry Andric HasBadSize = ValueOperandSize < *DbgVarSize;
1974ba319b5SDimitry Andric } else {
1984ba319b5SDimitry Andric HasBadSize = ValueOperandSize != *DbgVarSize;
1994ba319b5SDimitry Andric }
2004ba319b5SDimitry Andric
2014ba319b5SDimitry Andric if (HasBadSize) {
2024ba319b5SDimitry Andric dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize
2034ba319b5SDimitry Andric << ", but its variable has size " << *DbgVarSize << ": ";
2044ba319b5SDimitry Andric DVI->print(dbg());
2054ba319b5SDimitry Andric dbg() << "\n";
2064ba319b5SDimitry Andric }
2074ba319b5SDimitry Andric return HasBadSize;
2084ba319b5SDimitry Andric }
2094ba319b5SDimitry Andric
checkDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef NameOfWrappedPass,StringRef Banner,bool Strip,DebugifyStatsMap * StatsMap)2104ba319b5SDimitry Andric bool checkDebugifyMetadata(Module &M,
2114ba319b5SDimitry Andric iterator_range<Module::iterator> Functions,
2124ba319b5SDimitry Andric StringRef NameOfWrappedPass, StringRef Banner,
2134ba319b5SDimitry Andric bool Strip, DebugifyStatsMap *StatsMap) {
2142cab237bSDimitry Andric // Skip modules without debugify metadata.
2152cab237bSDimitry Andric NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
2164ba319b5SDimitry Andric if (!NMD) {
2174ba319b5SDimitry Andric dbg() << Banner << "Skipping module without debugify metadata\n";
2184ba319b5SDimitry Andric return false;
2194ba319b5SDimitry Andric }
2202cab237bSDimitry Andric
2212cab237bSDimitry Andric auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
2222cab237bSDimitry Andric return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
2232cab237bSDimitry Andric ->getZExtValue();
2242cab237bSDimitry Andric };
2254ba319b5SDimitry Andric assert(NMD->getNumOperands() == 2 &&
2264ba319b5SDimitry Andric "llvm.debugify should have exactly 2 operands!");
2272cab237bSDimitry Andric unsigned OriginalNumLines = getDebugifyOperand(0);
2282cab237bSDimitry Andric unsigned OriginalNumVars = getDebugifyOperand(1);
2292cab237bSDimitry Andric bool HasErrors = false;
2302cab237bSDimitry Andric
2314ba319b5SDimitry Andric // Track debug info loss statistics if able.
2324ba319b5SDimitry Andric DebugifyStatistics *Stats = nullptr;
2334ba319b5SDimitry Andric if (StatsMap && !NameOfWrappedPass.empty())
2344ba319b5SDimitry Andric Stats = &StatsMap->operator[](NameOfWrappedPass);
2354ba319b5SDimitry Andric
2362cab237bSDimitry Andric BitVector MissingLines{OriginalNumLines, true};
2374ba319b5SDimitry Andric BitVector MissingVars{OriginalNumVars, true};
2384ba319b5SDimitry Andric for (Function &F : Functions) {
2394ba319b5SDimitry Andric if (isFunctionSkipped(F))
2404ba319b5SDimitry Andric continue;
2414ba319b5SDimitry Andric
2424ba319b5SDimitry Andric // Find missing lines.
2432cab237bSDimitry Andric for (Instruction &I : instructions(F)) {
2442cab237bSDimitry Andric if (isa<DbgValueInst>(&I))
2452cab237bSDimitry Andric continue;
2462cab237bSDimitry Andric
2472cab237bSDimitry Andric auto DL = I.getDebugLoc();
2484ba319b5SDimitry Andric if (DL && DL.getLine() != 0) {
2492cab237bSDimitry Andric MissingLines.reset(DL.getLine() - 1);
2502cab237bSDimitry Andric continue;
2512cab237bSDimitry Andric }
2522cab237bSDimitry Andric
2534ba319b5SDimitry Andric if (!DL) {
2544ba319b5SDimitry Andric dbg() << "ERROR: Instruction with empty DebugLoc in function ";
2554ba319b5SDimitry Andric dbg() << F.getName() << " --";
2564ba319b5SDimitry Andric I.print(dbg());
2574ba319b5SDimitry Andric dbg() << "\n";
2582cab237bSDimitry Andric HasErrors = true;
2592cab237bSDimitry Andric }
2602cab237bSDimitry Andric }
2612cab237bSDimitry Andric
2624ba319b5SDimitry Andric // Find missing variables and mis-sized debug values.
2632cab237bSDimitry Andric for (Instruction &I : instructions(F)) {
2642cab237bSDimitry Andric auto *DVI = dyn_cast<DbgValueInst>(&I);
2652cab237bSDimitry Andric if (!DVI)
2662cab237bSDimitry Andric continue;
2672cab237bSDimitry Andric
2682cab237bSDimitry Andric unsigned Var = ~0U;
2692cab237bSDimitry Andric (void)to_integer(DVI->getVariable()->getName(), Var, 10);
2702cab237bSDimitry Andric assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
2714ba319b5SDimitry Andric bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI);
2724ba319b5SDimitry Andric if (!HasBadSize)
2732cab237bSDimitry Andric MissingVars.reset(Var - 1);
2744ba319b5SDimitry Andric HasErrors |= HasBadSize;
2752cab237bSDimitry Andric }
2762cab237bSDimitry Andric }
2774ba319b5SDimitry Andric
2784ba319b5SDimitry Andric // Print the results.
2794ba319b5SDimitry Andric for (unsigned Idx : MissingLines.set_bits())
2804ba319b5SDimitry Andric dbg() << "WARNING: Missing line " << Idx + 1 << "\n";
2814ba319b5SDimitry Andric
2822cab237bSDimitry Andric for (unsigned Idx : MissingVars.set_bits())
2834ba319b5SDimitry Andric dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
2842cab237bSDimitry Andric
2854ba319b5SDimitry Andric // Update DI loss statistics.
2864ba319b5SDimitry Andric if (Stats) {
2874ba319b5SDimitry Andric Stats->NumDbgLocsExpected += OriginalNumLines;
2884ba319b5SDimitry Andric Stats->NumDbgLocsMissing += MissingLines.count();
2894ba319b5SDimitry Andric Stats->NumDbgValuesExpected += OriginalNumVars;
2904ba319b5SDimitry Andric Stats->NumDbgValuesMissing += MissingVars.count();
2912cab237bSDimitry Andric }
2922cab237bSDimitry Andric
2934ba319b5SDimitry Andric dbg() << Banner;
2944ba319b5SDimitry Andric if (!NameOfWrappedPass.empty())
2954ba319b5SDimitry Andric dbg() << " [" << NameOfWrappedPass << "]";
2964ba319b5SDimitry Andric dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
2972cab237bSDimitry Andric
2984ba319b5SDimitry Andric // Strip the Debugify Metadata if required.
2994ba319b5SDimitry Andric if (Strip) {
3004ba319b5SDimitry Andric StripDebugInfo(M);
3014ba319b5SDimitry Andric M.eraseNamedMetadata(NMD);
3024ba319b5SDimitry Andric return true;
3034ba319b5SDimitry Andric }
3044ba319b5SDimitry Andric
3054ba319b5SDimitry Andric return false;
3064ba319b5SDimitry Andric }
3074ba319b5SDimitry Andric
3084ba319b5SDimitry Andric /// ModulePass for attaching synthetic debug info to everything, used with the
3094ba319b5SDimitry Andric /// legacy module pass manager.
3104ba319b5SDimitry Andric struct DebugifyModulePass : public ModulePass {
runOnModule__anonfea7d2800111::DebugifyModulePass3114ba319b5SDimitry Andric bool runOnModule(Module &M) override {
3124ba319b5SDimitry Andric return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
3134ba319b5SDimitry Andric }
3144ba319b5SDimitry Andric
DebugifyModulePass__anonfea7d2800111::DebugifyModulePass3154ba319b5SDimitry Andric DebugifyModulePass() : ModulePass(ID) {}
3162cab237bSDimitry Andric
getAnalysisUsage__anonfea7d2800111::DebugifyModulePass3172cab237bSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
3182cab237bSDimitry Andric AU.setPreservesAll();
3192cab237bSDimitry Andric }
3202cab237bSDimitry Andric
3212cab237bSDimitry Andric static char ID; // Pass identification.
3222cab237bSDimitry Andric };
3232cab237bSDimitry Andric
3244ba319b5SDimitry Andric /// FunctionPass for attaching synthetic debug info to instructions within a
3254ba319b5SDimitry Andric /// single function, used with the legacy module pass manager.
3264ba319b5SDimitry Andric struct DebugifyFunctionPass : public FunctionPass {
runOnFunction__anonfea7d2800111::DebugifyFunctionPass3274ba319b5SDimitry Andric bool runOnFunction(Function &F) override {
3284ba319b5SDimitry Andric Module &M = *F.getParent();
3294ba319b5SDimitry Andric auto FuncIt = F.getIterator();
3304ba319b5SDimitry Andric return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
3314ba319b5SDimitry Andric "FunctionDebugify: ");
3322cab237bSDimitry Andric }
3332cab237bSDimitry Andric
DebugifyFunctionPass__anonfea7d2800111::DebugifyFunctionPass3344ba319b5SDimitry Andric DebugifyFunctionPass() : FunctionPass(ID) {}
3352cab237bSDimitry Andric
getAnalysisUsage__anonfea7d2800111::DebugifyFunctionPass3362cab237bSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
3372cab237bSDimitry Andric AU.setPreservesAll();
3382cab237bSDimitry Andric }
3392cab237bSDimitry Andric
3402cab237bSDimitry Andric static char ID; // Pass identification.
3412cab237bSDimitry Andric };
3422cab237bSDimitry Andric
3434ba319b5SDimitry Andric /// ModulePass for checking debug info inserted by -debugify, used with the
3444ba319b5SDimitry Andric /// legacy module pass manager.
3454ba319b5SDimitry Andric struct CheckDebugifyModulePass : public ModulePass {
runOnModule__anonfea7d2800111::CheckDebugifyModulePass3464ba319b5SDimitry Andric bool runOnModule(Module &M) override {
3474ba319b5SDimitry Andric return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
3484ba319b5SDimitry Andric "CheckModuleDebugify", Strip, StatsMap);
3494ba319b5SDimitry Andric }
3504ba319b5SDimitry Andric
CheckDebugifyModulePass__anonfea7d2800111::CheckDebugifyModulePass3514ba319b5SDimitry Andric CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "",
3524ba319b5SDimitry Andric DebugifyStatsMap *StatsMap = nullptr)
3534ba319b5SDimitry Andric : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
3544ba319b5SDimitry Andric StatsMap(StatsMap) {}
3554ba319b5SDimitry Andric
getAnalysisUsage__anonfea7d2800111::CheckDebugifyModulePass3564ba319b5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
3574ba319b5SDimitry Andric AU.setPreservesAll();
3584ba319b5SDimitry Andric }
3594ba319b5SDimitry Andric
3604ba319b5SDimitry Andric static char ID; // Pass identification.
3614ba319b5SDimitry Andric
3624ba319b5SDimitry Andric private:
3634ba319b5SDimitry Andric bool Strip;
3644ba319b5SDimitry Andric StringRef NameOfWrappedPass;
3654ba319b5SDimitry Andric DebugifyStatsMap *StatsMap;
3664ba319b5SDimitry Andric };
3674ba319b5SDimitry Andric
3684ba319b5SDimitry Andric /// FunctionPass for checking debug info inserted by -debugify-function, used
3694ba319b5SDimitry Andric /// with the legacy module pass manager.
3704ba319b5SDimitry Andric struct CheckDebugifyFunctionPass : public FunctionPass {
runOnFunction__anonfea7d2800111::CheckDebugifyFunctionPass3714ba319b5SDimitry Andric bool runOnFunction(Function &F) override {
3724ba319b5SDimitry Andric Module &M = *F.getParent();
3734ba319b5SDimitry Andric auto FuncIt = F.getIterator();
3744ba319b5SDimitry Andric return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
3754ba319b5SDimitry Andric NameOfWrappedPass, "CheckFunctionDebugify",
3764ba319b5SDimitry Andric Strip, StatsMap);
3774ba319b5SDimitry Andric }
3784ba319b5SDimitry Andric
CheckDebugifyFunctionPass__anonfea7d2800111::CheckDebugifyFunctionPass3794ba319b5SDimitry Andric CheckDebugifyFunctionPass(bool Strip = false,
3804ba319b5SDimitry Andric StringRef NameOfWrappedPass = "",
3814ba319b5SDimitry Andric DebugifyStatsMap *StatsMap = nullptr)
3824ba319b5SDimitry Andric : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
3834ba319b5SDimitry Andric StatsMap(StatsMap) {}
3844ba319b5SDimitry Andric
getAnalysisUsage__anonfea7d2800111::CheckDebugifyFunctionPass3854ba319b5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
3864ba319b5SDimitry Andric AU.setPreservesAll();
3874ba319b5SDimitry Andric }
3884ba319b5SDimitry Andric
3894ba319b5SDimitry Andric static char ID; // Pass identification.
3904ba319b5SDimitry Andric
3914ba319b5SDimitry Andric private:
3924ba319b5SDimitry Andric bool Strip;
3934ba319b5SDimitry Andric StringRef NameOfWrappedPass;
3944ba319b5SDimitry Andric DebugifyStatsMap *StatsMap;
3954ba319b5SDimitry Andric };
3964ba319b5SDimitry Andric
3972cab237bSDimitry Andric } // end anonymous namespace
3982cab237bSDimitry Andric
exportDebugifyStats(llvm::StringRef Path,const DebugifyStatsMap & Map)3994ba319b5SDimitry Andric void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) {
4004ba319b5SDimitry Andric std::error_code EC;
4014ba319b5SDimitry Andric raw_fd_ostream OS{Path, EC};
4024ba319b5SDimitry Andric if (EC) {
4034ba319b5SDimitry Andric errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
4044ba319b5SDimitry Andric return;
4054ba319b5SDimitry Andric }
4064ba319b5SDimitry Andric
4074ba319b5SDimitry Andric OS << "Pass Name" << ',' << "# of missing debug values" << ','
4084ba319b5SDimitry Andric << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
4094ba319b5SDimitry Andric << "Missing/Expected location ratio" << '\n';
4104ba319b5SDimitry Andric for (const auto &Entry : Map) {
4114ba319b5SDimitry Andric StringRef Pass = Entry.first;
4124ba319b5SDimitry Andric DebugifyStatistics Stats = Entry.second;
4134ba319b5SDimitry Andric
4144ba319b5SDimitry Andric OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
4154ba319b5SDimitry Andric << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
4164ba319b5SDimitry Andric << Stats.getEmptyLocationRatio() << '\n';
4174ba319b5SDimitry Andric }
4184ba319b5SDimitry Andric }
4194ba319b5SDimitry Andric
createDebugifyModulePass()4204ba319b5SDimitry Andric ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); }
4214ba319b5SDimitry Andric
createDebugifyFunctionPass()4224ba319b5SDimitry Andric FunctionPass *createDebugifyFunctionPass() {
4234ba319b5SDimitry Andric return new DebugifyFunctionPass();
4244ba319b5SDimitry Andric }
4254ba319b5SDimitry Andric
run(Module & M,ModuleAnalysisManager &)4264ba319b5SDimitry Andric PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
4274ba319b5SDimitry Andric applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
4284ba319b5SDimitry Andric return PreservedAnalyses::all();
4294ba319b5SDimitry Andric }
4304ba319b5SDimitry Andric
createCheckDebugifyModulePass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap)4314ba319b5SDimitry Andric ModulePass *createCheckDebugifyModulePass(bool Strip,
4324ba319b5SDimitry Andric StringRef NameOfWrappedPass,
4334ba319b5SDimitry Andric DebugifyStatsMap *StatsMap) {
4344ba319b5SDimitry Andric return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
4354ba319b5SDimitry Andric }
4364ba319b5SDimitry Andric
createCheckDebugifyFunctionPass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap)4374ba319b5SDimitry Andric FunctionPass *createCheckDebugifyFunctionPass(bool Strip,
4384ba319b5SDimitry Andric StringRef NameOfWrappedPass,
4394ba319b5SDimitry Andric DebugifyStatsMap *StatsMap) {
4404ba319b5SDimitry Andric return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
4414ba319b5SDimitry Andric }
4424ba319b5SDimitry Andric
run(Module & M,ModuleAnalysisManager &)4434ba319b5SDimitry Andric PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
4444ba319b5SDimitry Andric ModuleAnalysisManager &) {
4454ba319b5SDimitry Andric checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false,
4464ba319b5SDimitry Andric nullptr);
4474ba319b5SDimitry Andric return PreservedAnalyses::all();
4484ba319b5SDimitry Andric }
4494ba319b5SDimitry Andric
4504ba319b5SDimitry Andric char DebugifyModulePass::ID = 0;
4514ba319b5SDimitry Andric static RegisterPass<DebugifyModulePass> DM("debugify",
4522cab237bSDimitry Andric "Attach debug info to everything");
4532cab237bSDimitry Andric
4544ba319b5SDimitry Andric char CheckDebugifyModulePass::ID = 0;
4554ba319b5SDimitry Andric static RegisterPass<CheckDebugifyModulePass>
4564ba319b5SDimitry Andric CDM("check-debugify", "Check debug info from -debugify");
4574ba319b5SDimitry Andric
4584ba319b5SDimitry Andric char DebugifyFunctionPass::ID = 0;
4594ba319b5SDimitry Andric static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
4604ba319b5SDimitry Andric "Attach debug info to a function");
4614ba319b5SDimitry Andric
4624ba319b5SDimitry Andric char CheckDebugifyFunctionPass::ID = 0;
4634ba319b5SDimitry Andric static RegisterPass<CheckDebugifyFunctionPass>
4644ba319b5SDimitry Andric CDF("check-debugify-function", "Check debug info from -debugify-function");
465