11a2b3536SDjordje Todorovic //===- Debugify.cpp - Check debug info preservation in optimizations ------===//
225ee8613SDaniel Sanders //
325ee8613SDaniel Sanders // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
425ee8613SDaniel Sanders // See https://llvm.org/LICENSE.txt for license information.
525ee8613SDaniel Sanders // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
625ee8613SDaniel Sanders //
725ee8613SDaniel Sanders //===----------------------------------------------------------------------===//
825ee8613SDaniel Sanders ///
91a2b3536SDjordje Todorovic /// \file In the `synthetic` mode, the `-debugify` attaches synthetic debug info
101a2b3536SDjordje Todorovic /// to everything. It can be used to create targeted tests for debug info
111a2b3536SDjordje Todorovic /// preservation. In addition, when using the `original` mode, it can check
121a2b3536SDjordje Todorovic /// original debug info preservation. The `synthetic` mode is default one.
1325ee8613SDaniel Sanders ///
1425ee8613SDaniel Sanders //===----------------------------------------------------------------------===//
1525ee8613SDaniel Sanders 
164c1a1d3cSReid Kleckner #include "llvm/Transforms/Utils/Debugify.h"
1725ee8613SDaniel Sanders #include "llvm/ADT/BitVector.h"
1825ee8613SDaniel Sanders #include "llvm/ADT/StringExtras.h"
1925ee8613SDaniel Sanders #include "llvm/IR/DIBuilder.h"
2025ee8613SDaniel Sanders #include "llvm/IR/DebugInfo.h"
2125ee8613SDaniel Sanders #include "llvm/IR/InstIterator.h"
2225ee8613SDaniel Sanders #include "llvm/IR/Instructions.h"
2325ee8613SDaniel Sanders #include "llvm/IR/IntrinsicInst.h"
240128b950SSimon Pilgrim #include "llvm/IR/Module.h"
257de6dcd2SArthur Eubanks #include "llvm/IR/PassInstrumentation.h"
2625ee8613SDaniel Sanders #include "llvm/Pass.h"
274c1a1d3cSReid Kleckner #include "llvm/Support/CommandLine.h"
28ba7a92c0SNico Weber #include "llvm/Support/FileSystem.h"
299f41c03fSDjordje Todorovic #include "llvm/Support/JSON.h"
3025ee8613SDaniel Sanders 
311a2b3536SDjordje Todorovic #define DEBUG_TYPE "debugify"
321a2b3536SDjordje Todorovic 
3325ee8613SDaniel Sanders using namespace llvm;
3425ee8613SDaniel Sanders 
3525ee8613SDaniel Sanders namespace {
3625ee8613SDaniel Sanders 
3725ee8613SDaniel Sanders cl::opt<bool> Quiet("debugify-quiet",
3825ee8613SDaniel Sanders                     cl::desc("Suppress verbose debugify output"));
3925ee8613SDaniel Sanders 
4015f7bc78SDaniel Sanders enum class Level {
4115f7bc78SDaniel Sanders   Locations,
4215f7bc78SDaniel Sanders   LocationsAndVariables
4315f7bc78SDaniel Sanders };
441a2b3536SDjordje Todorovic 
451a2b3536SDjordje Todorovic // Used for the synthetic mode only.
4615f7bc78SDaniel Sanders cl::opt<Level> DebugifyLevel(
4715f7bc78SDaniel Sanders     "debugify-level", cl::desc("Kind of debug info to add"),
4815f7bc78SDaniel Sanders     cl::values(clEnumValN(Level::Locations, "locations", "Locations only"),
4915f7bc78SDaniel Sanders                clEnumValN(Level::LocationsAndVariables, "location+variables",
5015f7bc78SDaniel Sanders                           "Locations and Variables")),
5115f7bc78SDaniel Sanders     cl::init(Level::LocationsAndVariables));
5215f7bc78SDaniel Sanders 
5325ee8613SDaniel Sanders raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
5425ee8613SDaniel Sanders 
5525ee8613SDaniel Sanders uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
5625ee8613SDaniel Sanders   return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
5725ee8613SDaniel Sanders }
5825ee8613SDaniel Sanders 
5925ee8613SDaniel Sanders bool isFunctionSkipped(Function &F) {
6025ee8613SDaniel Sanders   return F.isDeclaration() || !F.hasExactDefinition();
6125ee8613SDaniel Sanders }
6225ee8613SDaniel Sanders 
6325ee8613SDaniel Sanders /// Find the basic block's terminating instruction.
6425ee8613SDaniel Sanders ///
6525ee8613SDaniel Sanders /// Special care is needed to handle musttail and deopt calls, as these behave
6625ee8613SDaniel Sanders /// like (but are in fact not) terminators.
6725ee8613SDaniel Sanders Instruction *findTerminatingInstruction(BasicBlock &BB) {
6825ee8613SDaniel Sanders   if (auto *I = BB.getTerminatingMustTailCall())
6925ee8613SDaniel Sanders     return I;
7025ee8613SDaniel Sanders   if (auto *I = BB.getTerminatingDeoptimizeCall())
7125ee8613SDaniel Sanders     return I;
7225ee8613SDaniel Sanders   return BB.getTerminator();
7325ee8613SDaniel Sanders }
741adeeabbSDaniel Sanders } // end anonymous namespace
7525ee8613SDaniel Sanders 
761adeeabbSDaniel Sanders bool llvm::applyDebugifyMetadata(
771adeeabbSDaniel Sanders     Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
781adeeabbSDaniel Sanders     std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) {
7925ee8613SDaniel Sanders   // Skip modules with debug info.
8025ee8613SDaniel Sanders   if (M.getNamedMetadata("llvm.dbg.cu")) {
8125ee8613SDaniel Sanders     dbg() << Banner << "Skipping module with debug info\n";
8225ee8613SDaniel Sanders     return false;
8325ee8613SDaniel Sanders   }
8425ee8613SDaniel Sanders 
8525ee8613SDaniel Sanders   DIBuilder DIB(M);
8625ee8613SDaniel Sanders   LLVMContext &Ctx = M.getContext();
87a852ee19SNico Weber   auto *Int32Ty = Type::getInt32Ty(Ctx);
8825ee8613SDaniel Sanders 
8925ee8613SDaniel Sanders   // Get a DIType which corresponds to Ty.
9025ee8613SDaniel Sanders   DenseMap<uint64_t, DIType *> TypeCache;
9125ee8613SDaniel Sanders   auto getCachedDIType = [&](Type *Ty) -> DIType * {
9225ee8613SDaniel Sanders     uint64_t Size = getAllocSizeInBits(M, Ty);
9325ee8613SDaniel Sanders     DIType *&DTy = TypeCache[Size];
9425ee8613SDaniel Sanders     if (!DTy) {
9525ee8613SDaniel Sanders       std::string Name = "ty" + utostr(Size);
9625ee8613SDaniel Sanders       DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
9725ee8613SDaniel Sanders     }
9825ee8613SDaniel Sanders     return DTy;
9925ee8613SDaniel Sanders   };
10025ee8613SDaniel Sanders 
10125ee8613SDaniel Sanders   unsigned NextLine = 1;
10225ee8613SDaniel Sanders   unsigned NextVar = 1;
10325ee8613SDaniel Sanders   auto File = DIB.createFile(M.getName(), "/");
10425ee8613SDaniel Sanders   auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify",
10525ee8613SDaniel Sanders                                   /*isOptimized=*/true, "", 0);
10625ee8613SDaniel Sanders 
10725ee8613SDaniel Sanders   // Visit each instruction.
10825ee8613SDaniel Sanders   for (Function &F : Functions) {
10925ee8613SDaniel Sanders     if (isFunctionSkipped(F))
11025ee8613SDaniel Sanders       continue;
11125ee8613SDaniel Sanders 
112a852ee19SNico Weber     bool InsertedDbgVal = false;
11325ee8613SDaniel Sanders     auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
11425ee8613SDaniel Sanders     DISubprogram::DISPFlags SPFlags =
11525ee8613SDaniel Sanders         DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;
11625ee8613SDaniel Sanders     if (F.hasPrivateLinkage() || F.hasInternalLinkage())
11725ee8613SDaniel Sanders       SPFlags |= DISubprogram::SPFlagLocalToUnit;
11825ee8613SDaniel Sanders     auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,
11925ee8613SDaniel Sanders                                  SPType, NextLine, DINode::FlagZero, SPFlags);
12025ee8613SDaniel Sanders     F.setSubprogram(SP);
121a852ee19SNico Weber 
122a852ee19SNico Weber     // Helper that inserts a dbg.value before \p InsertBefore, copying the
123a852ee19SNico Weber     // location (and possibly the type, if it's non-void) from \p TemplateInst.
124a852ee19SNico Weber     auto insertDbgVal = [&](Instruction &TemplateInst,
125a852ee19SNico Weber                             Instruction *InsertBefore) {
126a852ee19SNico Weber       std::string Name = utostr(NextVar++);
127a852ee19SNico Weber       Value *V = &TemplateInst;
128a852ee19SNico Weber       if (TemplateInst.getType()->isVoidTy())
129a852ee19SNico Weber         V = ConstantInt::get(Int32Ty, 0);
130a852ee19SNico Weber       const DILocation *Loc = TemplateInst.getDebugLoc().get();
131a852ee19SNico Weber       auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
132a852ee19SNico Weber                                              getCachedDIType(V->getType()),
133a852ee19SNico Weber                                              /*AlwaysPreserve=*/true);
134a852ee19SNico Weber       DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc,
135a852ee19SNico Weber                                   InsertBefore);
136a852ee19SNico Weber     };
137a852ee19SNico Weber 
13825ee8613SDaniel Sanders     for (BasicBlock &BB : F) {
13925ee8613SDaniel Sanders       // Attach debug locations.
14025ee8613SDaniel Sanders       for (Instruction &I : BB)
14125ee8613SDaniel Sanders         I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
14225ee8613SDaniel Sanders 
14315f7bc78SDaniel Sanders       if (DebugifyLevel < Level::LocationsAndVariables)
14415f7bc78SDaniel Sanders         continue;
14515f7bc78SDaniel Sanders 
14625ee8613SDaniel Sanders       // Inserting debug values into EH pads can break IR invariants.
14725ee8613SDaniel Sanders       if (BB.isEHPad())
14825ee8613SDaniel Sanders         continue;
14925ee8613SDaniel Sanders 
15025ee8613SDaniel Sanders       // Find the terminating instruction, after which no debug values are
15125ee8613SDaniel Sanders       // attached.
15225ee8613SDaniel Sanders       Instruction *LastInst = findTerminatingInstruction(BB);
15325ee8613SDaniel Sanders       assert(LastInst && "Expected basic block with a terminator");
15425ee8613SDaniel Sanders 
15525ee8613SDaniel Sanders       // Maintain an insertion point which can't be invalidated when updates
15625ee8613SDaniel Sanders       // are made.
15725ee8613SDaniel Sanders       BasicBlock::iterator InsertPt = BB.getFirstInsertionPt();
15825ee8613SDaniel Sanders       assert(InsertPt != BB.end() && "Expected to find an insertion point");
15925ee8613SDaniel Sanders       Instruction *InsertBefore = &*InsertPt;
16025ee8613SDaniel Sanders 
16125ee8613SDaniel Sanders       // Attach debug values.
16225ee8613SDaniel Sanders       for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {
16325ee8613SDaniel Sanders         // Skip void-valued instructions.
16425ee8613SDaniel Sanders         if (I->getType()->isVoidTy())
16525ee8613SDaniel Sanders           continue;
16625ee8613SDaniel Sanders 
16725ee8613SDaniel Sanders         // Phis and EH pads must be grouped at the beginning of the block.
16825ee8613SDaniel Sanders         // Only advance the insertion point when we finish visiting these.
16925ee8613SDaniel Sanders         if (!isa<PHINode>(I) && !I->isEHPad())
17025ee8613SDaniel Sanders           InsertBefore = I->getNextNode();
17125ee8613SDaniel Sanders 
172a852ee19SNico Weber         insertDbgVal(*I, InsertBefore);
173a852ee19SNico Weber         InsertedDbgVal = true;
17425ee8613SDaniel Sanders       }
17525ee8613SDaniel Sanders     }
176a852ee19SNico Weber     // Make sure we emit at least one dbg.value, otherwise MachineDebugify may
177a852ee19SNico Weber     // not have anything to work with as it goes about inserting DBG_VALUEs.
178a852ee19SNico Weber     // (It's common for MIR tests to be written containing skeletal IR with
179a852ee19SNico Weber     // empty functions -- we're still interested in debugifying the MIR within
180a852ee19SNico Weber     // those tests, and this helps with that.)
181a852ee19SNico Weber     if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) {
182a852ee19SNico Weber       auto *Term = findTerminatingInstruction(F.getEntryBlock());
183a852ee19SNico Weber       insertDbgVal(*Term, Term);
184a852ee19SNico Weber     }
1851adeeabbSDaniel Sanders     if (ApplyToMF)
1861adeeabbSDaniel Sanders       ApplyToMF(DIB, F);
18725ee8613SDaniel Sanders     DIB.finalizeSubprogram(SP);
18825ee8613SDaniel Sanders   }
18925ee8613SDaniel Sanders   DIB.finalize();
19025ee8613SDaniel Sanders 
19125ee8613SDaniel Sanders   // Track the number of distinct lines and variables.
19225ee8613SDaniel Sanders   NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
19325ee8613SDaniel Sanders   auto addDebugifyOperand = [&](unsigned N) {
19425ee8613SDaniel Sanders     NMD->addOperand(MDNode::get(
195a852ee19SNico Weber         Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N))));
19625ee8613SDaniel Sanders   };
19725ee8613SDaniel Sanders   addDebugifyOperand(NextLine - 1); // Original number of lines.
19825ee8613SDaniel Sanders   addDebugifyOperand(NextVar - 1);  // Original number of variables.
19925ee8613SDaniel Sanders   assert(NMD->getNumOperands() == 2 &&
20025ee8613SDaniel Sanders          "llvm.debugify should have exactly 2 operands!");
20125ee8613SDaniel Sanders 
20225ee8613SDaniel Sanders   // Claim that this synthetic debug info is valid.
20325ee8613SDaniel Sanders   StringRef DIVersionKey = "Debug Info Version";
20425ee8613SDaniel Sanders   if (!M.getModuleFlag(DIVersionKey))
20525ee8613SDaniel Sanders     M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION);
20625ee8613SDaniel Sanders 
20725ee8613SDaniel Sanders   return true;
20825ee8613SDaniel Sanders }
20925ee8613SDaniel Sanders 
2101a2b3536SDjordje Todorovic static bool
2111a2b3536SDjordje Todorovic applyDebugify(Function &F,
2121a2b3536SDjordje Todorovic               enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
2131a2b3536SDjordje Todorovic               DebugInfoPerPassMap *DIPreservationMap = nullptr,
2141a2b3536SDjordje Todorovic               StringRef NameOfWrappedPass = "") {
21598b93385SFangrui Song   Module &M = *F.getParent();
21698b93385SFangrui Song   auto FuncIt = F.getIterator();
2171a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
21898b93385SFangrui Song     return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
2191a2b3536SDjordje Todorovic                                  "FunctionDebugify: ", /*ApplyToMF*/ nullptr);
2201a2b3536SDjordje Todorovic   assert(DIPreservationMap);
2211a2b3536SDjordje Todorovic   return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
2221a2b3536SDjordje Todorovic                                   "FunctionDebugify (original debuginfo)",
2231a2b3536SDjordje Todorovic                                   NameOfWrappedPass);
22498b93385SFangrui Song }
22598b93385SFangrui Song 
2261a2b3536SDjordje Todorovic static bool
2271a2b3536SDjordje Todorovic applyDebugify(Module &M,
2281a2b3536SDjordje Todorovic               enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
2291a2b3536SDjordje Todorovic               DebugInfoPerPassMap *DIPreservationMap = nullptr,
2301a2b3536SDjordje Todorovic               StringRef NameOfWrappedPass = "") {
2311a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
23298b93385SFangrui Song     return applyDebugifyMetadata(M, M.functions(),
2331a2b3536SDjordje Todorovic                                  "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
2341a2b3536SDjordje Todorovic   return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
2351a2b3536SDjordje Todorovic                                   "ModuleDebugify (original debuginfo)",
2361a2b3536SDjordje Todorovic                                   NameOfWrappedPass);
23798b93385SFangrui Song }
23898b93385SFangrui Song 
239122a6bfbSVedant Kumar bool llvm::stripDebugifyMetadata(Module &M) {
240122a6bfbSVedant Kumar   bool Changed = false;
241122a6bfbSVedant Kumar 
242122a6bfbSVedant Kumar   // Remove the llvm.debugify module-level named metadata.
243122a6bfbSVedant Kumar   NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify");
244122a6bfbSVedant Kumar   if (DebugifyMD) {
245122a6bfbSVedant Kumar     M.eraseNamedMetadata(DebugifyMD);
246122a6bfbSVedant Kumar     Changed = true;
247122a6bfbSVedant Kumar   }
248122a6bfbSVedant Kumar 
249122a6bfbSVedant Kumar   // Strip out all debug intrinsics and supporting metadata (subprograms, types,
250122a6bfbSVedant Kumar   // variables, etc).
251122a6bfbSVedant Kumar   Changed |= StripDebugInfo(M);
252122a6bfbSVedant Kumar 
253122a6bfbSVedant Kumar   // Strip out the dead dbg.value prototype.
254122a6bfbSVedant Kumar   Function *DbgValF = M.getFunction("llvm.dbg.value");
255122a6bfbSVedant Kumar   if (DbgValF) {
256122a6bfbSVedant Kumar     assert(DbgValF->isDeclaration() && DbgValF->use_empty() &&
257122a6bfbSVedant Kumar            "Not all debug info stripped?");
258122a6bfbSVedant Kumar     DbgValF->eraseFromParent();
259122a6bfbSVedant Kumar     Changed = true;
260122a6bfbSVedant Kumar   }
261122a6bfbSVedant Kumar 
262122a6bfbSVedant Kumar   // Strip out the module-level Debug Info Version metadata.
263122a6bfbSVedant Kumar   // FIXME: There must be an easier way to remove an operand from a NamedMDNode.
264122a6bfbSVedant Kumar   NamedMDNode *NMD = M.getModuleFlagsMetadata();
2652fa656cdSVedant Kumar   if (!NMD)
2662fa656cdSVedant Kumar     return Changed;
26719aacdb7SKazu Hirata   SmallVector<MDNode *, 4> Flags(NMD->operands());
268122a6bfbSVedant Kumar   NMD->clearOperands();
269122a6bfbSVedant Kumar   for (MDNode *Flag : Flags) {
270122a6bfbSVedant Kumar     MDString *Key = dyn_cast_or_null<MDString>(Flag->getOperand(1));
271122a6bfbSVedant Kumar     if (Key->getString() == "Debug Info Version") {
272122a6bfbSVedant Kumar       Changed = true;
273122a6bfbSVedant Kumar       continue;
274122a6bfbSVedant Kumar     }
275122a6bfbSVedant Kumar     NMD->addOperand(Flag);
276122a6bfbSVedant Kumar   }
277122a6bfbSVedant Kumar   // If we left it empty we might as well remove it.
278122a6bfbSVedant Kumar   if (NMD->getNumOperands() == 0)
279122a6bfbSVedant Kumar     NMD->eraseFromParent();
280122a6bfbSVedant Kumar 
281122a6bfbSVedant Kumar   return Changed;
282122a6bfbSVedant Kumar }
283122a6bfbSVedant Kumar 
2841a2b3536SDjordje Todorovic bool llvm::collectDebugInfoMetadata(Module &M,
2851a2b3536SDjordje Todorovic                                     iterator_range<Module::iterator> Functions,
2861a2b3536SDjordje Todorovic                                     DebugInfoPerPassMap &DIPreservationMap,
2871a2b3536SDjordje Todorovic                                     StringRef Banner,
2881a2b3536SDjordje Todorovic                                     StringRef NameOfWrappedPass) {
2891a2b3536SDjordje Todorovic   LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');
2901a2b3536SDjordje Todorovic 
2911a2b3536SDjordje Todorovic   // Clear the map with the debug info before every single pass.
2921a2b3536SDjordje Todorovic   DIPreservationMap.clear();
2931a2b3536SDjordje Todorovic 
2941a2b3536SDjordje Todorovic   if (!M.getNamedMetadata("llvm.dbg.cu")) {
2951a2b3536SDjordje Todorovic     dbg() << Banner << ": Skipping module without debug info\n";
2961a2b3536SDjordje Todorovic     return false;
2971a2b3536SDjordje Todorovic   }
2981a2b3536SDjordje Todorovic 
2991a2b3536SDjordje Todorovic   // Visit each instruction.
3001a2b3536SDjordje Todorovic   for (Function &F : Functions) {
3011a2b3536SDjordje Todorovic     if (isFunctionSkipped(F))
3021a2b3536SDjordje Todorovic       continue;
3031a2b3536SDjordje Todorovic 
3041a2b3536SDjordje Todorovic     // Collect the DISubprogram.
3051a2b3536SDjordje Todorovic     auto *SP = F.getSubprogram();
3061a2b3536SDjordje Todorovic     DIPreservationMap[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP});
3071a2b3536SDjordje Todorovic     if (SP)
3081a2b3536SDjordje Todorovic       LLVM_DEBUG(dbgs() << "  Collecting subprogram: " << *SP << '\n');
3091a2b3536SDjordje Todorovic 
3101a2b3536SDjordje Todorovic     for (BasicBlock &BB : F) {
3111a2b3536SDjordje Todorovic       // Collect debug locations (!dbg).
3121a2b3536SDjordje Todorovic       // TODO: Collect dbg.values.
3131a2b3536SDjordje Todorovic       for (Instruction &I : BB) {
3141a2b3536SDjordje Todorovic         // Skip PHIs.
3151a2b3536SDjordje Todorovic         if (isa<PHINode>(I))
3161a2b3536SDjordje Todorovic           continue;
3171a2b3536SDjordje Todorovic 
3181a2b3536SDjordje Todorovic         // Skip debug instructions.
3191a2b3536SDjordje Todorovic         if (isa<DbgInfoIntrinsic>(&I))
3201a2b3536SDjordje Todorovic           continue;
3211a2b3536SDjordje Todorovic 
3221a2b3536SDjordje Todorovic         LLVM_DEBUG(dbgs() << "  Collecting info for inst: " << I << '\n');
3231a2b3536SDjordje Todorovic         DIPreservationMap[NameOfWrappedPass].InstToDelete.insert({&I, &I});
3241a2b3536SDjordje Todorovic 
3251a2b3536SDjordje Todorovic         const DILocation *Loc = I.getDebugLoc().get();
3261a2b3536SDjordje Todorovic         bool HasLoc = Loc != nullptr;
3271a2b3536SDjordje Todorovic         DIPreservationMap[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
3281a2b3536SDjordje Todorovic       }
3291a2b3536SDjordje Todorovic     }
3301a2b3536SDjordje Todorovic   }
3311a2b3536SDjordje Todorovic 
3321a2b3536SDjordje Todorovic   return true;
3331a2b3536SDjordje Todorovic }
3341a2b3536SDjordje Todorovic 
3351a2b3536SDjordje Todorovic // This checks the preservation of original debug info attached to functions.
3361a2b3536SDjordje Todorovic static bool checkFunctions(const DebugFnMap &DIFunctionsBefore,
3371a2b3536SDjordje Todorovic                            const DebugFnMap &DIFunctionsAfter,
3381a2b3536SDjordje Todorovic                            StringRef NameOfWrappedPass,
3399f41c03fSDjordje Todorovic                            StringRef FileNameFromCU, bool ShouldWriteIntoJSON,
3409f41c03fSDjordje Todorovic                            llvm::json::Array &Bugs) {
3411a2b3536SDjordje Todorovic   bool Preserved = true;
3421a2b3536SDjordje Todorovic   for (const auto &F : DIFunctionsAfter) {
3431a2b3536SDjordje Todorovic     if (F.second)
3441a2b3536SDjordje Todorovic       continue;
3451a2b3536SDjordje Todorovic     auto SPIt = DIFunctionsBefore.find(F.first);
3461a2b3536SDjordje Todorovic     if (SPIt == DIFunctionsBefore.end()) {
3479f41c03fSDjordje Todorovic       if (ShouldWriteIntoJSON)
3489f41c03fSDjordje Todorovic         Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
3499f41c03fSDjordje Todorovic                                            {"name", F.first},
3509f41c03fSDjordje Todorovic                                            {"action", "not-generate"}}));
3519f41c03fSDjordje Todorovic       else
3521a2b3536SDjordje Todorovic         dbg() << "ERROR: " << NameOfWrappedPass
3531a2b3536SDjordje Todorovic               << " did not generate DISubprogram for " << F.first << " from "
3541a2b3536SDjordje Todorovic               << FileNameFromCU << '\n';
3551a2b3536SDjordje Todorovic       Preserved = false;
3561a2b3536SDjordje Todorovic     } else {
3571a2b3536SDjordje Todorovic       auto SP = SPIt->second;
3581a2b3536SDjordje Todorovic       if (!SP)
3591a2b3536SDjordje Todorovic         continue;
3601a2b3536SDjordje Todorovic       // If the function had the SP attached before the pass, consider it as
3611a2b3536SDjordje Todorovic       // a debug info bug.
3629f41c03fSDjordje Todorovic       if (ShouldWriteIntoJSON)
3639f41c03fSDjordje Todorovic         Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
3649f41c03fSDjordje Todorovic                                            {"name", F.first},
3659f41c03fSDjordje Todorovic                                            {"action", "drop"}}));
3669f41c03fSDjordje Todorovic       else
3671a2b3536SDjordje Todorovic         dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "
3681a2b3536SDjordje Todorovic               << F.first << " from " << FileNameFromCU << '\n';
3691a2b3536SDjordje Todorovic       Preserved = false;
3701a2b3536SDjordje Todorovic     }
3711a2b3536SDjordje Todorovic   }
3721a2b3536SDjordje Todorovic 
3731a2b3536SDjordje Todorovic   return Preserved;
3741a2b3536SDjordje Todorovic }
3751a2b3536SDjordje Todorovic 
3761a2b3536SDjordje Todorovic // This checks the preservation of the original debug info attached to
3771a2b3536SDjordje Todorovic // instructions.
3781a2b3536SDjordje Todorovic static bool checkInstructions(const DebugInstMap &DILocsBefore,
3791a2b3536SDjordje Todorovic                               const DebugInstMap &DILocsAfter,
3801a2b3536SDjordje Todorovic                               const WeakInstValueMap &InstToDelete,
3811a2b3536SDjordje Todorovic                               StringRef NameOfWrappedPass,
3829f41c03fSDjordje Todorovic                               StringRef FileNameFromCU,
3839f41c03fSDjordje Todorovic                               bool ShouldWriteIntoJSON,
3849f41c03fSDjordje Todorovic                               llvm::json::Array &Bugs) {
3851a2b3536SDjordje Todorovic   bool Preserved = true;
3861a2b3536SDjordje Todorovic   for (const auto &L : DILocsAfter) {
3871a2b3536SDjordje Todorovic     if (L.second)
3881a2b3536SDjordje Todorovic       continue;
3891a2b3536SDjordje Todorovic     auto Instr = L.first;
3901a2b3536SDjordje Todorovic 
3911a2b3536SDjordje Todorovic     // In order to avoid pointer reuse/recycling, skip the values that might
3921a2b3536SDjordje Todorovic     // have been deleted during a pass.
3931a2b3536SDjordje Todorovic     auto WeakInstrPtr = InstToDelete.find(Instr);
3941a2b3536SDjordje Todorovic     if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
3951a2b3536SDjordje Todorovic       continue;
3961a2b3536SDjordje Todorovic 
3971a2b3536SDjordje Todorovic     auto FnName = Instr->getFunction()->getName();
3981a2b3536SDjordje Todorovic     auto BB = Instr->getParent();
3991a2b3536SDjordje Todorovic     auto BBName = BB->hasName() ? BB->getName() : "no-name";
4009f41c03fSDjordje Todorovic     auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
4011a2b3536SDjordje Todorovic 
4021a2b3536SDjordje Todorovic     auto InstrIt = DILocsBefore.find(Instr);
4031a2b3536SDjordje Todorovic     if (InstrIt == DILocsBefore.end()) {
4049f41c03fSDjordje Todorovic       if (ShouldWriteIntoJSON)
4059f41c03fSDjordje Todorovic         Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
4069f41c03fSDjordje Todorovic                                            {"fn-name", FnName.str()},
4079f41c03fSDjordje Todorovic                                            {"bb-name", BBName.str()},
4089f41c03fSDjordje Todorovic                                            {"instr", InstName},
4099f41c03fSDjordje Todorovic                                            {"action", "not-generate"}}));
4109f41c03fSDjordje Todorovic       else
4111a2b3536SDjordje Todorovic         dbg() << "WARNING: " << NameOfWrappedPass
4121a2b3536SDjordje Todorovic               << " did not generate DILocation for " << *Instr
4131a2b3536SDjordje Todorovic               << " (BB: " << BBName << ", Fn: " << FnName
4141a2b3536SDjordje Todorovic               << ", File: " << FileNameFromCU << ")\n";
4151a2b3536SDjordje Todorovic       Preserved = false;
4161a2b3536SDjordje Todorovic     } else {
4171a2b3536SDjordje Todorovic       if (!InstrIt->second)
4181a2b3536SDjordje Todorovic         continue;
4191a2b3536SDjordje Todorovic       // If the instr had the !dbg attached before the pass, consider it as
4201a2b3536SDjordje Todorovic       // a debug info issue.
4219f41c03fSDjordje Todorovic       if (ShouldWriteIntoJSON)
4229f41c03fSDjordje Todorovic         Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
4239f41c03fSDjordje Todorovic                                            {"fn-name", FnName.str()},
4249f41c03fSDjordje Todorovic                                            {"bb-name", BBName.str()},
4259f41c03fSDjordje Todorovic                                            {"instr", InstName},
4269f41c03fSDjordje Todorovic                                            {"action", "drop"}}));
4279f41c03fSDjordje Todorovic       else
4281a2b3536SDjordje Todorovic         dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
4291a2b3536SDjordje Todorovic               << *Instr << " (BB: " << BBName << ", Fn: " << FnName
4301a2b3536SDjordje Todorovic               << ", File: " << FileNameFromCU << ")\n";
4311a2b3536SDjordje Todorovic       Preserved = false;
4321a2b3536SDjordje Todorovic     }
4331a2b3536SDjordje Todorovic   }
4341a2b3536SDjordje Todorovic 
4351a2b3536SDjordje Todorovic   return Preserved;
4361a2b3536SDjordje Todorovic }
4371a2b3536SDjordje Todorovic 
4389f41c03fSDjordje Todorovic // Write the json data into the specifed file.
4399f41c03fSDjordje Todorovic static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath,
4409f41c03fSDjordje Todorovic                       StringRef FileNameFromCU, StringRef NameOfWrappedPass,
4419f41c03fSDjordje Todorovic                       llvm::json::Array &Bugs) {
4429f41c03fSDjordje Todorovic   std::error_code EC;
4439f41c03fSDjordje Todorovic   raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC,
44482b3e28eSAbhina Sreeskantharajan                          sys::fs::OF_Append | sys::fs::OF_TextWithCRLF};
4459f41c03fSDjordje Todorovic   if (EC) {
4469f41c03fSDjordje Todorovic     errs() << "Could not open file: " << EC.message() << ", "
4479f41c03fSDjordje Todorovic            << OrigDIVerifyBugsReportFilePath << '\n';
4489f41c03fSDjordje Todorovic     return;
4499f41c03fSDjordje Todorovic   }
4509f41c03fSDjordje Todorovic 
4519f41c03fSDjordje Todorovic   OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", ";
4529f41c03fSDjordje Todorovic 
4539f41c03fSDjordje Todorovic   StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name";
4549f41c03fSDjordje Todorovic   OS_FILE << "\"pass\":\"" << PassName << "\", ";
4559f41c03fSDjordje Todorovic 
4569f41c03fSDjordje Todorovic   llvm::json::Value BugsToPrint{std::move(Bugs)};
4579f41c03fSDjordje Todorovic   OS_FILE << "\"bugs\": " << BugsToPrint;
4589f41c03fSDjordje Todorovic 
4599f41c03fSDjordje Todorovic   OS_FILE << "}\n";
4609f41c03fSDjordje Todorovic }
4619f41c03fSDjordje Todorovic 
4621a2b3536SDjordje Todorovic bool llvm::checkDebugInfoMetadata(Module &M,
4631a2b3536SDjordje Todorovic                                   iterator_range<Module::iterator> Functions,
4641a2b3536SDjordje Todorovic                                   DebugInfoPerPassMap &DIPreservationMap,
4659f41c03fSDjordje Todorovic                                   StringRef Banner, StringRef NameOfWrappedPass,
4669f41c03fSDjordje Todorovic                                   StringRef OrigDIVerifyBugsReportFilePath) {
4671a2b3536SDjordje Todorovic   LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');
4681a2b3536SDjordje Todorovic 
4691a2b3536SDjordje Todorovic   if (!M.getNamedMetadata("llvm.dbg.cu")) {
4701a2b3536SDjordje Todorovic     dbg() << Banner << ": Skipping module without debug info\n";
4711a2b3536SDjordje Todorovic     return false;
4721a2b3536SDjordje Todorovic   }
4731a2b3536SDjordje Todorovic 
4741a2b3536SDjordje Todorovic   // Map the debug info holding DIs after a pass.
4751a2b3536SDjordje Todorovic   DebugInfoPerPassMap DIPreservationAfter;
4761a2b3536SDjordje Todorovic 
4771a2b3536SDjordje Todorovic   // Visit each instruction.
4781a2b3536SDjordje Todorovic   for (Function &F : Functions) {
4791a2b3536SDjordje Todorovic     if (isFunctionSkipped(F))
4801a2b3536SDjordje Todorovic       continue;
4811a2b3536SDjordje Todorovic 
4821a2b3536SDjordje Todorovic     // TODO: Collect metadata other than DISubprograms.
4831a2b3536SDjordje Todorovic     // Collect the DISubprogram.
4841a2b3536SDjordje Todorovic     auto *SP = F.getSubprogram();
4859f41c03fSDjordje Todorovic     DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert(
4869f41c03fSDjordje Todorovic         {F.getName(), SP});
4871a2b3536SDjordje Todorovic     if (SP)
4881a2b3536SDjordje Todorovic       LLVM_DEBUG(dbgs() << "  Collecting subprogram: " << *SP << '\n');
4891a2b3536SDjordje Todorovic 
4901a2b3536SDjordje Todorovic     for (BasicBlock &BB : F) {
4911a2b3536SDjordje Todorovic       // Collect debug locations (!dbg attachments).
4921a2b3536SDjordje Todorovic       // TODO: Collect dbg.values.
4931a2b3536SDjordje Todorovic       for (Instruction &I : BB) {
4941a2b3536SDjordje Todorovic         // Skip PHIs.
4951a2b3536SDjordje Todorovic         if (isa<PHINode>(I))
4961a2b3536SDjordje Todorovic           continue;
4971a2b3536SDjordje Todorovic 
4981a2b3536SDjordje Todorovic         // Skip debug instructions.
4991a2b3536SDjordje Todorovic         if (isa<DbgInfoIntrinsic>(&I))
5001a2b3536SDjordje Todorovic           continue;
5011a2b3536SDjordje Todorovic 
5021a2b3536SDjordje Todorovic         LLVM_DEBUG(dbgs() << "  Collecting info for inst: " << I << '\n');
5031a2b3536SDjordje Todorovic 
5041a2b3536SDjordje Todorovic         const DILocation *Loc = I.getDebugLoc().get();
5051a2b3536SDjordje Todorovic         bool HasLoc = Loc != nullptr;
5061a2b3536SDjordje Todorovic 
5071a2b3536SDjordje Todorovic         DIPreservationAfter[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
5081a2b3536SDjordje Todorovic       }
5091a2b3536SDjordje Todorovic     }
5101a2b3536SDjordje Todorovic   }
5111a2b3536SDjordje Todorovic 
5121a2b3536SDjordje Todorovic   // TODO: The name of the module could be read better?
5131a2b3536SDjordje Todorovic   StringRef FileNameFromCU =
5141a2b3536SDjordje Todorovic       (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
5151a2b3536SDjordje Todorovic           ->getFilename();
5161a2b3536SDjordje Todorovic 
5171a2b3536SDjordje Todorovic   auto DIFunctionsBefore = DIPreservationMap[NameOfWrappedPass].DIFunctions;
5181a2b3536SDjordje Todorovic   auto DIFunctionsAfter = DIPreservationAfter[NameOfWrappedPass].DIFunctions;
5191a2b3536SDjordje Todorovic 
5201a2b3536SDjordje Todorovic   auto DILocsBefore = DIPreservationMap[NameOfWrappedPass].DILocations;
5211a2b3536SDjordje Todorovic   auto DILocsAfter = DIPreservationAfter[NameOfWrappedPass].DILocations;
5221a2b3536SDjordje Todorovic 
5231a2b3536SDjordje Todorovic   auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete;
5241a2b3536SDjordje Todorovic 
5259f41c03fSDjordje Todorovic   bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
5269f41c03fSDjordje Todorovic   llvm::json::Array Bugs;
5279f41c03fSDjordje Todorovic 
5289f41c03fSDjordje Todorovic   bool ResultForFunc =
5299f41c03fSDjordje Todorovic       checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,
5309f41c03fSDjordje Todorovic                      FileNameFromCU, ShouldWriteIntoJSON, Bugs);
5319f41c03fSDjordje Todorovic   bool ResultForInsts = checkInstructions(
5329f41c03fSDjordje Todorovic       DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,
5339f41c03fSDjordje Todorovic       FileNameFromCU, ShouldWriteIntoJSON, Bugs);
5341a2b3536SDjordje Todorovic   bool Result = ResultForFunc && ResultForInsts;
5351a2b3536SDjordje Todorovic 
5361a2b3536SDjordje Todorovic   StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;
5379f41c03fSDjordje Todorovic   if (ShouldWriteIntoJSON && !Bugs.empty())
5389f41c03fSDjordje Todorovic     writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass,
5399f41c03fSDjordje Todorovic               Bugs);
5409f41c03fSDjordje Todorovic 
5411a2b3536SDjordje Todorovic   if (Result)
5421a2b3536SDjordje Todorovic     dbg() << ResultBanner << ": PASS\n";
5431a2b3536SDjordje Todorovic   else
5441a2b3536SDjordje Todorovic     dbg() << ResultBanner << ": FAIL\n";
5451a2b3536SDjordje Todorovic 
5461a2b3536SDjordje Todorovic   LLVM_DEBUG(dbgs() << "\n\n");
5471a2b3536SDjordje Todorovic   return Result;
5481a2b3536SDjordje Todorovic }
5491a2b3536SDjordje Todorovic 
5501adeeabbSDaniel Sanders namespace {
55125ee8613SDaniel Sanders /// Return true if a mis-sized diagnostic is issued for \p DVI.
55225ee8613SDaniel Sanders bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
55325ee8613SDaniel Sanders   // The size of a dbg.value's value operand should match the size of the
55425ee8613SDaniel Sanders   // variable it corresponds to.
55525ee8613SDaniel Sanders   //
55625ee8613SDaniel Sanders   // TODO: This, along with a check for non-null value operands, should be
55725ee8613SDaniel Sanders   // promoted to verifier failures.
55825ee8613SDaniel Sanders 
55925ee8613SDaniel Sanders   // For now, don't try to interpret anything more complicated than an empty
56025ee8613SDaniel Sanders   // DIExpression. Eventually we should try to handle OP_deref and fragments.
56125ee8613SDaniel Sanders   if (DVI->getExpression()->getNumElements())
56225ee8613SDaniel Sanders     return false;
56325ee8613SDaniel Sanders 
5643bfddc25SStephen Tozer   Value *V = DVI->getVariableLocationOp(0);
5653bfddc25SStephen Tozer   if (!V)
5663bfddc25SStephen Tozer     return false;
5673bfddc25SStephen Tozer 
56825ee8613SDaniel Sanders   Type *Ty = V->getType();
56925ee8613SDaniel Sanders   uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);
57025ee8613SDaniel Sanders   Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits();
57125ee8613SDaniel Sanders   if (!ValueOperandSize || !DbgVarSize)
57225ee8613SDaniel Sanders     return false;
57325ee8613SDaniel Sanders 
57425ee8613SDaniel Sanders   bool HasBadSize = false;
57525ee8613SDaniel Sanders   if (Ty->isIntegerTy()) {
57625ee8613SDaniel Sanders     auto Signedness = DVI->getVariable()->getSignedness();
57725ee8613SDaniel Sanders     if (Signedness && *Signedness == DIBasicType::Signedness::Signed)
57825ee8613SDaniel Sanders       HasBadSize = ValueOperandSize < *DbgVarSize;
57925ee8613SDaniel Sanders   } else {
58025ee8613SDaniel Sanders     HasBadSize = ValueOperandSize != *DbgVarSize;
58125ee8613SDaniel Sanders   }
58225ee8613SDaniel Sanders 
58325ee8613SDaniel Sanders   if (HasBadSize) {
58425ee8613SDaniel Sanders     dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize
58525ee8613SDaniel Sanders           << ", but its variable has size " << *DbgVarSize << ": ";
58625ee8613SDaniel Sanders     DVI->print(dbg());
58725ee8613SDaniel Sanders     dbg() << "\n";
58825ee8613SDaniel Sanders   }
58925ee8613SDaniel Sanders   return HasBadSize;
59025ee8613SDaniel Sanders }
59125ee8613SDaniel Sanders 
59225ee8613SDaniel Sanders bool checkDebugifyMetadata(Module &M,
59325ee8613SDaniel Sanders                            iterator_range<Module::iterator> Functions,
59425ee8613SDaniel Sanders                            StringRef NameOfWrappedPass, StringRef Banner,
59525ee8613SDaniel Sanders                            bool Strip, DebugifyStatsMap *StatsMap) {
59625ee8613SDaniel Sanders   // Skip modules without debugify metadata.
59725ee8613SDaniel Sanders   NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
59825ee8613SDaniel Sanders   if (!NMD) {
59965030821SDjordje Todorovic     dbg() << Banner << ": Skipping module without debugify metadata\n";
60025ee8613SDaniel Sanders     return false;
60125ee8613SDaniel Sanders   }
60225ee8613SDaniel Sanders 
60325ee8613SDaniel Sanders   auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
60425ee8613SDaniel Sanders     return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
60525ee8613SDaniel Sanders         ->getZExtValue();
60625ee8613SDaniel Sanders   };
60725ee8613SDaniel Sanders   assert(NMD->getNumOperands() == 2 &&
60825ee8613SDaniel Sanders          "llvm.debugify should have exactly 2 operands!");
60925ee8613SDaniel Sanders   unsigned OriginalNumLines = getDebugifyOperand(0);
61025ee8613SDaniel Sanders   unsigned OriginalNumVars = getDebugifyOperand(1);
61125ee8613SDaniel Sanders   bool HasErrors = false;
61225ee8613SDaniel Sanders 
61325ee8613SDaniel Sanders   // Track debug info loss statistics if able.
61425ee8613SDaniel Sanders   DebugifyStatistics *Stats = nullptr;
61525ee8613SDaniel Sanders   if (StatsMap && !NameOfWrappedPass.empty())
61625ee8613SDaniel Sanders     Stats = &StatsMap->operator[](NameOfWrappedPass);
61725ee8613SDaniel Sanders 
61825ee8613SDaniel Sanders   BitVector MissingLines{OriginalNumLines, true};
61925ee8613SDaniel Sanders   BitVector MissingVars{OriginalNumVars, true};
62025ee8613SDaniel Sanders   for (Function &F : Functions) {
62125ee8613SDaniel Sanders     if (isFunctionSkipped(F))
62225ee8613SDaniel Sanders       continue;
62325ee8613SDaniel Sanders 
62425ee8613SDaniel Sanders     // Find missing lines.
62525ee8613SDaniel Sanders     for (Instruction &I : instructions(F)) {
626*01c90bbdSDjordje Todorovic       if (isa<DbgValueInst>(&I))
62725ee8613SDaniel Sanders         continue;
62825ee8613SDaniel Sanders 
62925ee8613SDaniel Sanders       auto DL = I.getDebugLoc();
63025ee8613SDaniel Sanders       if (DL && DL.getLine() != 0) {
63125ee8613SDaniel Sanders         MissingLines.reset(DL.getLine() - 1);
63225ee8613SDaniel Sanders         continue;
63325ee8613SDaniel Sanders       }
63425ee8613SDaniel Sanders 
635*01c90bbdSDjordje Todorovic       if (!isa<PHINode>(&I) && !DL) {
636c1cad151SVedant Kumar         dbg() << "WARNING: Instruction with empty DebugLoc in function ";
63725ee8613SDaniel Sanders         dbg() << F.getName() << " --";
63825ee8613SDaniel Sanders         I.print(dbg());
63925ee8613SDaniel Sanders         dbg() << "\n";
64025ee8613SDaniel Sanders       }
64125ee8613SDaniel Sanders     }
64225ee8613SDaniel Sanders 
64325ee8613SDaniel Sanders     // Find missing variables and mis-sized debug values.
64425ee8613SDaniel Sanders     for (Instruction &I : instructions(F)) {
64525ee8613SDaniel Sanders       auto *DVI = dyn_cast<DbgValueInst>(&I);
64625ee8613SDaniel Sanders       if (!DVI)
64725ee8613SDaniel Sanders         continue;
64825ee8613SDaniel Sanders 
64925ee8613SDaniel Sanders       unsigned Var = ~0U;
65025ee8613SDaniel Sanders       (void)to_integer(DVI->getVariable()->getName(), Var, 10);
65125ee8613SDaniel Sanders       assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
65225ee8613SDaniel Sanders       bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI);
65325ee8613SDaniel Sanders       if (!HasBadSize)
65425ee8613SDaniel Sanders         MissingVars.reset(Var - 1);
65525ee8613SDaniel Sanders       HasErrors |= HasBadSize;
65625ee8613SDaniel Sanders     }
65725ee8613SDaniel Sanders   }
65825ee8613SDaniel Sanders 
65925ee8613SDaniel Sanders   // Print the results.
66025ee8613SDaniel Sanders   for (unsigned Idx : MissingLines.set_bits())
66125ee8613SDaniel Sanders     dbg() << "WARNING: Missing line " << Idx + 1 << "\n";
66225ee8613SDaniel Sanders 
66325ee8613SDaniel Sanders   for (unsigned Idx : MissingVars.set_bits())
66425ee8613SDaniel Sanders     dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
66525ee8613SDaniel Sanders 
66625ee8613SDaniel Sanders   // Update DI loss statistics.
66725ee8613SDaniel Sanders   if (Stats) {
66825ee8613SDaniel Sanders     Stats->NumDbgLocsExpected += OriginalNumLines;
66925ee8613SDaniel Sanders     Stats->NumDbgLocsMissing += MissingLines.count();
67025ee8613SDaniel Sanders     Stats->NumDbgValuesExpected += OriginalNumVars;
67125ee8613SDaniel Sanders     Stats->NumDbgValuesMissing += MissingVars.count();
67225ee8613SDaniel Sanders   }
67325ee8613SDaniel Sanders 
67425ee8613SDaniel Sanders   dbg() << Banner;
67525ee8613SDaniel Sanders   if (!NameOfWrappedPass.empty())
67625ee8613SDaniel Sanders     dbg() << " [" << NameOfWrappedPass << "]";
67725ee8613SDaniel Sanders   dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
67825ee8613SDaniel Sanders 
679122a6bfbSVedant Kumar   // Strip debugify metadata if required.
680122a6bfbSVedant Kumar   if (Strip)
681122a6bfbSVedant Kumar     return stripDebugifyMetadata(M);
68225ee8613SDaniel Sanders 
68325ee8613SDaniel Sanders   return false;
68425ee8613SDaniel Sanders }
68525ee8613SDaniel Sanders 
68625ee8613SDaniel Sanders /// ModulePass for attaching synthetic debug info to everything, used with the
68725ee8613SDaniel Sanders /// legacy module pass manager.
68825ee8613SDaniel Sanders struct DebugifyModulePass : public ModulePass {
6898ee7c7e0SDjordje Todorovic   bool runOnModule(Module &M) override {
6901a2b3536SDjordje Todorovic     return applyDebugify(M, Mode, DIPreservationMap, NameOfWrappedPass);
6918ee7c7e0SDjordje Todorovic   }
6928ee7c7e0SDjordje Todorovic 
6931a2b3536SDjordje Todorovic   DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
6941a2b3536SDjordje Todorovic                      StringRef NameOfWrappedPass = "",
6951a2b3536SDjordje Todorovic                      DebugInfoPerPassMap *DIPreservationMap = nullptr)
6961a2b3536SDjordje Todorovic       : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
6971a2b3536SDjordje Todorovic         DIPreservationMap(DIPreservationMap), Mode(Mode) {}
6988ee7c7e0SDjordje Todorovic 
6998ee7c7e0SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
7008ee7c7e0SDjordje Todorovic     AU.setPreservesAll();
7018ee7c7e0SDjordje Todorovic   }
7028ee7c7e0SDjordje Todorovic 
7038ee7c7e0SDjordje Todorovic   static char ID; // Pass identification.
7048ee7c7e0SDjordje Todorovic 
7058ee7c7e0SDjordje Todorovic private:
7061a2b3536SDjordje Todorovic   StringRef NameOfWrappedPass;
7071a2b3536SDjordje Todorovic   DebugInfoPerPassMap *DIPreservationMap;
7081a2b3536SDjordje Todorovic   enum DebugifyMode Mode;
7091a2b3536SDjordje Todorovic };
7101a2b3536SDjordje Todorovic 
7111a2b3536SDjordje Todorovic /// FunctionPass for attaching synthetic debug info to instructions within a
7121a2b3536SDjordje Todorovic /// single function, used with the legacy module pass manager.
7131a2b3536SDjordje Todorovic struct DebugifyFunctionPass : public FunctionPass {
7141a2b3536SDjordje Todorovic   bool runOnFunction(Function &F) override {
7151a2b3536SDjordje Todorovic     return applyDebugify(F, Mode, DIPreservationMap, NameOfWrappedPass);
7161a2b3536SDjordje Todorovic   }
7171a2b3536SDjordje Todorovic 
7181a2b3536SDjordje Todorovic   DebugifyFunctionPass(
7191a2b3536SDjordje Todorovic       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
7201a2b3536SDjordje Todorovic       StringRef NameOfWrappedPass = "",
7211a2b3536SDjordje Todorovic       DebugInfoPerPassMap *DIPreservationMap = nullptr)
7221a2b3536SDjordje Todorovic       : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
7231a2b3536SDjordje Todorovic         DIPreservationMap(DIPreservationMap), Mode(Mode) {}
7241a2b3536SDjordje Todorovic 
7251a2b3536SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
7261a2b3536SDjordje Todorovic     AU.setPreservesAll();
7271a2b3536SDjordje Todorovic   }
7281a2b3536SDjordje Todorovic 
7291a2b3536SDjordje Todorovic   static char ID; // Pass identification.
7301a2b3536SDjordje Todorovic 
7311a2b3536SDjordje Todorovic private:
7321a2b3536SDjordje Todorovic   StringRef NameOfWrappedPass;
7331a2b3536SDjordje Todorovic   DebugInfoPerPassMap *DIPreservationMap;
7341a2b3536SDjordje Todorovic   enum DebugifyMode Mode;
7351a2b3536SDjordje Todorovic };
7361a2b3536SDjordje Todorovic 
7371a2b3536SDjordje Todorovic /// ModulePass for checking debug info inserted by -debugify, used with the
7381a2b3536SDjordje Todorovic /// legacy module pass manager.
7391a2b3536SDjordje Todorovic struct CheckDebugifyModulePass : public ModulePass {
7401a2b3536SDjordje Todorovic   bool runOnModule(Module &M) override {
7411a2b3536SDjordje Todorovic     if (Mode == DebugifyMode::SyntheticDebugInfo)
7421a2b3536SDjordje Todorovic       return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
7431a2b3536SDjordje Todorovic                                    "CheckModuleDebugify", Strip, StatsMap);
7441a2b3536SDjordje Todorovic     return checkDebugInfoMetadata(
7451a2b3536SDjordje Todorovic         M, M.functions(), *DIPreservationMap,
7469f41c03fSDjordje Todorovic         "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
7479f41c03fSDjordje Todorovic         OrigDIVerifyBugsReportFilePath);
7481a2b3536SDjordje Todorovic   }
7491a2b3536SDjordje Todorovic 
7501a2b3536SDjordje Todorovic   CheckDebugifyModulePass(
7511a2b3536SDjordje Todorovic       bool Strip = false, StringRef NameOfWrappedPass = "",
7521a2b3536SDjordje Todorovic       DebugifyStatsMap *StatsMap = nullptr,
7531a2b3536SDjordje Todorovic       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
7549f41c03fSDjordje Todorovic       DebugInfoPerPassMap *DIPreservationMap = nullptr,
7559f41c03fSDjordje Todorovic       StringRef OrigDIVerifyBugsReportFilePath = "")
7561a2b3536SDjordje Todorovic       : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
7579f41c03fSDjordje Todorovic         OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
7581a2b3536SDjordje Todorovic         StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
7591a2b3536SDjordje Todorovic         Strip(Strip) {}
7601a2b3536SDjordje Todorovic 
7611a2b3536SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
7621a2b3536SDjordje Todorovic     AU.setPreservesAll();
7631a2b3536SDjordje Todorovic   }
7641a2b3536SDjordje Todorovic 
7651a2b3536SDjordje Todorovic   static char ID; // Pass identification.
7661a2b3536SDjordje Todorovic 
7671a2b3536SDjordje Todorovic private:
76825ee8613SDaniel Sanders   StringRef NameOfWrappedPass;
7699f41c03fSDjordje Todorovic   StringRef OrigDIVerifyBugsReportFilePath;
77025ee8613SDaniel Sanders   DebugifyStatsMap *StatsMap;
7711a2b3536SDjordje Todorovic   DebugInfoPerPassMap *DIPreservationMap;
7721a2b3536SDjordje Todorovic   enum DebugifyMode Mode;
7731a2b3536SDjordje Todorovic   bool Strip;
77425ee8613SDaniel Sanders };
77525ee8613SDaniel Sanders 
77625ee8613SDaniel Sanders /// FunctionPass for checking debug info inserted by -debugify-function, used
77725ee8613SDaniel Sanders /// with the legacy module pass manager.
77825ee8613SDaniel Sanders struct CheckDebugifyFunctionPass : public FunctionPass {
77925ee8613SDaniel Sanders   bool runOnFunction(Function &F) override {
78025ee8613SDaniel Sanders     Module &M = *F.getParent();
78125ee8613SDaniel Sanders     auto FuncIt = F.getIterator();
7821a2b3536SDjordje Todorovic     if (Mode == DebugifyMode::SyntheticDebugInfo)
78325ee8613SDaniel Sanders       return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
78425ee8613SDaniel Sanders                                    NameOfWrappedPass, "CheckFunctionDebugify",
78525ee8613SDaniel Sanders                                    Strip, StatsMap);
7861a2b3536SDjordje Todorovic     return checkDebugInfoMetadata(
7871a2b3536SDjordje Todorovic         M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap,
7889f41c03fSDjordje Todorovic         "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass,
7899f41c03fSDjordje Todorovic         OrigDIVerifyBugsReportFilePath);
79025ee8613SDaniel Sanders   }
79125ee8613SDaniel Sanders 
7921a2b3536SDjordje Todorovic   CheckDebugifyFunctionPass(
7931a2b3536SDjordje Todorovic       bool Strip = false, StringRef NameOfWrappedPass = "",
7941a2b3536SDjordje Todorovic       DebugifyStatsMap *StatsMap = nullptr,
7951a2b3536SDjordje Todorovic       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
7969f41c03fSDjordje Todorovic       DebugInfoPerPassMap *DIPreservationMap = nullptr,
7979f41c03fSDjordje Todorovic       StringRef OrigDIVerifyBugsReportFilePath = "")
7981a2b3536SDjordje Todorovic       : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
7999f41c03fSDjordje Todorovic         OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
8001a2b3536SDjordje Todorovic         StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
8011a2b3536SDjordje Todorovic         Strip(Strip) {}
80225ee8613SDaniel Sanders 
80325ee8613SDaniel Sanders   void getAnalysisUsage(AnalysisUsage &AU) const override {
80425ee8613SDaniel Sanders     AU.setPreservesAll();
80525ee8613SDaniel Sanders   }
80625ee8613SDaniel Sanders 
80725ee8613SDaniel Sanders   static char ID; // Pass identification.
80825ee8613SDaniel Sanders 
80925ee8613SDaniel Sanders private:
81025ee8613SDaniel Sanders   StringRef NameOfWrappedPass;
8119f41c03fSDjordje Todorovic   StringRef OrigDIVerifyBugsReportFilePath;
81225ee8613SDaniel Sanders   DebugifyStatsMap *StatsMap;
8131a2b3536SDjordje Todorovic   DebugInfoPerPassMap *DIPreservationMap;
8141a2b3536SDjordje Todorovic   enum DebugifyMode Mode;
8151a2b3536SDjordje Todorovic   bool Strip;
81625ee8613SDaniel Sanders };
81725ee8613SDaniel Sanders 
81825ee8613SDaniel Sanders } // end anonymous namespace
81925ee8613SDaniel Sanders 
82039856d5dSFangrui Song void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) {
82139856d5dSFangrui Song   std::error_code EC;
82239856d5dSFangrui Song   raw_fd_ostream OS{Path, EC};
82339856d5dSFangrui Song   if (EC) {
82439856d5dSFangrui Song     errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
82539856d5dSFangrui Song     return;
82639856d5dSFangrui Song   }
82725ee8613SDaniel Sanders 
82839856d5dSFangrui Song   OS << "Pass Name" << ',' << "# of missing debug values" << ','
82939856d5dSFangrui Song      << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
83039856d5dSFangrui Song      << "Missing/Expected location ratio" << '\n';
83139856d5dSFangrui Song   for (const auto &Entry : Map) {
83239856d5dSFangrui Song     StringRef Pass = Entry.first;
83339856d5dSFangrui Song     DebugifyStatistics Stats = Entry.second;
83439856d5dSFangrui Song 
83539856d5dSFangrui Song     OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
83639856d5dSFangrui Song        << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
83739856d5dSFangrui Song        << Stats.getEmptyLocationRatio() << '\n';
83839856d5dSFangrui Song   }
83939856d5dSFangrui Song }
84039856d5dSFangrui Song 
8411a2b3536SDjordje Todorovic ModulePass *createDebugifyModulePass(enum DebugifyMode Mode,
8421a2b3536SDjordje Todorovic                                      llvm::StringRef NameOfWrappedPass,
8431a2b3536SDjordje Todorovic                                      DebugInfoPerPassMap *DIPreservationMap) {
8441a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
84539856d5dSFangrui Song     return new DebugifyModulePass();
8461a2b3536SDjordje Todorovic   assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
8471a2b3536SDjordje Todorovic   return new DebugifyModulePass(Mode, NameOfWrappedPass, DIPreservationMap);
84839856d5dSFangrui Song }
84939856d5dSFangrui Song 
8501a2b3536SDjordje Todorovic FunctionPass *
8511a2b3536SDjordje Todorovic createDebugifyFunctionPass(enum DebugifyMode Mode,
8521a2b3536SDjordje Todorovic                            llvm::StringRef NameOfWrappedPass,
8531a2b3536SDjordje Todorovic                            DebugInfoPerPassMap *DIPreservationMap) {
8541a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
85525ee8613SDaniel Sanders     return new DebugifyFunctionPass();
8561a2b3536SDjordje Todorovic   assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
8571a2b3536SDjordje Todorovic   return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap);
85825ee8613SDaniel Sanders }
85925ee8613SDaniel Sanders 
86025ee8613SDaniel Sanders PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
8611adeeabbSDaniel Sanders   applyDebugifyMetadata(M, M.functions(),
8621adeeabbSDaniel Sanders                         "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
86325ee8613SDaniel Sanders   return PreservedAnalyses::all();
86425ee8613SDaniel Sanders }
86525ee8613SDaniel Sanders 
8661a2b3536SDjordje Todorovic ModulePass *createCheckDebugifyModulePass(
8671a2b3536SDjordje Todorovic     bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
8689f41c03fSDjordje Todorovic     enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap,
8699f41c03fSDjordje Todorovic     StringRef OrigDIVerifyBugsReportFilePath) {
8701a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
87125ee8613SDaniel Sanders     return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
8721a2b3536SDjordje Todorovic   assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
8731a2b3536SDjordje Todorovic   return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,
8749f41c03fSDjordje Todorovic                                      DIPreservationMap,
8759f41c03fSDjordje Todorovic                                      OrigDIVerifyBugsReportFilePath);
87625ee8613SDaniel Sanders }
87725ee8613SDaniel Sanders 
8781a2b3536SDjordje Todorovic FunctionPass *createCheckDebugifyFunctionPass(
8791a2b3536SDjordje Todorovic     bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
8809f41c03fSDjordje Todorovic     enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap,
8819f41c03fSDjordje Todorovic     StringRef OrigDIVerifyBugsReportFilePath) {
8821a2b3536SDjordje Todorovic   if (Mode == DebugifyMode::SyntheticDebugInfo)
88325ee8613SDaniel Sanders     return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
8841a2b3536SDjordje Todorovic   assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
8851a2b3536SDjordje Todorovic   return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,
8869f41c03fSDjordje Todorovic                                        DIPreservationMap,
8879f41c03fSDjordje Todorovic                                        OrigDIVerifyBugsReportFilePath);
88825ee8613SDaniel Sanders }
88925ee8613SDaniel Sanders 
89025ee8613SDaniel Sanders PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
89125ee8613SDaniel Sanders                                               ModuleAnalysisManager &) {
89225ee8613SDaniel Sanders   checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false,
89325ee8613SDaniel Sanders                         nullptr);
89425ee8613SDaniel Sanders   return PreservedAnalyses::all();
89525ee8613SDaniel Sanders }
89625ee8613SDaniel Sanders 
8977de6dcd2SArthur Eubanks static bool isIgnoredPass(StringRef PassID) {
8987de6dcd2SArthur Eubanks   return isSpecialPass(PassID, {"PassManager", "PassAdaptor",
8997de6dcd2SArthur Eubanks                                 "AnalysisManagerProxy", "PrintFunctionPass",
9007de6dcd2SArthur Eubanks                                 "PrintModulePass", "BitcodeWriterPass",
9017de6dcd2SArthur Eubanks                                 "ThinLTOBitcodeWriterPass", "VerifierPass"});
9027de6dcd2SArthur Eubanks }
9037de6dcd2SArthur Eubanks 
90498b93385SFangrui Song void DebugifyEachInstrumentation::registerCallbacks(
90598b93385SFangrui Song     PassInstrumentationCallbacks &PIC) {
90698b93385SFangrui Song   PIC.registerBeforeNonSkippedPassCallback([](StringRef P, Any IR) {
9077de6dcd2SArthur Eubanks     if (isIgnoredPass(P))
9087de6dcd2SArthur Eubanks       return;
90998b93385SFangrui Song     if (any_isa<const Function *>(IR))
91098b93385SFangrui Song       applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR)));
91198b93385SFangrui Song     else if (any_isa<const Module *>(IR))
91298b93385SFangrui Song       applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR)));
91398b93385SFangrui Song   });
91498b93385SFangrui Song   PIC.registerAfterPassCallback([this](StringRef P, Any IR,
91598b93385SFangrui Song                                        const PreservedAnalyses &PassPA) {
9167de6dcd2SArthur Eubanks     if (isIgnoredPass(P))
9177de6dcd2SArthur Eubanks       return;
91898b93385SFangrui Song     if (any_isa<const Function *>(IR)) {
91998b93385SFangrui Song       auto &F = *const_cast<Function *>(any_cast<const Function *>(IR));
92098b93385SFangrui Song       Module &M = *F.getParent();
92198b93385SFangrui Song       auto It = F.getIterator();
92298b93385SFangrui Song       checkDebugifyMetadata(M, make_range(It, std::next(It)), P,
92398b93385SFangrui Song                             "CheckFunctionDebugify", /*Strip=*/true, &StatsMap);
92498b93385SFangrui Song     } else if (any_isa<const Module *>(IR)) {
92598b93385SFangrui Song       auto &M = *const_cast<Module *>(any_cast<const Module *>(IR));
92698b93385SFangrui Song       checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify",
92798b93385SFangrui Song                             /*Strip=*/true, &StatsMap);
92898b93385SFangrui Song     }
92998b93385SFangrui Song   });
93098b93385SFangrui Song }
93198b93385SFangrui Song 
93225ee8613SDaniel Sanders char DebugifyModulePass::ID = 0;
93325ee8613SDaniel Sanders static RegisterPass<DebugifyModulePass> DM("debugify",
93425ee8613SDaniel Sanders                                            "Attach debug info to everything");
93525ee8613SDaniel Sanders 
93625ee8613SDaniel Sanders char CheckDebugifyModulePass::ID = 0;
93725ee8613SDaniel Sanders static RegisterPass<CheckDebugifyModulePass>
93825ee8613SDaniel Sanders     CDM("check-debugify", "Check debug info from -debugify");
93925ee8613SDaniel Sanders 
94025ee8613SDaniel Sanders char DebugifyFunctionPass::ID = 0;
94125ee8613SDaniel Sanders static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
94225ee8613SDaniel Sanders                                              "Attach debug info to a function");
94325ee8613SDaniel Sanders 
94425ee8613SDaniel Sanders char CheckDebugifyFunctionPass::ID = 0;
94525ee8613SDaniel Sanders static RegisterPass<CheckDebugifyFunctionPass>
94625ee8613SDaniel Sanders     CDF("check-debugify-function", "Check debug info from -debugify-function");
947