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
40c5600aefSNikola Tesic cl::opt<uint64_t> DebugifyFunctionsLimit(
41c5600aefSNikola Tesic "debugify-func-limit",
42c5600aefSNikola Tesic cl::desc("Set max number of processed functions per pass."),
43c5600aefSNikola Tesic cl::init(UINT_MAX));
44c5600aefSNikola Tesic
4515f7bc78SDaniel Sanders enum class Level {
4615f7bc78SDaniel Sanders Locations,
4715f7bc78SDaniel Sanders LocationsAndVariables
4815f7bc78SDaniel Sanders };
491a2b3536SDjordje Todorovic
5015f7bc78SDaniel Sanders cl::opt<Level> DebugifyLevel(
5115f7bc78SDaniel Sanders "debugify-level", cl::desc("Kind of debug info to add"),
5215f7bc78SDaniel Sanders cl::values(clEnumValN(Level::Locations, "locations", "Locations only"),
5315f7bc78SDaniel Sanders clEnumValN(Level::LocationsAndVariables, "location+variables",
5415f7bc78SDaniel Sanders "Locations and Variables")),
5515f7bc78SDaniel Sanders cl::init(Level::LocationsAndVariables));
5615f7bc78SDaniel Sanders
dbg()5725ee8613SDaniel Sanders raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
5825ee8613SDaniel Sanders
getAllocSizeInBits(Module & M,Type * Ty)5925ee8613SDaniel Sanders uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
6025ee8613SDaniel Sanders return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
6125ee8613SDaniel Sanders }
6225ee8613SDaniel Sanders
isFunctionSkipped(Function & F)6325ee8613SDaniel Sanders bool isFunctionSkipped(Function &F) {
6425ee8613SDaniel Sanders return F.isDeclaration() || !F.hasExactDefinition();
6525ee8613SDaniel Sanders }
6625ee8613SDaniel Sanders
6725ee8613SDaniel Sanders /// Find the basic block's terminating instruction.
6825ee8613SDaniel Sanders ///
6925ee8613SDaniel Sanders /// Special care is needed to handle musttail and deopt calls, as these behave
7025ee8613SDaniel Sanders /// like (but are in fact not) terminators.
findTerminatingInstruction(BasicBlock & BB)7125ee8613SDaniel Sanders Instruction *findTerminatingInstruction(BasicBlock &BB) {
7225ee8613SDaniel Sanders if (auto *I = BB.getTerminatingMustTailCall())
7325ee8613SDaniel Sanders return I;
7425ee8613SDaniel Sanders if (auto *I = BB.getTerminatingDeoptimizeCall())
7525ee8613SDaniel Sanders return I;
7625ee8613SDaniel Sanders return BB.getTerminator();
7725ee8613SDaniel Sanders }
781adeeabbSDaniel Sanders } // end anonymous namespace
7925ee8613SDaniel Sanders
applyDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef Banner,std::function<bool (DIBuilder & DIB,Function & F)> ApplyToMF)801adeeabbSDaniel Sanders bool llvm::applyDebugifyMetadata(
811adeeabbSDaniel Sanders Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
821adeeabbSDaniel Sanders std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) {
8325ee8613SDaniel Sanders // Skip modules with debug info.
8425ee8613SDaniel Sanders if (M.getNamedMetadata("llvm.dbg.cu")) {
8525ee8613SDaniel Sanders dbg() << Banner << "Skipping module with debug info\n";
8625ee8613SDaniel Sanders return false;
8725ee8613SDaniel Sanders }
8825ee8613SDaniel Sanders
8925ee8613SDaniel Sanders DIBuilder DIB(M);
9025ee8613SDaniel Sanders LLVMContext &Ctx = M.getContext();
91a852ee19SNico Weber auto *Int32Ty = Type::getInt32Ty(Ctx);
9225ee8613SDaniel Sanders
9325ee8613SDaniel Sanders // Get a DIType which corresponds to Ty.
9425ee8613SDaniel Sanders DenseMap<uint64_t, DIType *> TypeCache;
9525ee8613SDaniel Sanders auto getCachedDIType = [&](Type *Ty) -> DIType * {
9625ee8613SDaniel Sanders uint64_t Size = getAllocSizeInBits(M, Ty);
9725ee8613SDaniel Sanders DIType *&DTy = TypeCache[Size];
9825ee8613SDaniel Sanders if (!DTy) {
9925ee8613SDaniel Sanders std::string Name = "ty" + utostr(Size);
10025ee8613SDaniel Sanders DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
10125ee8613SDaniel Sanders }
10225ee8613SDaniel Sanders return DTy;
10325ee8613SDaniel Sanders };
10425ee8613SDaniel Sanders
10525ee8613SDaniel Sanders unsigned NextLine = 1;
10625ee8613SDaniel Sanders unsigned NextVar = 1;
10725ee8613SDaniel Sanders auto File = DIB.createFile(M.getName(), "/");
10825ee8613SDaniel Sanders auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify",
10925ee8613SDaniel Sanders /*isOptimized=*/true, "", 0);
11025ee8613SDaniel Sanders
11125ee8613SDaniel Sanders // Visit each instruction.
11225ee8613SDaniel Sanders for (Function &F : Functions) {
11325ee8613SDaniel Sanders if (isFunctionSkipped(F))
11425ee8613SDaniel Sanders continue;
11525ee8613SDaniel Sanders
116a852ee19SNico Weber bool InsertedDbgVal = false;
11725ee8613SDaniel Sanders auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
11825ee8613SDaniel Sanders DISubprogram::DISPFlags SPFlags =
11925ee8613SDaniel Sanders DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;
12025ee8613SDaniel Sanders if (F.hasPrivateLinkage() || F.hasInternalLinkage())
12125ee8613SDaniel Sanders SPFlags |= DISubprogram::SPFlagLocalToUnit;
12225ee8613SDaniel Sanders auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,
12325ee8613SDaniel Sanders SPType, NextLine, DINode::FlagZero, SPFlags);
12425ee8613SDaniel Sanders F.setSubprogram(SP);
125a852ee19SNico Weber
126a852ee19SNico Weber // Helper that inserts a dbg.value before \p InsertBefore, copying the
127a852ee19SNico Weber // location (and possibly the type, if it's non-void) from \p TemplateInst.
128a852ee19SNico Weber auto insertDbgVal = [&](Instruction &TemplateInst,
129a852ee19SNico Weber Instruction *InsertBefore) {
130a852ee19SNico Weber std::string Name = utostr(NextVar++);
131a852ee19SNico Weber Value *V = &TemplateInst;
132a852ee19SNico Weber if (TemplateInst.getType()->isVoidTy())
133a852ee19SNico Weber V = ConstantInt::get(Int32Ty, 0);
134a852ee19SNico Weber const DILocation *Loc = TemplateInst.getDebugLoc().get();
135a852ee19SNico Weber auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
136a852ee19SNico Weber getCachedDIType(V->getType()),
137a852ee19SNico Weber /*AlwaysPreserve=*/true);
138a852ee19SNico Weber DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc,
139a852ee19SNico Weber InsertBefore);
140a852ee19SNico Weber };
141a852ee19SNico Weber
14225ee8613SDaniel Sanders for (BasicBlock &BB : F) {
14325ee8613SDaniel Sanders // Attach debug locations.
14425ee8613SDaniel Sanders for (Instruction &I : BB)
14525ee8613SDaniel Sanders I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
14625ee8613SDaniel Sanders
14715f7bc78SDaniel Sanders if (DebugifyLevel < Level::LocationsAndVariables)
14815f7bc78SDaniel Sanders continue;
14915f7bc78SDaniel Sanders
15025ee8613SDaniel Sanders // Inserting debug values into EH pads can break IR invariants.
15125ee8613SDaniel Sanders if (BB.isEHPad())
15225ee8613SDaniel Sanders continue;
15325ee8613SDaniel Sanders
15425ee8613SDaniel Sanders // Find the terminating instruction, after which no debug values are
15525ee8613SDaniel Sanders // attached.
15625ee8613SDaniel Sanders Instruction *LastInst = findTerminatingInstruction(BB);
15725ee8613SDaniel Sanders assert(LastInst && "Expected basic block with a terminator");
15825ee8613SDaniel Sanders
15925ee8613SDaniel Sanders // Maintain an insertion point which can't be invalidated when updates
16025ee8613SDaniel Sanders // are made.
16125ee8613SDaniel Sanders BasicBlock::iterator InsertPt = BB.getFirstInsertionPt();
16225ee8613SDaniel Sanders assert(InsertPt != BB.end() && "Expected to find an insertion point");
16325ee8613SDaniel Sanders Instruction *InsertBefore = &*InsertPt;
16425ee8613SDaniel Sanders
16525ee8613SDaniel Sanders // Attach debug values.
16625ee8613SDaniel Sanders for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {
16725ee8613SDaniel Sanders // Skip void-valued instructions.
16825ee8613SDaniel Sanders if (I->getType()->isVoidTy())
16925ee8613SDaniel Sanders continue;
17025ee8613SDaniel Sanders
17125ee8613SDaniel Sanders // Phis and EH pads must be grouped at the beginning of the block.
17225ee8613SDaniel Sanders // Only advance the insertion point when we finish visiting these.
17325ee8613SDaniel Sanders if (!isa<PHINode>(I) && !I->isEHPad())
17425ee8613SDaniel Sanders InsertBefore = I->getNextNode();
17525ee8613SDaniel Sanders
176a852ee19SNico Weber insertDbgVal(*I, InsertBefore);
177a852ee19SNico Weber InsertedDbgVal = true;
17825ee8613SDaniel Sanders }
17925ee8613SDaniel Sanders }
180a852ee19SNico Weber // Make sure we emit at least one dbg.value, otherwise MachineDebugify may
181a852ee19SNico Weber // not have anything to work with as it goes about inserting DBG_VALUEs.
182a852ee19SNico Weber // (It's common for MIR tests to be written containing skeletal IR with
183a852ee19SNico Weber // empty functions -- we're still interested in debugifying the MIR within
184a852ee19SNico Weber // those tests, and this helps with that.)
185a852ee19SNico Weber if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) {
186a852ee19SNico Weber auto *Term = findTerminatingInstruction(F.getEntryBlock());
187a852ee19SNico Weber insertDbgVal(*Term, Term);
188a852ee19SNico Weber }
1891adeeabbSDaniel Sanders if (ApplyToMF)
1901adeeabbSDaniel Sanders ApplyToMF(DIB, F);
19125ee8613SDaniel Sanders DIB.finalizeSubprogram(SP);
19225ee8613SDaniel Sanders }
19325ee8613SDaniel Sanders DIB.finalize();
19425ee8613SDaniel Sanders
19525ee8613SDaniel Sanders // Track the number of distinct lines and variables.
19625ee8613SDaniel Sanders NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
19725ee8613SDaniel Sanders auto addDebugifyOperand = [&](unsigned N) {
19825ee8613SDaniel Sanders NMD->addOperand(MDNode::get(
199a852ee19SNico Weber Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N))));
20025ee8613SDaniel Sanders };
20125ee8613SDaniel Sanders addDebugifyOperand(NextLine - 1); // Original number of lines.
20225ee8613SDaniel Sanders addDebugifyOperand(NextVar - 1); // Original number of variables.
20325ee8613SDaniel Sanders assert(NMD->getNumOperands() == 2 &&
20425ee8613SDaniel Sanders "llvm.debugify should have exactly 2 operands!");
20525ee8613SDaniel Sanders
20625ee8613SDaniel Sanders // Claim that this synthetic debug info is valid.
20725ee8613SDaniel Sanders StringRef DIVersionKey = "Debug Info Version";
20825ee8613SDaniel Sanders if (!M.getModuleFlag(DIVersionKey))
20925ee8613SDaniel Sanders M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION);
21025ee8613SDaniel Sanders
21125ee8613SDaniel Sanders return true;
21225ee8613SDaniel Sanders }
21325ee8613SDaniel Sanders
2141a2b3536SDjordje Todorovic static bool
applyDebugify(Function & F,enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo,DebugInfoPerPass * DebugInfoBeforePass=nullptr,StringRef NameOfWrappedPass="")2151a2b3536SDjordje Todorovic applyDebugify(Function &F,
2161a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
21773777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr,
2181a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "") {
21998b93385SFangrui Song Module &M = *F.getParent();
22098b93385SFangrui Song auto FuncIt = F.getIterator();
2211a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
22298b93385SFangrui Song return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
2231a2b3536SDjordje Todorovic "FunctionDebugify: ", /*ApplyToMF*/ nullptr);
22473777b4cSDjordje Todorovic assert(DebugInfoBeforePass);
22573777b4cSDjordje Todorovic return collectDebugInfoMetadata(M, M.functions(), *DebugInfoBeforePass,
2261a2b3536SDjordje Todorovic "FunctionDebugify (original debuginfo)",
2271a2b3536SDjordje Todorovic NameOfWrappedPass);
22898b93385SFangrui Song }
22998b93385SFangrui Song
2301a2b3536SDjordje Todorovic static bool
applyDebugify(Module & M,enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo,DebugInfoPerPass * DebugInfoBeforePass=nullptr,StringRef NameOfWrappedPass="")2311a2b3536SDjordje Todorovic applyDebugify(Module &M,
2321a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
23373777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr,
2341a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "") {
2351a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
23698b93385SFangrui Song return applyDebugifyMetadata(M, M.functions(),
2371a2b3536SDjordje Todorovic "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
23873777b4cSDjordje Todorovic return collectDebugInfoMetadata(M, M.functions(), *DebugInfoBeforePass,
2391a2b3536SDjordje Todorovic "ModuleDebugify (original debuginfo)",
2401a2b3536SDjordje Todorovic NameOfWrappedPass);
24198b93385SFangrui Song }
24298b93385SFangrui Song
stripDebugifyMetadata(Module & M)243122a6bfbSVedant Kumar bool llvm::stripDebugifyMetadata(Module &M) {
244122a6bfbSVedant Kumar bool Changed = false;
245122a6bfbSVedant Kumar
246122a6bfbSVedant Kumar // Remove the llvm.debugify module-level named metadata.
247122a6bfbSVedant Kumar NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify");
248122a6bfbSVedant Kumar if (DebugifyMD) {
249122a6bfbSVedant Kumar M.eraseNamedMetadata(DebugifyMD);
250122a6bfbSVedant Kumar Changed = true;
251122a6bfbSVedant Kumar }
252122a6bfbSVedant Kumar
253122a6bfbSVedant Kumar // Strip out all debug intrinsics and supporting metadata (subprograms, types,
254122a6bfbSVedant Kumar // variables, etc).
255122a6bfbSVedant Kumar Changed |= StripDebugInfo(M);
256122a6bfbSVedant Kumar
257122a6bfbSVedant Kumar // Strip out the dead dbg.value prototype.
258122a6bfbSVedant Kumar Function *DbgValF = M.getFunction("llvm.dbg.value");
259122a6bfbSVedant Kumar if (DbgValF) {
260122a6bfbSVedant Kumar assert(DbgValF->isDeclaration() && DbgValF->use_empty() &&
261122a6bfbSVedant Kumar "Not all debug info stripped?");
262122a6bfbSVedant Kumar DbgValF->eraseFromParent();
263122a6bfbSVedant Kumar Changed = true;
264122a6bfbSVedant Kumar }
265122a6bfbSVedant Kumar
266122a6bfbSVedant Kumar // Strip out the module-level Debug Info Version metadata.
267122a6bfbSVedant Kumar // FIXME: There must be an easier way to remove an operand from a NamedMDNode.
268122a6bfbSVedant Kumar NamedMDNode *NMD = M.getModuleFlagsMetadata();
2692fa656cdSVedant Kumar if (!NMD)
2702fa656cdSVedant Kumar return Changed;
27119aacdb7SKazu Hirata SmallVector<MDNode *, 4> Flags(NMD->operands());
272122a6bfbSVedant Kumar NMD->clearOperands();
273122a6bfbSVedant Kumar for (MDNode *Flag : Flags) {
2741a943923SSimon Pilgrim auto *Key = cast<MDString>(Flag->getOperand(1));
275122a6bfbSVedant Kumar if (Key->getString() == "Debug Info Version") {
276122a6bfbSVedant Kumar Changed = true;
277122a6bfbSVedant Kumar continue;
278122a6bfbSVedant Kumar }
279122a6bfbSVedant Kumar NMD->addOperand(Flag);
280122a6bfbSVedant Kumar }
281122a6bfbSVedant Kumar // If we left it empty we might as well remove it.
282122a6bfbSVedant Kumar if (NMD->getNumOperands() == 0)
283122a6bfbSVedant Kumar NMD->eraseFromParent();
284122a6bfbSVedant Kumar
285122a6bfbSVedant Kumar return Changed;
286122a6bfbSVedant Kumar }
287122a6bfbSVedant Kumar
collectDebugInfoMetadata(Module & M,iterator_range<Module::iterator> Functions,DebugInfoPerPass & DebugInfoBeforePass,StringRef Banner,StringRef NameOfWrappedPass)2881a2b3536SDjordje Todorovic bool llvm::collectDebugInfoMetadata(Module &M,
2891a2b3536SDjordje Todorovic iterator_range<Module::iterator> Functions,
29073777b4cSDjordje Todorovic DebugInfoPerPass &DebugInfoBeforePass,
2911a2b3536SDjordje Todorovic StringRef Banner,
2921a2b3536SDjordje Todorovic StringRef NameOfWrappedPass) {
2931a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');
2941a2b3536SDjordje Todorovic
2951a2b3536SDjordje Todorovic if (!M.getNamedMetadata("llvm.dbg.cu")) {
2961a2b3536SDjordje Todorovic dbg() << Banner << ": Skipping module without debug info\n";
2971a2b3536SDjordje Todorovic return false;
2981a2b3536SDjordje Todorovic }
2991a2b3536SDjordje Todorovic
300c5600aefSNikola Tesic uint64_t FunctionsCnt = DebugInfoBeforePass.DIFunctions.size();
3011a2b3536SDjordje Todorovic // Visit each instruction.
3021a2b3536SDjordje Todorovic for (Function &F : Functions) {
30373777b4cSDjordje Todorovic // Use DI collected after previous Pass (when -debugify-each is used).
30473777b4cSDjordje Todorovic if (DebugInfoBeforePass.DIFunctions.count(&F))
30573777b4cSDjordje Todorovic continue;
30673777b4cSDjordje Todorovic
3071a2b3536SDjordje Todorovic if (isFunctionSkipped(F))
3081a2b3536SDjordje Todorovic continue;
3091a2b3536SDjordje Todorovic
310c5600aefSNikola Tesic // Stop collecting DI if the Functions number reached the limit.
311c5600aefSNikola Tesic if (++FunctionsCnt >= DebugifyFunctionsLimit)
312c5600aefSNikola Tesic break;
3131a2b3536SDjordje Todorovic // Collect the DISubprogram.
3141a2b3536SDjordje Todorovic auto *SP = F.getSubprogram();
31573777b4cSDjordje Todorovic DebugInfoBeforePass.DIFunctions.insert({&F, SP});
316b9076d11SDjordje Todorovic if (SP) {
3171a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
318b9076d11SDjordje Todorovic for (const DINode *DN : SP->getRetainedNodes()) {
319b9076d11SDjordje Todorovic if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
32073777b4cSDjordje Todorovic DebugInfoBeforePass.DIVariables[DV] = 0;
321b9076d11SDjordje Todorovic }
322b9076d11SDjordje Todorovic }
323b9076d11SDjordje Todorovic }
3241a2b3536SDjordje Todorovic
3251a2b3536SDjordje Todorovic for (BasicBlock &BB : F) {
326b9076d11SDjordje Todorovic // Collect debug locations (!dbg) and debug variable intrinsics.
3271a2b3536SDjordje Todorovic for (Instruction &I : BB) {
3281a2b3536SDjordje Todorovic // Skip PHIs.
3291a2b3536SDjordje Todorovic if (isa<PHINode>(I))
3301a2b3536SDjordje Todorovic continue;
3311a2b3536SDjordje Todorovic
33291ea2470SDjordje Todorovic // Cllect dbg.values and dbg.declare.
33391ea2470SDjordje Todorovic if (DebugifyLevel > Level::Locations) {
334b9076d11SDjordje Todorovic if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) {
335b9076d11SDjordje Todorovic if (!SP)
336b9076d11SDjordje Todorovic continue;
337b9076d11SDjordje Todorovic // Skip inlined variables.
338b9076d11SDjordje Todorovic if (I.getDebugLoc().getInlinedAt())
339b9076d11SDjordje Todorovic continue;
340b9076d11SDjordje Todorovic // Skip undef values.
341b9076d11SDjordje Todorovic if (DVI->isUndef())
342b9076d11SDjordje Todorovic continue;
343b9076d11SDjordje Todorovic
344b9076d11SDjordje Todorovic auto *Var = DVI->getVariable();
34573777b4cSDjordje Todorovic DebugInfoBeforePass.DIVariables[Var]++;
346b9076d11SDjordje Todorovic continue;
347b9076d11SDjordje Todorovic }
34891ea2470SDjordje Todorovic }
349b9076d11SDjordje Todorovic
350b9076d11SDjordje Todorovic // Skip debug instructions other than dbg.value and dbg.declare.
3511a2b3536SDjordje Todorovic if (isa<DbgInfoIntrinsic>(&I))
3521a2b3536SDjordje Todorovic continue;
3531a2b3536SDjordje Todorovic
3541a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
35573777b4cSDjordje Todorovic DebugInfoBeforePass.InstToDelete.insert({&I, &I});
3561a2b3536SDjordje Todorovic
3571a2b3536SDjordje Todorovic const DILocation *Loc = I.getDebugLoc().get();
3581a2b3536SDjordje Todorovic bool HasLoc = Loc != nullptr;
35973777b4cSDjordje Todorovic DebugInfoBeforePass.DILocations.insert({&I, HasLoc});
3601a2b3536SDjordje Todorovic }
3611a2b3536SDjordje Todorovic }
3621a2b3536SDjordje Todorovic }
3631a2b3536SDjordje Todorovic
3641a2b3536SDjordje Todorovic return true;
3651a2b3536SDjordje Todorovic }
3661a2b3536SDjordje Todorovic
3671a2b3536SDjordje Todorovic // This checks the preservation of original debug info attached to functions.
checkFunctions(const DebugFnMap & DIFunctionsBefore,const DebugFnMap & DIFunctionsAfter,StringRef NameOfWrappedPass,StringRef FileNameFromCU,bool ShouldWriteIntoJSON,llvm::json::Array & Bugs)3681a2b3536SDjordje Todorovic static bool checkFunctions(const DebugFnMap &DIFunctionsBefore,
3691a2b3536SDjordje Todorovic const DebugFnMap &DIFunctionsAfter,
3701a2b3536SDjordje Todorovic StringRef NameOfWrappedPass,
3719f41c03fSDjordje Todorovic StringRef FileNameFromCU, bool ShouldWriteIntoJSON,
3729f41c03fSDjordje Todorovic llvm::json::Array &Bugs) {
3731a2b3536SDjordje Todorovic bool Preserved = true;
3741a2b3536SDjordje Todorovic for (const auto &F : DIFunctionsAfter) {
3751a2b3536SDjordje Todorovic if (F.second)
3761a2b3536SDjordje Todorovic continue;
3771a2b3536SDjordje Todorovic auto SPIt = DIFunctionsBefore.find(F.first);
3781a2b3536SDjordje Todorovic if (SPIt == DIFunctionsBefore.end()) {
3799f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON)
3809f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
38173777b4cSDjordje Todorovic {"name", F.first->getName()},
3829f41c03fSDjordje Todorovic {"action", "not-generate"}}));
3839f41c03fSDjordje Todorovic else
3841a2b3536SDjordje Todorovic dbg() << "ERROR: " << NameOfWrappedPass
38573777b4cSDjordje Todorovic << " did not generate DISubprogram for " << F.first->getName()
38673777b4cSDjordje Todorovic << " from " << FileNameFromCU << '\n';
3871a2b3536SDjordje Todorovic Preserved = false;
3881a2b3536SDjordje Todorovic } else {
3891a2b3536SDjordje Todorovic auto SP = SPIt->second;
3901a2b3536SDjordje Todorovic if (!SP)
3911a2b3536SDjordje Todorovic continue;
3921a2b3536SDjordje Todorovic // If the function had the SP attached before the pass, consider it as
3931a2b3536SDjordje Todorovic // a debug info bug.
3949f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON)
3959f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
39673777b4cSDjordje Todorovic {"name", F.first->getName()},
3979f41c03fSDjordje Todorovic {"action", "drop"}}));
3989f41c03fSDjordje Todorovic else
3991a2b3536SDjordje Todorovic dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "
40073777b4cSDjordje Todorovic << F.first->getName() << " from " << FileNameFromCU << '\n';
4011a2b3536SDjordje Todorovic Preserved = false;
4021a2b3536SDjordje Todorovic }
4031a2b3536SDjordje Todorovic }
4041a2b3536SDjordje Todorovic
4051a2b3536SDjordje Todorovic return Preserved;
4061a2b3536SDjordje Todorovic }
4071a2b3536SDjordje Todorovic
4081a2b3536SDjordje Todorovic // This checks the preservation of the original debug info attached to
4091a2b3536SDjordje Todorovic // instructions.
checkInstructions(const DebugInstMap & DILocsBefore,const DebugInstMap & DILocsAfter,const WeakInstValueMap & InstToDelete,StringRef NameOfWrappedPass,StringRef FileNameFromCU,bool ShouldWriteIntoJSON,llvm::json::Array & Bugs)4101a2b3536SDjordje Todorovic static bool checkInstructions(const DebugInstMap &DILocsBefore,
4111a2b3536SDjordje Todorovic const DebugInstMap &DILocsAfter,
4121a2b3536SDjordje Todorovic const WeakInstValueMap &InstToDelete,
4131a2b3536SDjordje Todorovic StringRef NameOfWrappedPass,
4149f41c03fSDjordje Todorovic StringRef FileNameFromCU,
4159f41c03fSDjordje Todorovic bool ShouldWriteIntoJSON,
4169f41c03fSDjordje Todorovic llvm::json::Array &Bugs) {
4171a2b3536SDjordje Todorovic bool Preserved = true;
4181a2b3536SDjordje Todorovic for (const auto &L : DILocsAfter) {
4191a2b3536SDjordje Todorovic if (L.second)
4201a2b3536SDjordje Todorovic continue;
4211a2b3536SDjordje Todorovic auto Instr = L.first;
4221a2b3536SDjordje Todorovic
4231a2b3536SDjordje Todorovic // In order to avoid pointer reuse/recycling, skip the values that might
4241a2b3536SDjordje Todorovic // have been deleted during a pass.
4251a2b3536SDjordje Todorovic auto WeakInstrPtr = InstToDelete.find(Instr);
4261a2b3536SDjordje Todorovic if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
4271a2b3536SDjordje Todorovic continue;
4281a2b3536SDjordje Todorovic
4291a2b3536SDjordje Todorovic auto FnName = Instr->getFunction()->getName();
4301a2b3536SDjordje Todorovic auto BB = Instr->getParent();
4311a2b3536SDjordje Todorovic auto BBName = BB->hasName() ? BB->getName() : "no-name";
4329f41c03fSDjordje Todorovic auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
4331a2b3536SDjordje Todorovic
4341a2b3536SDjordje Todorovic auto InstrIt = DILocsBefore.find(Instr);
4351a2b3536SDjordje Todorovic if (InstrIt == DILocsBefore.end()) {
4369f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON)
4379f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
4389f41c03fSDjordje Todorovic {"fn-name", FnName.str()},
4399f41c03fSDjordje Todorovic {"bb-name", BBName.str()},
4409f41c03fSDjordje Todorovic {"instr", InstName},
4419f41c03fSDjordje Todorovic {"action", "not-generate"}}));
4429f41c03fSDjordje Todorovic else
4431a2b3536SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass
4441a2b3536SDjordje Todorovic << " did not generate DILocation for " << *Instr
4451a2b3536SDjordje Todorovic << " (BB: " << BBName << ", Fn: " << FnName
4461a2b3536SDjordje Todorovic << ", File: " << FileNameFromCU << ")\n";
4471a2b3536SDjordje Todorovic Preserved = false;
4481a2b3536SDjordje Todorovic } else {
4491a2b3536SDjordje Todorovic if (!InstrIt->second)
4501a2b3536SDjordje Todorovic continue;
4511a2b3536SDjordje Todorovic // If the instr had the !dbg attached before the pass, consider it as
4521a2b3536SDjordje Todorovic // a debug info issue.
4539f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON)
4549f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
4559f41c03fSDjordje Todorovic {"fn-name", FnName.str()},
4569f41c03fSDjordje Todorovic {"bb-name", BBName.str()},
4579f41c03fSDjordje Todorovic {"instr", InstName},
4589f41c03fSDjordje Todorovic {"action", "drop"}}));
4599f41c03fSDjordje Todorovic else
4601a2b3536SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
4611a2b3536SDjordje Todorovic << *Instr << " (BB: " << BBName << ", Fn: " << FnName
4621a2b3536SDjordje Todorovic << ", File: " << FileNameFromCU << ")\n";
4631a2b3536SDjordje Todorovic Preserved = false;
4641a2b3536SDjordje Todorovic }
4651a2b3536SDjordje Todorovic }
4661a2b3536SDjordje Todorovic
4671a2b3536SDjordje Todorovic return Preserved;
4681a2b3536SDjordje Todorovic }
4691a2b3536SDjordje Todorovic
470b9076d11SDjordje Todorovic // This checks the preservation of original debug variable intrinsics.
checkVars(const DebugVarMap & DIVarsBefore,const DebugVarMap & DIVarsAfter,StringRef NameOfWrappedPass,StringRef FileNameFromCU,bool ShouldWriteIntoJSON,llvm::json::Array & Bugs)471f8dfc352SDjordje Todorovic static bool checkVars(const DebugVarMap &DIVarsBefore,
472f8dfc352SDjordje Todorovic const DebugVarMap &DIVarsAfter,
473b9076d11SDjordje Todorovic StringRef NameOfWrappedPass, StringRef FileNameFromCU,
474b9076d11SDjordje Todorovic bool ShouldWriteIntoJSON, llvm::json::Array &Bugs) {
475b9076d11SDjordje Todorovic bool Preserved = true;
476f8dfc352SDjordje Todorovic for (const auto &V : DIVarsBefore) {
477f8dfc352SDjordje Todorovic auto VarIt = DIVarsAfter.find(V.first);
478f8dfc352SDjordje Todorovic if (VarIt == DIVarsAfter.end())
479b9076d11SDjordje Todorovic continue;
480b9076d11SDjordje Todorovic
481b9076d11SDjordje Todorovic unsigned NumOfDbgValsAfter = VarIt->second;
482b9076d11SDjordje Todorovic
483b9076d11SDjordje Todorovic if (V.second > NumOfDbgValsAfter) {
484b9076d11SDjordje Todorovic if (ShouldWriteIntoJSON)
485b9076d11SDjordje Todorovic Bugs.push_back(llvm::json::Object(
486b9076d11SDjordje Todorovic {{"metadata", "dbg-var-intrinsic"},
487b9076d11SDjordje Todorovic {"name", V.first->getName()},
488b9076d11SDjordje Todorovic {"fn-name", V.first->getScope()->getSubprogram()->getName()},
489b9076d11SDjordje Todorovic {"action", "drop"}}));
490b9076d11SDjordje Todorovic else
491b9076d11SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass
492b9076d11SDjordje Todorovic << " drops dbg.value()/dbg.declare() for " << V.first->getName()
493b9076d11SDjordje Todorovic << " from "
494b9076d11SDjordje Todorovic << "function " << V.first->getScope()->getSubprogram()->getName()
495b9076d11SDjordje Todorovic << " (file " << FileNameFromCU << ")\n";
496b9076d11SDjordje Todorovic Preserved = false;
497b9076d11SDjordje Todorovic }
498b9076d11SDjordje Todorovic }
499b9076d11SDjordje Todorovic
500b9076d11SDjordje Todorovic return Preserved;
501b9076d11SDjordje Todorovic }
502b9076d11SDjordje Todorovic
5039f41c03fSDjordje Todorovic // Write the json data into the specifed file.
writeJSON(StringRef OrigDIVerifyBugsReportFilePath,StringRef FileNameFromCU,StringRef NameOfWrappedPass,llvm::json::Array & Bugs)5049f41c03fSDjordje Todorovic static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath,
5059f41c03fSDjordje Todorovic StringRef FileNameFromCU, StringRef NameOfWrappedPass,
5069f41c03fSDjordje Todorovic llvm::json::Array &Bugs) {
5079f41c03fSDjordje Todorovic std::error_code EC;
5089f41c03fSDjordje Todorovic raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC,
50982b3e28eSAbhina Sreeskantharajan sys::fs::OF_Append | sys::fs::OF_TextWithCRLF};
5109f41c03fSDjordje Todorovic if (EC) {
5119f41c03fSDjordje Todorovic errs() << "Could not open file: " << EC.message() << ", "
5129f41c03fSDjordje Todorovic << OrigDIVerifyBugsReportFilePath << '\n';
5139f41c03fSDjordje Todorovic return;
5149f41c03fSDjordje Todorovic }
5159f41c03fSDjordje Todorovic
5169f41c03fSDjordje Todorovic OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", ";
5179f41c03fSDjordje Todorovic
5189f41c03fSDjordje Todorovic StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name";
5199f41c03fSDjordje Todorovic OS_FILE << "\"pass\":\"" << PassName << "\", ";
5209f41c03fSDjordje Todorovic
5219f41c03fSDjordje Todorovic llvm::json::Value BugsToPrint{std::move(Bugs)};
5229f41c03fSDjordje Todorovic OS_FILE << "\"bugs\": " << BugsToPrint;
5239f41c03fSDjordje Todorovic
5249f41c03fSDjordje Todorovic OS_FILE << "}\n";
5259f41c03fSDjordje Todorovic }
5269f41c03fSDjordje Todorovic
checkDebugInfoMetadata(Module & M,iterator_range<Module::iterator> Functions,DebugInfoPerPass & DebugInfoBeforePass,StringRef Banner,StringRef NameOfWrappedPass,StringRef OrigDIVerifyBugsReportFilePath)5271a2b3536SDjordje Todorovic bool llvm::checkDebugInfoMetadata(Module &M,
5281a2b3536SDjordje Todorovic iterator_range<Module::iterator> Functions,
52973777b4cSDjordje Todorovic DebugInfoPerPass &DebugInfoBeforePass,
5309f41c03fSDjordje Todorovic StringRef Banner, StringRef NameOfWrappedPass,
5319f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) {
5321a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');
5331a2b3536SDjordje Todorovic
5341a2b3536SDjordje Todorovic if (!M.getNamedMetadata("llvm.dbg.cu")) {
5351a2b3536SDjordje Todorovic dbg() << Banner << ": Skipping module without debug info\n";
5361a2b3536SDjordje Todorovic return false;
5371a2b3536SDjordje Todorovic }
5381a2b3536SDjordje Todorovic
5391a2b3536SDjordje Todorovic // Map the debug info holding DIs after a pass.
54073777b4cSDjordje Todorovic DebugInfoPerPass DebugInfoAfterPass;
5411a2b3536SDjordje Todorovic
5421a2b3536SDjordje Todorovic // Visit each instruction.
5431a2b3536SDjordje Todorovic for (Function &F : Functions) {
5441a2b3536SDjordje Todorovic if (isFunctionSkipped(F))
5451a2b3536SDjordje Todorovic continue;
5461a2b3536SDjordje Todorovic
547c5600aefSNikola Tesic // Don't process functions without DI collected before the Pass.
548c5600aefSNikola Tesic if (!DebugInfoBeforePass.DIFunctions.count(&F))
549c5600aefSNikola Tesic continue;
5501a2b3536SDjordje Todorovic // TODO: Collect metadata other than DISubprograms.
5511a2b3536SDjordje Todorovic // Collect the DISubprogram.
5521a2b3536SDjordje Todorovic auto *SP = F.getSubprogram();
55373777b4cSDjordje Todorovic DebugInfoAfterPass.DIFunctions.insert({&F, SP});
554b9076d11SDjordje Todorovic
555b9076d11SDjordje Todorovic if (SP) {
5561a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
557b9076d11SDjordje Todorovic for (const DINode *DN : SP->getRetainedNodes()) {
558b9076d11SDjordje Todorovic if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
55973777b4cSDjordje Todorovic DebugInfoAfterPass.DIVariables[DV] = 0;
560b9076d11SDjordje Todorovic }
561b9076d11SDjordje Todorovic }
562b9076d11SDjordje Todorovic }
5631a2b3536SDjordje Todorovic
5641a2b3536SDjordje Todorovic for (BasicBlock &BB : F) {
565b9076d11SDjordje Todorovic // Collect debug locations (!dbg) and debug variable intrinsics.
5661a2b3536SDjordje Todorovic for (Instruction &I : BB) {
5671a2b3536SDjordje Todorovic // Skip PHIs.
5681a2b3536SDjordje Todorovic if (isa<PHINode>(I))
5691a2b3536SDjordje Todorovic continue;
5701a2b3536SDjordje Todorovic
571b9076d11SDjordje Todorovic // Collect dbg.values and dbg.declares.
57291ea2470SDjordje Todorovic if (DebugifyLevel > Level::Locations) {
573b9076d11SDjordje Todorovic if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) {
574b9076d11SDjordje Todorovic if (!SP)
575b9076d11SDjordje Todorovic continue;
576b9076d11SDjordje Todorovic // Skip inlined variables.
577b9076d11SDjordje Todorovic if (I.getDebugLoc().getInlinedAt())
578b9076d11SDjordje Todorovic continue;
579b9076d11SDjordje Todorovic // Skip undef values.
580b9076d11SDjordje Todorovic if (DVI->isUndef())
581b9076d11SDjordje Todorovic continue;
582b9076d11SDjordje Todorovic
583b9076d11SDjordje Todorovic auto *Var = DVI->getVariable();
58473777b4cSDjordje Todorovic DebugInfoAfterPass.DIVariables[Var]++;
585b9076d11SDjordje Todorovic continue;
586b9076d11SDjordje Todorovic }
58791ea2470SDjordje Todorovic }
588b9076d11SDjordje Todorovic
589b9076d11SDjordje Todorovic // Skip debug instructions other than dbg.value and dbg.declare.
5901a2b3536SDjordje Todorovic if (isa<DbgInfoIntrinsic>(&I))
5911a2b3536SDjordje Todorovic continue;
5921a2b3536SDjordje Todorovic
5931a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
5941a2b3536SDjordje Todorovic
5951a2b3536SDjordje Todorovic const DILocation *Loc = I.getDebugLoc().get();
5961a2b3536SDjordje Todorovic bool HasLoc = Loc != nullptr;
5971a2b3536SDjordje Todorovic
59873777b4cSDjordje Todorovic DebugInfoAfterPass.DILocations.insert({&I, HasLoc});
5991a2b3536SDjordje Todorovic }
6001a2b3536SDjordje Todorovic }
6011a2b3536SDjordje Todorovic }
6021a2b3536SDjordje Todorovic
6031a2b3536SDjordje Todorovic // TODO: The name of the module could be read better?
6041a2b3536SDjordje Todorovic StringRef FileNameFromCU =
6051a2b3536SDjordje Todorovic (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
6061a2b3536SDjordje Todorovic ->getFilename();
6071a2b3536SDjordje Todorovic
60873777b4cSDjordje Todorovic auto DIFunctionsBefore = DebugInfoBeforePass.DIFunctions;
60973777b4cSDjordje Todorovic auto DIFunctionsAfter = DebugInfoAfterPass.DIFunctions;
6101a2b3536SDjordje Todorovic
61173777b4cSDjordje Todorovic auto DILocsBefore = DebugInfoBeforePass.DILocations;
61273777b4cSDjordje Todorovic auto DILocsAfter = DebugInfoAfterPass.DILocations;
6131a2b3536SDjordje Todorovic
61473777b4cSDjordje Todorovic auto InstToDelete = DebugInfoBeforePass.InstToDelete;
6151a2b3536SDjordje Todorovic
61673777b4cSDjordje Todorovic auto DIVarsBefore = DebugInfoBeforePass.DIVariables;
61773777b4cSDjordje Todorovic auto DIVarsAfter = DebugInfoAfterPass.DIVariables;
618b9076d11SDjordje Todorovic
6199f41c03fSDjordje Todorovic bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
6209f41c03fSDjordje Todorovic llvm::json::Array Bugs;
6219f41c03fSDjordje Todorovic
6229f41c03fSDjordje Todorovic bool ResultForFunc =
6239f41c03fSDjordje Todorovic checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,
6249f41c03fSDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs);
6259f41c03fSDjordje Todorovic bool ResultForInsts = checkInstructions(
6269f41c03fSDjordje Todorovic DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,
6279f41c03fSDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs);
628b9076d11SDjordje Todorovic
629b9076d11SDjordje Todorovic bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass,
630b9076d11SDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs);
631b9076d11SDjordje Todorovic
632b9076d11SDjordje Todorovic bool Result = ResultForFunc && ResultForInsts && ResultForVars;
6331a2b3536SDjordje Todorovic
6341a2b3536SDjordje Todorovic StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;
6359f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON && !Bugs.empty())
6369f41c03fSDjordje Todorovic writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass,
6379f41c03fSDjordje Todorovic Bugs);
6389f41c03fSDjordje Todorovic
6391a2b3536SDjordje Todorovic if (Result)
6401a2b3536SDjordje Todorovic dbg() << ResultBanner << ": PASS\n";
6411a2b3536SDjordje Todorovic else
6421a2b3536SDjordje Todorovic dbg() << ResultBanner << ": FAIL\n";
6431a2b3536SDjordje Todorovic
64473777b4cSDjordje Todorovic // In the case of the `debugify-each`, no need to go over all the instructions
64573777b4cSDjordje Todorovic // again in the collectDebugInfoMetadata(), since as an input we can use
64673777b4cSDjordje Todorovic // the debugging information from the previous pass.
64773777b4cSDjordje Todorovic DebugInfoBeforePass = DebugInfoAfterPass;
64873777b4cSDjordje Todorovic
6491a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << "\n\n");
6501a2b3536SDjordje Todorovic return Result;
6511a2b3536SDjordje Todorovic }
6521a2b3536SDjordje Todorovic
6531adeeabbSDaniel Sanders namespace {
65425ee8613SDaniel Sanders /// Return true if a mis-sized diagnostic is issued for \p DVI.
diagnoseMisSizedDbgValue(Module & M,DbgValueInst * DVI)65525ee8613SDaniel Sanders bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
65625ee8613SDaniel Sanders // The size of a dbg.value's value operand should match the size of the
65725ee8613SDaniel Sanders // variable it corresponds to.
65825ee8613SDaniel Sanders //
65925ee8613SDaniel Sanders // TODO: This, along with a check for non-null value operands, should be
66025ee8613SDaniel Sanders // promoted to verifier failures.
66125ee8613SDaniel Sanders
66225ee8613SDaniel Sanders // For now, don't try to interpret anything more complicated than an empty
66325ee8613SDaniel Sanders // DIExpression. Eventually we should try to handle OP_deref and fragments.
66425ee8613SDaniel Sanders if (DVI->getExpression()->getNumElements())
66525ee8613SDaniel Sanders return false;
66625ee8613SDaniel Sanders
6673bfddc25SStephen Tozer Value *V = DVI->getVariableLocationOp(0);
6683bfddc25SStephen Tozer if (!V)
6693bfddc25SStephen Tozer return false;
6703bfddc25SStephen Tozer
67125ee8613SDaniel Sanders Type *Ty = V->getType();
67225ee8613SDaniel Sanders uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);
67325ee8613SDaniel Sanders Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits();
67425ee8613SDaniel Sanders if (!ValueOperandSize || !DbgVarSize)
67525ee8613SDaniel Sanders return false;
67625ee8613SDaniel Sanders
67725ee8613SDaniel Sanders bool HasBadSize = false;
67825ee8613SDaniel Sanders if (Ty->isIntegerTy()) {
67925ee8613SDaniel Sanders auto Signedness = DVI->getVariable()->getSignedness();
68025ee8613SDaniel Sanders if (Signedness && *Signedness == DIBasicType::Signedness::Signed)
68125ee8613SDaniel Sanders HasBadSize = ValueOperandSize < *DbgVarSize;
68225ee8613SDaniel Sanders } else {
68325ee8613SDaniel Sanders HasBadSize = ValueOperandSize != *DbgVarSize;
68425ee8613SDaniel Sanders }
68525ee8613SDaniel Sanders
68625ee8613SDaniel Sanders if (HasBadSize) {
68725ee8613SDaniel Sanders dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize
68825ee8613SDaniel Sanders << ", but its variable has size " << *DbgVarSize << ": ";
68925ee8613SDaniel Sanders DVI->print(dbg());
69025ee8613SDaniel Sanders dbg() << "\n";
69125ee8613SDaniel Sanders }
69225ee8613SDaniel Sanders return HasBadSize;
69325ee8613SDaniel Sanders }
69425ee8613SDaniel Sanders
checkDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef NameOfWrappedPass,StringRef Banner,bool Strip,DebugifyStatsMap * StatsMap)69525ee8613SDaniel Sanders bool checkDebugifyMetadata(Module &M,
69625ee8613SDaniel Sanders iterator_range<Module::iterator> Functions,
69725ee8613SDaniel Sanders StringRef NameOfWrappedPass, StringRef Banner,
69825ee8613SDaniel Sanders bool Strip, DebugifyStatsMap *StatsMap) {
69925ee8613SDaniel Sanders // Skip modules without debugify metadata.
70025ee8613SDaniel Sanders NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
70125ee8613SDaniel Sanders if (!NMD) {
70265030821SDjordje Todorovic dbg() << Banner << ": Skipping module without debugify metadata\n";
70325ee8613SDaniel Sanders return false;
70425ee8613SDaniel Sanders }
70525ee8613SDaniel Sanders
70625ee8613SDaniel Sanders auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
70725ee8613SDaniel Sanders return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
70825ee8613SDaniel Sanders ->getZExtValue();
70925ee8613SDaniel Sanders };
71025ee8613SDaniel Sanders assert(NMD->getNumOperands() == 2 &&
71125ee8613SDaniel Sanders "llvm.debugify should have exactly 2 operands!");
71225ee8613SDaniel Sanders unsigned OriginalNumLines = getDebugifyOperand(0);
71325ee8613SDaniel Sanders unsigned OriginalNumVars = getDebugifyOperand(1);
71425ee8613SDaniel Sanders bool HasErrors = false;
71525ee8613SDaniel Sanders
71625ee8613SDaniel Sanders // Track debug info loss statistics if able.
71725ee8613SDaniel Sanders DebugifyStatistics *Stats = nullptr;
71825ee8613SDaniel Sanders if (StatsMap && !NameOfWrappedPass.empty())
71925ee8613SDaniel Sanders Stats = &StatsMap->operator[](NameOfWrappedPass);
72025ee8613SDaniel Sanders
72125ee8613SDaniel Sanders BitVector MissingLines{OriginalNumLines, true};
72225ee8613SDaniel Sanders BitVector MissingVars{OriginalNumVars, true};
72325ee8613SDaniel Sanders for (Function &F : Functions) {
72425ee8613SDaniel Sanders if (isFunctionSkipped(F))
72525ee8613SDaniel Sanders continue;
72625ee8613SDaniel Sanders
72725ee8613SDaniel Sanders // Find missing lines.
72825ee8613SDaniel Sanders for (Instruction &I : instructions(F)) {
72901c90bbdSDjordje Todorovic if (isa<DbgValueInst>(&I))
73025ee8613SDaniel Sanders continue;
73125ee8613SDaniel Sanders
73225ee8613SDaniel Sanders auto DL = I.getDebugLoc();
73325ee8613SDaniel Sanders if (DL && DL.getLine() != 0) {
73425ee8613SDaniel Sanders MissingLines.reset(DL.getLine() - 1);
73525ee8613SDaniel Sanders continue;
73625ee8613SDaniel Sanders }
73725ee8613SDaniel Sanders
73801c90bbdSDjordje Todorovic if (!isa<PHINode>(&I) && !DL) {
739c1cad151SVedant Kumar dbg() << "WARNING: Instruction with empty DebugLoc in function ";
74025ee8613SDaniel Sanders dbg() << F.getName() << " --";
74125ee8613SDaniel Sanders I.print(dbg());
74225ee8613SDaniel Sanders dbg() << "\n";
74325ee8613SDaniel Sanders }
74425ee8613SDaniel Sanders }
74525ee8613SDaniel Sanders
74625ee8613SDaniel Sanders // Find missing variables and mis-sized debug values.
74725ee8613SDaniel Sanders for (Instruction &I : instructions(F)) {
74825ee8613SDaniel Sanders auto *DVI = dyn_cast<DbgValueInst>(&I);
74925ee8613SDaniel Sanders if (!DVI)
75025ee8613SDaniel Sanders continue;
75125ee8613SDaniel Sanders
75225ee8613SDaniel Sanders unsigned Var = ~0U;
75325ee8613SDaniel Sanders (void)to_integer(DVI->getVariable()->getName(), Var, 10);
75425ee8613SDaniel Sanders assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
75525ee8613SDaniel Sanders bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI);
75625ee8613SDaniel Sanders if (!HasBadSize)
75725ee8613SDaniel Sanders MissingVars.reset(Var - 1);
75825ee8613SDaniel Sanders HasErrors |= HasBadSize;
75925ee8613SDaniel Sanders }
76025ee8613SDaniel Sanders }
76125ee8613SDaniel Sanders
76225ee8613SDaniel Sanders // Print the results.
76325ee8613SDaniel Sanders for (unsigned Idx : MissingLines.set_bits())
76425ee8613SDaniel Sanders dbg() << "WARNING: Missing line " << Idx + 1 << "\n";
76525ee8613SDaniel Sanders
76625ee8613SDaniel Sanders for (unsigned Idx : MissingVars.set_bits())
76725ee8613SDaniel Sanders dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
76825ee8613SDaniel Sanders
76925ee8613SDaniel Sanders // Update DI loss statistics.
77025ee8613SDaniel Sanders if (Stats) {
77125ee8613SDaniel Sanders Stats->NumDbgLocsExpected += OriginalNumLines;
77225ee8613SDaniel Sanders Stats->NumDbgLocsMissing += MissingLines.count();
77325ee8613SDaniel Sanders Stats->NumDbgValuesExpected += OriginalNumVars;
77425ee8613SDaniel Sanders Stats->NumDbgValuesMissing += MissingVars.count();
77525ee8613SDaniel Sanders }
77625ee8613SDaniel Sanders
77725ee8613SDaniel Sanders dbg() << Banner;
77825ee8613SDaniel Sanders if (!NameOfWrappedPass.empty())
77925ee8613SDaniel Sanders dbg() << " [" << NameOfWrappedPass << "]";
78025ee8613SDaniel Sanders dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
78125ee8613SDaniel Sanders
782122a6bfbSVedant Kumar // Strip debugify metadata if required.
783122a6bfbSVedant Kumar if (Strip)
784122a6bfbSVedant Kumar return stripDebugifyMetadata(M);
78525ee8613SDaniel Sanders
78625ee8613SDaniel Sanders return false;
78725ee8613SDaniel Sanders }
78825ee8613SDaniel Sanders
78925ee8613SDaniel Sanders /// ModulePass for attaching synthetic debug info to everything, used with the
79025ee8613SDaniel Sanders /// legacy module pass manager.
79125ee8613SDaniel Sanders struct DebugifyModulePass : public ModulePass {
runOnModule__anonda48fbad0511::DebugifyModulePass7928ee7c7e0SDjordje Todorovic bool runOnModule(Module &M) override {
79373777b4cSDjordje Todorovic return applyDebugify(M, Mode, DebugInfoBeforePass, NameOfWrappedPass);
7948ee7c7e0SDjordje Todorovic }
7958ee7c7e0SDjordje Todorovic
DebugifyModulePass__anonda48fbad0511::DebugifyModulePass7961a2b3536SDjordje Todorovic DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
7971a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "",
79873777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr)
7991a2b3536SDjordje Todorovic : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
80073777b4cSDjordje Todorovic DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
8018ee7c7e0SDjordje Todorovic
getAnalysisUsage__anonda48fbad0511::DebugifyModulePass8028ee7c7e0SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override {
8038ee7c7e0SDjordje Todorovic AU.setPreservesAll();
8048ee7c7e0SDjordje Todorovic }
8058ee7c7e0SDjordje Todorovic
8068ee7c7e0SDjordje Todorovic static char ID; // Pass identification.
8078ee7c7e0SDjordje Todorovic
8088ee7c7e0SDjordje Todorovic private:
8091a2b3536SDjordje Todorovic StringRef NameOfWrappedPass;
81073777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass;
8111a2b3536SDjordje Todorovic enum DebugifyMode Mode;
8121a2b3536SDjordje Todorovic };
8131a2b3536SDjordje Todorovic
8141a2b3536SDjordje Todorovic /// FunctionPass for attaching synthetic debug info to instructions within a
8151a2b3536SDjordje Todorovic /// single function, used with the legacy module pass manager.
8161a2b3536SDjordje Todorovic struct DebugifyFunctionPass : public FunctionPass {
runOnFunction__anonda48fbad0511::DebugifyFunctionPass8171a2b3536SDjordje Todorovic bool runOnFunction(Function &F) override {
81873777b4cSDjordje Todorovic return applyDebugify(F, Mode, DebugInfoBeforePass, NameOfWrappedPass);
8191a2b3536SDjordje Todorovic }
8201a2b3536SDjordje Todorovic
DebugifyFunctionPass__anonda48fbad0511::DebugifyFunctionPass8211a2b3536SDjordje Todorovic DebugifyFunctionPass(
8221a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
8231a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "",
82473777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr)
8251a2b3536SDjordje Todorovic : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
82673777b4cSDjordje Todorovic DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
8271a2b3536SDjordje Todorovic
getAnalysisUsage__anonda48fbad0511::DebugifyFunctionPass8281a2b3536SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override {
8291a2b3536SDjordje Todorovic AU.setPreservesAll();
8301a2b3536SDjordje Todorovic }
8311a2b3536SDjordje Todorovic
8321a2b3536SDjordje Todorovic static char ID; // Pass identification.
8331a2b3536SDjordje Todorovic
8341a2b3536SDjordje Todorovic private:
8351a2b3536SDjordje Todorovic StringRef NameOfWrappedPass;
83673777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass;
8371a2b3536SDjordje Todorovic enum DebugifyMode Mode;
8381a2b3536SDjordje Todorovic };
8391a2b3536SDjordje Todorovic
8401a2b3536SDjordje Todorovic /// ModulePass for checking debug info inserted by -debugify, used with the
8411a2b3536SDjordje Todorovic /// legacy module pass manager.
8421a2b3536SDjordje Todorovic struct CheckDebugifyModulePass : public ModulePass {
runOnModule__anonda48fbad0511::CheckDebugifyModulePass8431a2b3536SDjordje Todorovic bool runOnModule(Module &M) override {
8441a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
8451a2b3536SDjordje Todorovic return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
8461a2b3536SDjordje Todorovic "CheckModuleDebugify", Strip, StatsMap);
8471a2b3536SDjordje Todorovic return checkDebugInfoMetadata(
84873777b4cSDjordje Todorovic M, M.functions(), *DebugInfoBeforePass,
8499f41c03fSDjordje Todorovic "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
8509f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath);
8511a2b3536SDjordje Todorovic }
8521a2b3536SDjordje Todorovic
CheckDebugifyModulePass__anonda48fbad0511::CheckDebugifyModulePass8531a2b3536SDjordje Todorovic CheckDebugifyModulePass(
8541a2b3536SDjordje Todorovic bool Strip = false, StringRef NameOfWrappedPass = "",
8551a2b3536SDjordje Todorovic DebugifyStatsMap *StatsMap = nullptr,
8561a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
85773777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr,
8589f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath = "")
8591a2b3536SDjordje Todorovic : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
8609f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
86173777b4cSDjordje Todorovic StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
8621a2b3536SDjordje Todorovic Strip(Strip) {}
8631a2b3536SDjordje Todorovic
getAnalysisUsage__anonda48fbad0511::CheckDebugifyModulePass8641a2b3536SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override {
8651a2b3536SDjordje Todorovic AU.setPreservesAll();
8661a2b3536SDjordje Todorovic }
8671a2b3536SDjordje Todorovic
8681a2b3536SDjordje Todorovic static char ID; // Pass identification.
8691a2b3536SDjordje Todorovic
8701a2b3536SDjordje Todorovic private:
87125ee8613SDaniel Sanders StringRef NameOfWrappedPass;
8729f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath;
87325ee8613SDaniel Sanders DebugifyStatsMap *StatsMap;
87473777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass;
8751a2b3536SDjordje Todorovic enum DebugifyMode Mode;
8761a2b3536SDjordje Todorovic bool Strip;
87725ee8613SDaniel Sanders };
87825ee8613SDaniel Sanders
87925ee8613SDaniel Sanders /// FunctionPass for checking debug info inserted by -debugify-function, used
88025ee8613SDaniel Sanders /// with the legacy module pass manager.
88125ee8613SDaniel Sanders struct CheckDebugifyFunctionPass : public FunctionPass {
runOnFunction__anonda48fbad0511::CheckDebugifyFunctionPass88225ee8613SDaniel Sanders bool runOnFunction(Function &F) override {
88325ee8613SDaniel Sanders Module &M = *F.getParent();
88425ee8613SDaniel Sanders auto FuncIt = F.getIterator();
8851a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
88625ee8613SDaniel Sanders return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
88725ee8613SDaniel Sanders NameOfWrappedPass, "CheckFunctionDebugify",
88825ee8613SDaniel Sanders Strip, StatsMap);
8891a2b3536SDjordje Todorovic return checkDebugInfoMetadata(
89073777b4cSDjordje Todorovic M, make_range(FuncIt, std::next(FuncIt)), *DebugInfoBeforePass,
8919f41c03fSDjordje Todorovic "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass,
8929f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath);
89325ee8613SDaniel Sanders }
89425ee8613SDaniel Sanders
CheckDebugifyFunctionPass__anonda48fbad0511::CheckDebugifyFunctionPass8951a2b3536SDjordje Todorovic CheckDebugifyFunctionPass(
8961a2b3536SDjordje Todorovic bool Strip = false, StringRef NameOfWrappedPass = "",
8971a2b3536SDjordje Todorovic DebugifyStatsMap *StatsMap = nullptr,
8981a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
89973777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass = nullptr,
9009f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath = "")
9011a2b3536SDjordje Todorovic : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
9029f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
90373777b4cSDjordje Todorovic StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
9041a2b3536SDjordje Todorovic Strip(Strip) {}
90525ee8613SDaniel Sanders
getAnalysisUsage__anonda48fbad0511::CheckDebugifyFunctionPass90625ee8613SDaniel Sanders void getAnalysisUsage(AnalysisUsage &AU) const override {
90725ee8613SDaniel Sanders AU.setPreservesAll();
90825ee8613SDaniel Sanders }
90925ee8613SDaniel Sanders
91025ee8613SDaniel Sanders static char ID; // Pass identification.
91125ee8613SDaniel Sanders
91225ee8613SDaniel Sanders private:
91325ee8613SDaniel Sanders StringRef NameOfWrappedPass;
9149f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath;
91525ee8613SDaniel Sanders DebugifyStatsMap *StatsMap;
91673777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass;
9171a2b3536SDjordje Todorovic enum DebugifyMode Mode;
9181a2b3536SDjordje Todorovic bool Strip;
91925ee8613SDaniel Sanders };
92025ee8613SDaniel Sanders
92125ee8613SDaniel Sanders } // end anonymous namespace
92225ee8613SDaniel Sanders
exportDebugifyStats(StringRef Path,const DebugifyStatsMap & Map)92339856d5dSFangrui Song void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) {
92439856d5dSFangrui Song std::error_code EC;
92539856d5dSFangrui Song raw_fd_ostream OS{Path, EC};
92639856d5dSFangrui Song if (EC) {
92739856d5dSFangrui Song errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
92839856d5dSFangrui Song return;
92939856d5dSFangrui Song }
93025ee8613SDaniel Sanders
93139856d5dSFangrui Song OS << "Pass Name" << ',' << "# of missing debug values" << ','
93239856d5dSFangrui Song << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
93339856d5dSFangrui Song << "Missing/Expected location ratio" << '\n';
93439856d5dSFangrui Song for (const auto &Entry : Map) {
93539856d5dSFangrui Song StringRef Pass = Entry.first;
93639856d5dSFangrui Song DebugifyStatistics Stats = Entry.second;
93739856d5dSFangrui Song
93839856d5dSFangrui Song OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
93939856d5dSFangrui Song << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
94039856d5dSFangrui Song << Stats.getEmptyLocationRatio() << '\n';
94139856d5dSFangrui Song }
94239856d5dSFangrui Song }
94339856d5dSFangrui Song
createDebugifyModulePass(enum DebugifyMode Mode,llvm::StringRef NameOfWrappedPass,DebugInfoPerPass * DebugInfoBeforePass)9441a2b3536SDjordje Todorovic ModulePass *createDebugifyModulePass(enum DebugifyMode Mode,
9451a2b3536SDjordje Todorovic llvm::StringRef NameOfWrappedPass,
94673777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass) {
9471a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
94839856d5dSFangrui Song return new DebugifyModulePass();
9491a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
95073777b4cSDjordje Todorovic return new DebugifyModulePass(Mode, NameOfWrappedPass, DebugInfoBeforePass);
95139856d5dSFangrui Song }
95239856d5dSFangrui Song
9531a2b3536SDjordje Todorovic FunctionPass *
createDebugifyFunctionPass(enum DebugifyMode Mode,llvm::StringRef NameOfWrappedPass,DebugInfoPerPass * DebugInfoBeforePass)9541a2b3536SDjordje Todorovic createDebugifyFunctionPass(enum DebugifyMode Mode,
9551a2b3536SDjordje Todorovic llvm::StringRef NameOfWrappedPass,
95673777b4cSDjordje Todorovic DebugInfoPerPass *DebugInfoBeforePass) {
9571a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
95825ee8613SDaniel Sanders return new DebugifyFunctionPass();
9591a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
96073777b4cSDjordje Todorovic return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DebugInfoBeforePass);
96125ee8613SDaniel Sanders }
96225ee8613SDaniel Sanders
run(Module & M,ModuleAnalysisManager &)96325ee8613SDaniel Sanders PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
964*b5b6d3a4SNikola Tesic if (Mode == DebugifyMode::SyntheticDebugInfo)
9651adeeabbSDaniel Sanders applyDebugifyMetadata(M, M.functions(),
9661adeeabbSDaniel Sanders "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
967*b5b6d3a4SNikola Tesic else
968*b5b6d3a4SNikola Tesic collectDebugInfoMetadata(M, M.functions(), *DebugInfoBeforePass,
969*b5b6d3a4SNikola Tesic "ModuleDebugify (original debuginfo)",
970*b5b6d3a4SNikola Tesic NameOfWrappedPass);
97125ee8613SDaniel Sanders return PreservedAnalyses::all();
97225ee8613SDaniel Sanders }
97325ee8613SDaniel Sanders
createCheckDebugifyModulePass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap,enum DebugifyMode Mode,DebugInfoPerPass * DebugInfoBeforePass,StringRef OrigDIVerifyBugsReportFilePath)9741a2b3536SDjordje Todorovic ModulePass *createCheckDebugifyModulePass(
9751a2b3536SDjordje Todorovic bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
97673777b4cSDjordje Todorovic enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass,
9779f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) {
9781a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
97925ee8613SDaniel Sanders return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
9801a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
9811a2b3536SDjordje Todorovic return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,
98273777b4cSDjordje Todorovic DebugInfoBeforePass,
9839f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath);
98425ee8613SDaniel Sanders }
98525ee8613SDaniel Sanders
createCheckDebugifyFunctionPass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap,enum DebugifyMode Mode,DebugInfoPerPass * DebugInfoBeforePass,StringRef OrigDIVerifyBugsReportFilePath)9861a2b3536SDjordje Todorovic FunctionPass *createCheckDebugifyFunctionPass(
9871a2b3536SDjordje Todorovic bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
98873777b4cSDjordje Todorovic enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass,
9899f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) {
9901a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo)
99125ee8613SDaniel Sanders return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
9921a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
9931a2b3536SDjordje Todorovic return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,
99473777b4cSDjordje Todorovic DebugInfoBeforePass,
9959f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath);
99625ee8613SDaniel Sanders }
99725ee8613SDaniel Sanders
run(Module & M,ModuleAnalysisManager &)99825ee8613SDaniel Sanders PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
99925ee8613SDaniel Sanders ModuleAnalysisManager &) {
1000*b5b6d3a4SNikola Tesic if (Mode == DebugifyMode::SyntheticDebugInfo)
1001*b5b6d3a4SNikola Tesic checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
1002*b5b6d3a4SNikola Tesic "CheckModuleDebugify", Strip, StatsMap);
1003*b5b6d3a4SNikola Tesic else
1004*b5b6d3a4SNikola Tesic checkDebugInfoMetadata(
1005*b5b6d3a4SNikola Tesic M, M.functions(), *DebugInfoBeforePass,
1006*b5b6d3a4SNikola Tesic "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
1007*b5b6d3a4SNikola Tesic OrigDIVerifyBugsReportFilePath);
100825ee8613SDaniel Sanders return PreservedAnalyses::all();
100925ee8613SDaniel Sanders }
101025ee8613SDaniel Sanders
isIgnoredPass(StringRef PassID)10117de6dcd2SArthur Eubanks static bool isIgnoredPass(StringRef PassID) {
10127de6dcd2SArthur Eubanks return isSpecialPass(PassID, {"PassManager", "PassAdaptor",
10137de6dcd2SArthur Eubanks "AnalysisManagerProxy", "PrintFunctionPass",
10147de6dcd2SArthur Eubanks "PrintModulePass", "BitcodeWriterPass",
10157de6dcd2SArthur Eubanks "ThinLTOBitcodeWriterPass", "VerifierPass"});
10167de6dcd2SArthur Eubanks }
10177de6dcd2SArthur Eubanks
registerCallbacks(PassInstrumentationCallbacks & PIC)101898b93385SFangrui Song void DebugifyEachInstrumentation::registerCallbacks(
101998b93385SFangrui Song PassInstrumentationCallbacks &PIC) {
1020*b5b6d3a4SNikola Tesic PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) {
10217de6dcd2SArthur Eubanks if (isIgnoredPass(P))
10227de6dcd2SArthur Eubanks return;
102398b93385SFangrui Song if (any_isa<const Function *>(IR))
1024*b5b6d3a4SNikola Tesic applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR)),
1025*b5b6d3a4SNikola Tesic Mode, DebugInfoBeforePass, P);
102698b93385SFangrui Song else if (any_isa<const Module *>(IR))
1027*b5b6d3a4SNikola Tesic applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR)),
1028*b5b6d3a4SNikola Tesic Mode, DebugInfoBeforePass, P);
102998b93385SFangrui Song });
103098b93385SFangrui Song PIC.registerAfterPassCallback([this](StringRef P, Any IR,
103198b93385SFangrui Song const PreservedAnalyses &PassPA) {
10327de6dcd2SArthur Eubanks if (isIgnoredPass(P))
10337de6dcd2SArthur Eubanks return;
103498b93385SFangrui Song if (any_isa<const Function *>(IR)) {
103598b93385SFangrui Song auto &F = *const_cast<Function *>(any_cast<const Function *>(IR));
103698b93385SFangrui Song Module &M = *F.getParent();
103798b93385SFangrui Song auto It = F.getIterator();
1038*b5b6d3a4SNikola Tesic if (Mode == DebugifyMode::SyntheticDebugInfo)
103998b93385SFangrui Song checkDebugifyMetadata(M, make_range(It, std::next(It)), P,
1040*b5b6d3a4SNikola Tesic "CheckFunctionDebugify", /*Strip=*/true, DIStatsMap);
1041*b5b6d3a4SNikola Tesic else
1042*b5b6d3a4SNikola Tesic checkDebugInfoMetadata(
1043*b5b6d3a4SNikola Tesic M, make_range(It, std::next(It)), *DebugInfoBeforePass,
1044*b5b6d3a4SNikola Tesic "CheckModuleDebugify (original debuginfo)",
1045*b5b6d3a4SNikola Tesic P, OrigDIVerifyBugsReportFilePath);
104698b93385SFangrui Song } else if (any_isa<const Module *>(IR)) {
104798b93385SFangrui Song auto &M = *const_cast<Module *>(any_cast<const Module *>(IR));
1048*b5b6d3a4SNikola Tesic if (Mode == DebugifyMode::SyntheticDebugInfo)
104998b93385SFangrui Song checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify",
1050*b5b6d3a4SNikola Tesic /*Strip=*/true, DIStatsMap);
1051*b5b6d3a4SNikola Tesic else
1052*b5b6d3a4SNikola Tesic checkDebugInfoMetadata(
1053*b5b6d3a4SNikola Tesic M, M.functions(), *DebugInfoBeforePass,
1054*b5b6d3a4SNikola Tesic "CheckModuleDebugify (original debuginfo)",
1055*b5b6d3a4SNikola Tesic P, OrigDIVerifyBugsReportFilePath);
105698b93385SFangrui Song }
105798b93385SFangrui Song });
105898b93385SFangrui Song }
105998b93385SFangrui Song
106025ee8613SDaniel Sanders char DebugifyModulePass::ID = 0;
106125ee8613SDaniel Sanders static RegisterPass<DebugifyModulePass> DM("debugify",
106225ee8613SDaniel Sanders "Attach debug info to everything");
106325ee8613SDaniel Sanders
106425ee8613SDaniel Sanders char CheckDebugifyModulePass::ID = 0;
106525ee8613SDaniel Sanders static RegisterPass<CheckDebugifyModulePass>
106625ee8613SDaniel Sanders CDM("check-debugify", "Check debug info from -debugify");
106725ee8613SDaniel Sanders
106825ee8613SDaniel Sanders char DebugifyFunctionPass::ID = 0;
106925ee8613SDaniel Sanders static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
107025ee8613SDaniel Sanders "Attach debug info to a function");
107125ee8613SDaniel Sanders
107225ee8613SDaniel Sanders char CheckDebugifyFunctionPass::ID = 0;
107325ee8613SDaniel Sanders static RegisterPass<CheckDebugifyFunctionPass>
107425ee8613SDaniel Sanders CDF("check-debugify-function", "Check debug info from -debugify-function");
1075