1*82d56013Sjoerg //===- Debugify.cpp - Check debug info preservation in optimizations ------===//
2*82d56013Sjoerg //
3*82d56013Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*82d56013Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*82d56013Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*82d56013Sjoerg //
7*82d56013Sjoerg //===----------------------------------------------------------------------===//
8*82d56013Sjoerg ///
9*82d56013Sjoerg /// \file In the `synthetic` mode, the `-debugify` attaches synthetic debug info
10*82d56013Sjoerg /// to everything. It can be used to create targeted tests for debug info
11*82d56013Sjoerg /// preservation. In addition, when using the `original` mode, it can check
12*82d56013Sjoerg /// original debug info preservation. The `synthetic` mode is default one.
13*82d56013Sjoerg ///
14*82d56013Sjoerg //===----------------------------------------------------------------------===//
15*82d56013Sjoerg
16*82d56013Sjoerg #include "llvm/Transforms/Utils/Debugify.h"
17*82d56013Sjoerg #include "llvm/ADT/BitVector.h"
18*82d56013Sjoerg #include "llvm/ADT/StringExtras.h"
19*82d56013Sjoerg #include "llvm/IR/DIBuilder.h"
20*82d56013Sjoerg #include "llvm/IR/DebugInfo.h"
21*82d56013Sjoerg #include "llvm/IR/InstIterator.h"
22*82d56013Sjoerg #include "llvm/IR/Instructions.h"
23*82d56013Sjoerg #include "llvm/IR/IntrinsicInst.h"
24*82d56013Sjoerg #include "llvm/IR/Module.h"
25*82d56013Sjoerg #include "llvm/IR/PassInstrumentation.h"
26*82d56013Sjoerg #include "llvm/Pass.h"
27*82d56013Sjoerg #include "llvm/Support/CommandLine.h"
28*82d56013Sjoerg #include "llvm/Support/FileSystem.h"
29*82d56013Sjoerg #include "llvm/Support/JSON.h"
30*82d56013Sjoerg
31*82d56013Sjoerg #define DEBUG_TYPE "debugify"
32*82d56013Sjoerg
33*82d56013Sjoerg using namespace llvm;
34*82d56013Sjoerg
35*82d56013Sjoerg namespace {
36*82d56013Sjoerg
37*82d56013Sjoerg cl::opt<bool> Quiet("debugify-quiet",
38*82d56013Sjoerg cl::desc("Suppress verbose debugify output"));
39*82d56013Sjoerg
40*82d56013Sjoerg enum class Level {
41*82d56013Sjoerg Locations,
42*82d56013Sjoerg LocationsAndVariables
43*82d56013Sjoerg };
44*82d56013Sjoerg
45*82d56013Sjoerg // Used for the synthetic mode only.
46*82d56013Sjoerg cl::opt<Level> DebugifyLevel(
47*82d56013Sjoerg "debugify-level", cl::desc("Kind of debug info to add"),
48*82d56013Sjoerg cl::values(clEnumValN(Level::Locations, "locations", "Locations only"),
49*82d56013Sjoerg clEnumValN(Level::LocationsAndVariables, "location+variables",
50*82d56013Sjoerg "Locations and Variables")),
51*82d56013Sjoerg cl::init(Level::LocationsAndVariables));
52*82d56013Sjoerg
dbg()53*82d56013Sjoerg raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
54*82d56013Sjoerg
getAllocSizeInBits(Module & M,Type * Ty)55*82d56013Sjoerg uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
56*82d56013Sjoerg return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
57*82d56013Sjoerg }
58*82d56013Sjoerg
isFunctionSkipped(Function & F)59*82d56013Sjoerg bool isFunctionSkipped(Function &F) {
60*82d56013Sjoerg return F.isDeclaration() || !F.hasExactDefinition();
61*82d56013Sjoerg }
62*82d56013Sjoerg
63*82d56013Sjoerg /// Find the basic block's terminating instruction.
64*82d56013Sjoerg ///
65*82d56013Sjoerg /// Special care is needed to handle musttail and deopt calls, as these behave
66*82d56013Sjoerg /// like (but are in fact not) terminators.
findTerminatingInstruction(BasicBlock & BB)67*82d56013Sjoerg Instruction *findTerminatingInstruction(BasicBlock &BB) {
68*82d56013Sjoerg if (auto *I = BB.getTerminatingMustTailCall())
69*82d56013Sjoerg return I;
70*82d56013Sjoerg if (auto *I = BB.getTerminatingDeoptimizeCall())
71*82d56013Sjoerg return I;
72*82d56013Sjoerg return BB.getTerminator();
73*82d56013Sjoerg }
74*82d56013Sjoerg } // end anonymous namespace
75*82d56013Sjoerg
applyDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef Banner,std::function<bool (DIBuilder & DIB,Function & F)> ApplyToMF)76*82d56013Sjoerg bool llvm::applyDebugifyMetadata(
77*82d56013Sjoerg Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
78*82d56013Sjoerg std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) {
79*82d56013Sjoerg // Skip modules with debug info.
80*82d56013Sjoerg if (M.getNamedMetadata("llvm.dbg.cu")) {
81*82d56013Sjoerg dbg() << Banner << "Skipping module with debug info\n";
82*82d56013Sjoerg return false;
83*82d56013Sjoerg }
84*82d56013Sjoerg
85*82d56013Sjoerg DIBuilder DIB(M);
86*82d56013Sjoerg LLVMContext &Ctx = M.getContext();
87*82d56013Sjoerg auto *Int32Ty = Type::getInt32Ty(Ctx);
88*82d56013Sjoerg
89*82d56013Sjoerg // Get a DIType which corresponds to Ty.
90*82d56013Sjoerg DenseMap<uint64_t, DIType *> TypeCache;
91*82d56013Sjoerg auto getCachedDIType = [&](Type *Ty) -> DIType * {
92*82d56013Sjoerg uint64_t Size = getAllocSizeInBits(M, Ty);
93*82d56013Sjoerg DIType *&DTy = TypeCache[Size];
94*82d56013Sjoerg if (!DTy) {
95*82d56013Sjoerg std::string Name = "ty" + utostr(Size);
96*82d56013Sjoerg DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
97*82d56013Sjoerg }
98*82d56013Sjoerg return DTy;
99*82d56013Sjoerg };
100*82d56013Sjoerg
101*82d56013Sjoerg unsigned NextLine = 1;
102*82d56013Sjoerg unsigned NextVar = 1;
103*82d56013Sjoerg auto File = DIB.createFile(M.getName(), "/");
104*82d56013Sjoerg auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify",
105*82d56013Sjoerg /*isOptimized=*/true, "", 0);
106*82d56013Sjoerg
107*82d56013Sjoerg // Visit each instruction.
108*82d56013Sjoerg for (Function &F : Functions) {
109*82d56013Sjoerg if (isFunctionSkipped(F))
110*82d56013Sjoerg continue;
111*82d56013Sjoerg
112*82d56013Sjoerg bool InsertedDbgVal = false;
113*82d56013Sjoerg auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
114*82d56013Sjoerg DISubprogram::DISPFlags SPFlags =
115*82d56013Sjoerg DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;
116*82d56013Sjoerg if (F.hasPrivateLinkage() || F.hasInternalLinkage())
117*82d56013Sjoerg SPFlags |= DISubprogram::SPFlagLocalToUnit;
118*82d56013Sjoerg auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,
119*82d56013Sjoerg SPType, NextLine, DINode::FlagZero, SPFlags);
120*82d56013Sjoerg F.setSubprogram(SP);
121*82d56013Sjoerg
122*82d56013Sjoerg // Helper that inserts a dbg.value before \p InsertBefore, copying the
123*82d56013Sjoerg // location (and possibly the type, if it's non-void) from \p TemplateInst.
124*82d56013Sjoerg auto insertDbgVal = [&](Instruction &TemplateInst,
125*82d56013Sjoerg Instruction *InsertBefore) {
126*82d56013Sjoerg std::string Name = utostr(NextVar++);
127*82d56013Sjoerg Value *V = &TemplateInst;
128*82d56013Sjoerg if (TemplateInst.getType()->isVoidTy())
129*82d56013Sjoerg V = ConstantInt::get(Int32Ty, 0);
130*82d56013Sjoerg const DILocation *Loc = TemplateInst.getDebugLoc().get();
131*82d56013Sjoerg auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
132*82d56013Sjoerg getCachedDIType(V->getType()),
133*82d56013Sjoerg /*AlwaysPreserve=*/true);
134*82d56013Sjoerg DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc,
135*82d56013Sjoerg InsertBefore);
136*82d56013Sjoerg };
137*82d56013Sjoerg
138*82d56013Sjoerg for (BasicBlock &BB : F) {
139*82d56013Sjoerg // Attach debug locations.
140*82d56013Sjoerg for (Instruction &I : BB)
141*82d56013Sjoerg I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
142*82d56013Sjoerg
143*82d56013Sjoerg if (DebugifyLevel < Level::LocationsAndVariables)
144*82d56013Sjoerg continue;
145*82d56013Sjoerg
146*82d56013Sjoerg // Inserting debug values into EH pads can break IR invariants.
147*82d56013Sjoerg if (BB.isEHPad())
148*82d56013Sjoerg continue;
149*82d56013Sjoerg
150*82d56013Sjoerg // Find the terminating instruction, after which no debug values are
151*82d56013Sjoerg // attached.
152*82d56013Sjoerg Instruction *LastInst = findTerminatingInstruction(BB);
153*82d56013Sjoerg assert(LastInst && "Expected basic block with a terminator");
154*82d56013Sjoerg
155*82d56013Sjoerg // Maintain an insertion point which can't be invalidated when updates
156*82d56013Sjoerg // are made.
157*82d56013Sjoerg BasicBlock::iterator InsertPt = BB.getFirstInsertionPt();
158*82d56013Sjoerg assert(InsertPt != BB.end() && "Expected to find an insertion point");
159*82d56013Sjoerg Instruction *InsertBefore = &*InsertPt;
160*82d56013Sjoerg
161*82d56013Sjoerg // Attach debug values.
162*82d56013Sjoerg for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {
163*82d56013Sjoerg // Skip void-valued instructions.
164*82d56013Sjoerg if (I->getType()->isVoidTy())
165*82d56013Sjoerg continue;
166*82d56013Sjoerg
167*82d56013Sjoerg // Phis and EH pads must be grouped at the beginning of the block.
168*82d56013Sjoerg // Only advance the insertion point when we finish visiting these.
169*82d56013Sjoerg if (!isa<PHINode>(I) && !I->isEHPad())
170*82d56013Sjoerg InsertBefore = I->getNextNode();
171*82d56013Sjoerg
172*82d56013Sjoerg insertDbgVal(*I, InsertBefore);
173*82d56013Sjoerg InsertedDbgVal = true;
174*82d56013Sjoerg }
175*82d56013Sjoerg }
176*82d56013Sjoerg // Make sure we emit at least one dbg.value, otherwise MachineDebugify may
177*82d56013Sjoerg // not have anything to work with as it goes about inserting DBG_VALUEs.
178*82d56013Sjoerg // (It's common for MIR tests to be written containing skeletal IR with
179*82d56013Sjoerg // empty functions -- we're still interested in debugifying the MIR within
180*82d56013Sjoerg // those tests, and this helps with that.)
181*82d56013Sjoerg if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) {
182*82d56013Sjoerg auto *Term = findTerminatingInstruction(F.getEntryBlock());
183*82d56013Sjoerg insertDbgVal(*Term, Term);
184*82d56013Sjoerg }
185*82d56013Sjoerg if (ApplyToMF)
186*82d56013Sjoerg ApplyToMF(DIB, F);
187*82d56013Sjoerg DIB.finalizeSubprogram(SP);
188*82d56013Sjoerg }
189*82d56013Sjoerg DIB.finalize();
190*82d56013Sjoerg
191*82d56013Sjoerg // Track the number of distinct lines and variables.
192*82d56013Sjoerg NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
193*82d56013Sjoerg auto addDebugifyOperand = [&](unsigned N) {
194*82d56013Sjoerg NMD->addOperand(MDNode::get(
195*82d56013Sjoerg Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N))));
196*82d56013Sjoerg };
197*82d56013Sjoerg addDebugifyOperand(NextLine - 1); // Original number of lines.
198*82d56013Sjoerg addDebugifyOperand(NextVar - 1); // Original number of variables.
199*82d56013Sjoerg assert(NMD->getNumOperands() == 2 &&
200*82d56013Sjoerg "llvm.debugify should have exactly 2 operands!");
201*82d56013Sjoerg
202*82d56013Sjoerg // Claim that this synthetic debug info is valid.
203*82d56013Sjoerg StringRef DIVersionKey = "Debug Info Version";
204*82d56013Sjoerg if (!M.getModuleFlag(DIVersionKey))
205*82d56013Sjoerg M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION);
206*82d56013Sjoerg
207*82d56013Sjoerg return true;
208*82d56013Sjoerg }
209*82d56013Sjoerg
210*82d56013Sjoerg static bool
applyDebugify(Function & F,enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo,DebugInfoPerPassMap * DIPreservationMap=nullptr,StringRef NameOfWrappedPass="")211*82d56013Sjoerg applyDebugify(Function &F,
212*82d56013Sjoerg enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
213*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr,
214*82d56013Sjoerg StringRef NameOfWrappedPass = "") {
215*82d56013Sjoerg Module &M = *F.getParent();
216*82d56013Sjoerg auto FuncIt = F.getIterator();
217*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
218*82d56013Sjoerg return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
219*82d56013Sjoerg "FunctionDebugify: ", /*ApplyToMF*/ nullptr);
220*82d56013Sjoerg assert(DIPreservationMap);
221*82d56013Sjoerg return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
222*82d56013Sjoerg "FunctionDebugify (original debuginfo)",
223*82d56013Sjoerg NameOfWrappedPass);
224*82d56013Sjoerg }
225*82d56013Sjoerg
226*82d56013Sjoerg static bool
applyDebugify(Module & M,enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo,DebugInfoPerPassMap * DIPreservationMap=nullptr,StringRef NameOfWrappedPass="")227*82d56013Sjoerg applyDebugify(Module &M,
228*82d56013Sjoerg enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
229*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr,
230*82d56013Sjoerg StringRef NameOfWrappedPass = "") {
231*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
232*82d56013Sjoerg return applyDebugifyMetadata(M, M.functions(),
233*82d56013Sjoerg "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
234*82d56013Sjoerg return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap,
235*82d56013Sjoerg "ModuleDebugify (original debuginfo)",
236*82d56013Sjoerg NameOfWrappedPass);
237*82d56013Sjoerg }
238*82d56013Sjoerg
stripDebugifyMetadata(Module & M)239*82d56013Sjoerg bool llvm::stripDebugifyMetadata(Module &M) {
240*82d56013Sjoerg bool Changed = false;
241*82d56013Sjoerg
242*82d56013Sjoerg // Remove the llvm.debugify module-level named metadata.
243*82d56013Sjoerg NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify");
244*82d56013Sjoerg if (DebugifyMD) {
245*82d56013Sjoerg M.eraseNamedMetadata(DebugifyMD);
246*82d56013Sjoerg Changed = true;
247*82d56013Sjoerg }
248*82d56013Sjoerg
249*82d56013Sjoerg // Strip out all debug intrinsics and supporting metadata (subprograms, types,
250*82d56013Sjoerg // variables, etc).
251*82d56013Sjoerg Changed |= StripDebugInfo(M);
252*82d56013Sjoerg
253*82d56013Sjoerg // Strip out the dead dbg.value prototype.
254*82d56013Sjoerg Function *DbgValF = M.getFunction("llvm.dbg.value");
255*82d56013Sjoerg if (DbgValF) {
256*82d56013Sjoerg assert(DbgValF->isDeclaration() && DbgValF->use_empty() &&
257*82d56013Sjoerg "Not all debug info stripped?");
258*82d56013Sjoerg DbgValF->eraseFromParent();
259*82d56013Sjoerg Changed = true;
260*82d56013Sjoerg }
261*82d56013Sjoerg
262*82d56013Sjoerg // Strip out the module-level Debug Info Version metadata.
263*82d56013Sjoerg // FIXME: There must be an easier way to remove an operand from a NamedMDNode.
264*82d56013Sjoerg NamedMDNode *NMD = M.getModuleFlagsMetadata();
265*82d56013Sjoerg if (!NMD)
266*82d56013Sjoerg return Changed;
267*82d56013Sjoerg SmallVector<MDNode *, 4> Flags(NMD->operands());
268*82d56013Sjoerg NMD->clearOperands();
269*82d56013Sjoerg for (MDNode *Flag : Flags) {
270*82d56013Sjoerg MDString *Key = dyn_cast_or_null<MDString>(Flag->getOperand(1));
271*82d56013Sjoerg if (Key->getString() == "Debug Info Version") {
272*82d56013Sjoerg Changed = true;
273*82d56013Sjoerg continue;
274*82d56013Sjoerg }
275*82d56013Sjoerg NMD->addOperand(Flag);
276*82d56013Sjoerg }
277*82d56013Sjoerg // If we left it empty we might as well remove it.
278*82d56013Sjoerg if (NMD->getNumOperands() == 0)
279*82d56013Sjoerg NMD->eraseFromParent();
280*82d56013Sjoerg
281*82d56013Sjoerg return Changed;
282*82d56013Sjoerg }
283*82d56013Sjoerg
collectDebugInfoMetadata(Module & M,iterator_range<Module::iterator> Functions,DebugInfoPerPassMap & DIPreservationMap,StringRef Banner,StringRef NameOfWrappedPass)284*82d56013Sjoerg bool llvm::collectDebugInfoMetadata(Module &M,
285*82d56013Sjoerg iterator_range<Module::iterator> Functions,
286*82d56013Sjoerg DebugInfoPerPassMap &DIPreservationMap,
287*82d56013Sjoerg StringRef Banner,
288*82d56013Sjoerg StringRef NameOfWrappedPass) {
289*82d56013Sjoerg LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');
290*82d56013Sjoerg
291*82d56013Sjoerg // Clear the map with the debug info before every single pass.
292*82d56013Sjoerg DIPreservationMap.clear();
293*82d56013Sjoerg
294*82d56013Sjoerg if (!M.getNamedMetadata("llvm.dbg.cu")) {
295*82d56013Sjoerg dbg() << Banner << ": Skipping module without debug info\n";
296*82d56013Sjoerg return false;
297*82d56013Sjoerg }
298*82d56013Sjoerg
299*82d56013Sjoerg // Visit each instruction.
300*82d56013Sjoerg for (Function &F : Functions) {
301*82d56013Sjoerg if (isFunctionSkipped(F))
302*82d56013Sjoerg continue;
303*82d56013Sjoerg
304*82d56013Sjoerg // Collect the DISubprogram.
305*82d56013Sjoerg auto *SP = F.getSubprogram();
306*82d56013Sjoerg DIPreservationMap[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP});
307*82d56013Sjoerg if (SP) {
308*82d56013Sjoerg LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
309*82d56013Sjoerg for (const DINode *DN : SP->getRetainedNodes()) {
310*82d56013Sjoerg if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
311*82d56013Sjoerg DIPreservationMap[NameOfWrappedPass].DIVariables[DV] = 0;
312*82d56013Sjoerg }
313*82d56013Sjoerg }
314*82d56013Sjoerg }
315*82d56013Sjoerg
316*82d56013Sjoerg for (BasicBlock &BB : F) {
317*82d56013Sjoerg // Collect debug locations (!dbg) and debug variable intrinsics.
318*82d56013Sjoerg for (Instruction &I : BB) {
319*82d56013Sjoerg // Skip PHIs.
320*82d56013Sjoerg if (isa<PHINode>(I))
321*82d56013Sjoerg continue;
322*82d56013Sjoerg
323*82d56013Sjoerg // Collect dbg.values and dbg.declares.
324*82d56013Sjoerg if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) {
325*82d56013Sjoerg if (!SP)
326*82d56013Sjoerg continue;
327*82d56013Sjoerg // Skip inlined variables.
328*82d56013Sjoerg if (I.getDebugLoc().getInlinedAt())
329*82d56013Sjoerg continue;
330*82d56013Sjoerg // Skip undef values.
331*82d56013Sjoerg if (DVI->isUndef())
332*82d56013Sjoerg continue;
333*82d56013Sjoerg
334*82d56013Sjoerg auto *Var = DVI->getVariable();
335*82d56013Sjoerg DIPreservationMap[NameOfWrappedPass].DIVariables[Var]++;
336*82d56013Sjoerg continue;
337*82d56013Sjoerg }
338*82d56013Sjoerg
339*82d56013Sjoerg // Skip debug instructions other than dbg.value and dbg.declare.
340*82d56013Sjoerg if (isa<DbgInfoIntrinsic>(&I))
341*82d56013Sjoerg continue;
342*82d56013Sjoerg
343*82d56013Sjoerg LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
344*82d56013Sjoerg DIPreservationMap[NameOfWrappedPass].InstToDelete.insert({&I, &I});
345*82d56013Sjoerg
346*82d56013Sjoerg const DILocation *Loc = I.getDebugLoc().get();
347*82d56013Sjoerg bool HasLoc = Loc != nullptr;
348*82d56013Sjoerg DIPreservationMap[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
349*82d56013Sjoerg }
350*82d56013Sjoerg }
351*82d56013Sjoerg }
352*82d56013Sjoerg
353*82d56013Sjoerg return true;
354*82d56013Sjoerg }
355*82d56013Sjoerg
356*82d56013Sjoerg // 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)357*82d56013Sjoerg static bool checkFunctions(const DebugFnMap &DIFunctionsBefore,
358*82d56013Sjoerg const DebugFnMap &DIFunctionsAfter,
359*82d56013Sjoerg StringRef NameOfWrappedPass,
360*82d56013Sjoerg StringRef FileNameFromCU, bool ShouldWriteIntoJSON,
361*82d56013Sjoerg llvm::json::Array &Bugs) {
362*82d56013Sjoerg bool Preserved = true;
363*82d56013Sjoerg for (const auto &F : DIFunctionsAfter) {
364*82d56013Sjoerg if (F.second)
365*82d56013Sjoerg continue;
366*82d56013Sjoerg auto SPIt = DIFunctionsBefore.find(F.first);
367*82d56013Sjoerg if (SPIt == DIFunctionsBefore.end()) {
368*82d56013Sjoerg if (ShouldWriteIntoJSON)
369*82d56013Sjoerg Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
370*82d56013Sjoerg {"name", F.first},
371*82d56013Sjoerg {"action", "not-generate"}}));
372*82d56013Sjoerg else
373*82d56013Sjoerg dbg() << "ERROR: " << NameOfWrappedPass
374*82d56013Sjoerg << " did not generate DISubprogram for " << F.first << " from "
375*82d56013Sjoerg << FileNameFromCU << '\n';
376*82d56013Sjoerg Preserved = false;
377*82d56013Sjoerg } else {
378*82d56013Sjoerg auto SP = SPIt->second;
379*82d56013Sjoerg if (!SP)
380*82d56013Sjoerg continue;
381*82d56013Sjoerg // If the function had the SP attached before the pass, consider it as
382*82d56013Sjoerg // a debug info bug.
383*82d56013Sjoerg if (ShouldWriteIntoJSON)
384*82d56013Sjoerg Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"},
385*82d56013Sjoerg {"name", F.first},
386*82d56013Sjoerg {"action", "drop"}}));
387*82d56013Sjoerg else
388*82d56013Sjoerg dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "
389*82d56013Sjoerg << F.first << " from " << FileNameFromCU << '\n';
390*82d56013Sjoerg Preserved = false;
391*82d56013Sjoerg }
392*82d56013Sjoerg }
393*82d56013Sjoerg
394*82d56013Sjoerg return Preserved;
395*82d56013Sjoerg }
396*82d56013Sjoerg
397*82d56013Sjoerg // This checks the preservation of the original debug info attached to
398*82d56013Sjoerg // instructions.
checkInstructions(const DebugInstMap & DILocsBefore,const DebugInstMap & DILocsAfter,const WeakInstValueMap & InstToDelete,StringRef NameOfWrappedPass,StringRef FileNameFromCU,bool ShouldWriteIntoJSON,llvm::json::Array & Bugs)399*82d56013Sjoerg static bool checkInstructions(const DebugInstMap &DILocsBefore,
400*82d56013Sjoerg const DebugInstMap &DILocsAfter,
401*82d56013Sjoerg const WeakInstValueMap &InstToDelete,
402*82d56013Sjoerg StringRef NameOfWrappedPass,
403*82d56013Sjoerg StringRef FileNameFromCU,
404*82d56013Sjoerg bool ShouldWriteIntoJSON,
405*82d56013Sjoerg llvm::json::Array &Bugs) {
406*82d56013Sjoerg bool Preserved = true;
407*82d56013Sjoerg for (const auto &L : DILocsAfter) {
408*82d56013Sjoerg if (L.second)
409*82d56013Sjoerg continue;
410*82d56013Sjoerg auto Instr = L.first;
411*82d56013Sjoerg
412*82d56013Sjoerg // In order to avoid pointer reuse/recycling, skip the values that might
413*82d56013Sjoerg // have been deleted during a pass.
414*82d56013Sjoerg auto WeakInstrPtr = InstToDelete.find(Instr);
415*82d56013Sjoerg if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
416*82d56013Sjoerg continue;
417*82d56013Sjoerg
418*82d56013Sjoerg auto FnName = Instr->getFunction()->getName();
419*82d56013Sjoerg auto BB = Instr->getParent();
420*82d56013Sjoerg auto BBName = BB->hasName() ? BB->getName() : "no-name";
421*82d56013Sjoerg auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
422*82d56013Sjoerg
423*82d56013Sjoerg auto InstrIt = DILocsBefore.find(Instr);
424*82d56013Sjoerg if (InstrIt == DILocsBefore.end()) {
425*82d56013Sjoerg if (ShouldWriteIntoJSON)
426*82d56013Sjoerg Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
427*82d56013Sjoerg {"fn-name", FnName.str()},
428*82d56013Sjoerg {"bb-name", BBName.str()},
429*82d56013Sjoerg {"instr", InstName},
430*82d56013Sjoerg {"action", "not-generate"}}));
431*82d56013Sjoerg else
432*82d56013Sjoerg dbg() << "WARNING: " << NameOfWrappedPass
433*82d56013Sjoerg << " did not generate DILocation for " << *Instr
434*82d56013Sjoerg << " (BB: " << BBName << ", Fn: " << FnName
435*82d56013Sjoerg << ", File: " << FileNameFromCU << ")\n";
436*82d56013Sjoerg Preserved = false;
437*82d56013Sjoerg } else {
438*82d56013Sjoerg if (!InstrIt->second)
439*82d56013Sjoerg continue;
440*82d56013Sjoerg // If the instr had the !dbg attached before the pass, consider it as
441*82d56013Sjoerg // a debug info issue.
442*82d56013Sjoerg if (ShouldWriteIntoJSON)
443*82d56013Sjoerg Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
444*82d56013Sjoerg {"fn-name", FnName.str()},
445*82d56013Sjoerg {"bb-name", BBName.str()},
446*82d56013Sjoerg {"instr", InstName},
447*82d56013Sjoerg {"action", "drop"}}));
448*82d56013Sjoerg else
449*82d56013Sjoerg dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
450*82d56013Sjoerg << *Instr << " (BB: " << BBName << ", Fn: " << FnName
451*82d56013Sjoerg << ", File: " << FileNameFromCU << ")\n";
452*82d56013Sjoerg Preserved = false;
453*82d56013Sjoerg }
454*82d56013Sjoerg }
455*82d56013Sjoerg
456*82d56013Sjoerg return Preserved;
457*82d56013Sjoerg }
458*82d56013Sjoerg
459*82d56013Sjoerg // This checks the preservation of original debug variable intrinsics.
checkVars(const DebugVarMap & DIFunctionsBefore,const DebugVarMap & DIFunctionsAfter,StringRef NameOfWrappedPass,StringRef FileNameFromCU,bool ShouldWriteIntoJSON,llvm::json::Array & Bugs)460*82d56013Sjoerg static bool checkVars(const DebugVarMap &DIFunctionsBefore,
461*82d56013Sjoerg const DebugVarMap &DIFunctionsAfter,
462*82d56013Sjoerg StringRef NameOfWrappedPass, StringRef FileNameFromCU,
463*82d56013Sjoerg bool ShouldWriteIntoJSON, llvm::json::Array &Bugs) {
464*82d56013Sjoerg bool Preserved = true;
465*82d56013Sjoerg for (const auto &V : DIFunctionsBefore) {
466*82d56013Sjoerg auto VarIt = DIFunctionsAfter.find(V.first);
467*82d56013Sjoerg if (VarIt == DIFunctionsAfter.end())
468*82d56013Sjoerg continue;
469*82d56013Sjoerg
470*82d56013Sjoerg unsigned NumOfDbgValsAfter = VarIt->second;
471*82d56013Sjoerg
472*82d56013Sjoerg if (V.second > NumOfDbgValsAfter) {
473*82d56013Sjoerg if (ShouldWriteIntoJSON)
474*82d56013Sjoerg Bugs.push_back(llvm::json::Object(
475*82d56013Sjoerg {{"metadata", "dbg-var-intrinsic"},
476*82d56013Sjoerg {"name", V.first->getName()},
477*82d56013Sjoerg {"fn-name", V.first->getScope()->getSubprogram()->getName()},
478*82d56013Sjoerg {"action", "drop"}}));
479*82d56013Sjoerg else
480*82d56013Sjoerg dbg() << "WARNING: " << NameOfWrappedPass
481*82d56013Sjoerg << " drops dbg.value()/dbg.declare() for " << V.first->getName()
482*82d56013Sjoerg << " from "
483*82d56013Sjoerg << "function " << V.first->getScope()->getSubprogram()->getName()
484*82d56013Sjoerg << " (file " << FileNameFromCU << ")\n";
485*82d56013Sjoerg Preserved = false;
486*82d56013Sjoerg }
487*82d56013Sjoerg }
488*82d56013Sjoerg
489*82d56013Sjoerg return Preserved;
490*82d56013Sjoerg }
491*82d56013Sjoerg
492*82d56013Sjoerg // Write the json data into the specifed file.
writeJSON(StringRef OrigDIVerifyBugsReportFilePath,StringRef FileNameFromCU,StringRef NameOfWrappedPass,llvm::json::Array & Bugs)493*82d56013Sjoerg static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath,
494*82d56013Sjoerg StringRef FileNameFromCU, StringRef NameOfWrappedPass,
495*82d56013Sjoerg llvm::json::Array &Bugs) {
496*82d56013Sjoerg std::error_code EC;
497*82d56013Sjoerg raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC,
498*82d56013Sjoerg sys::fs::OF_Append | sys::fs::OF_TextWithCRLF};
499*82d56013Sjoerg if (EC) {
500*82d56013Sjoerg errs() << "Could not open file: " << EC.message() << ", "
501*82d56013Sjoerg << OrigDIVerifyBugsReportFilePath << '\n';
502*82d56013Sjoerg return;
503*82d56013Sjoerg }
504*82d56013Sjoerg
505*82d56013Sjoerg OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", ";
506*82d56013Sjoerg
507*82d56013Sjoerg StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name";
508*82d56013Sjoerg OS_FILE << "\"pass\":\"" << PassName << "\", ";
509*82d56013Sjoerg
510*82d56013Sjoerg llvm::json::Value BugsToPrint{std::move(Bugs)};
511*82d56013Sjoerg OS_FILE << "\"bugs\": " << BugsToPrint;
512*82d56013Sjoerg
513*82d56013Sjoerg OS_FILE << "}\n";
514*82d56013Sjoerg }
515*82d56013Sjoerg
checkDebugInfoMetadata(Module & M,iterator_range<Module::iterator> Functions,DebugInfoPerPassMap & DIPreservationMap,StringRef Banner,StringRef NameOfWrappedPass,StringRef OrigDIVerifyBugsReportFilePath)516*82d56013Sjoerg bool llvm::checkDebugInfoMetadata(Module &M,
517*82d56013Sjoerg iterator_range<Module::iterator> Functions,
518*82d56013Sjoerg DebugInfoPerPassMap &DIPreservationMap,
519*82d56013Sjoerg StringRef Banner, StringRef NameOfWrappedPass,
520*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath) {
521*82d56013Sjoerg LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');
522*82d56013Sjoerg
523*82d56013Sjoerg if (!M.getNamedMetadata("llvm.dbg.cu")) {
524*82d56013Sjoerg dbg() << Banner << ": Skipping module without debug info\n";
525*82d56013Sjoerg return false;
526*82d56013Sjoerg }
527*82d56013Sjoerg
528*82d56013Sjoerg // Map the debug info holding DIs after a pass.
529*82d56013Sjoerg DebugInfoPerPassMap DIPreservationAfter;
530*82d56013Sjoerg
531*82d56013Sjoerg // Visit each instruction.
532*82d56013Sjoerg for (Function &F : Functions) {
533*82d56013Sjoerg if (isFunctionSkipped(F))
534*82d56013Sjoerg continue;
535*82d56013Sjoerg
536*82d56013Sjoerg // TODO: Collect metadata other than DISubprograms.
537*82d56013Sjoerg // Collect the DISubprogram.
538*82d56013Sjoerg auto *SP = F.getSubprogram();
539*82d56013Sjoerg DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert(
540*82d56013Sjoerg {F.getName(), SP});
541*82d56013Sjoerg
542*82d56013Sjoerg if (SP) {
543*82d56013Sjoerg LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
544*82d56013Sjoerg for (const DINode *DN : SP->getRetainedNodes()) {
545*82d56013Sjoerg if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
546*82d56013Sjoerg DIPreservationAfter[NameOfWrappedPass].DIVariables[DV] = 0;
547*82d56013Sjoerg }
548*82d56013Sjoerg }
549*82d56013Sjoerg }
550*82d56013Sjoerg
551*82d56013Sjoerg for (BasicBlock &BB : F) {
552*82d56013Sjoerg // Collect debug locations (!dbg) and debug variable intrinsics.
553*82d56013Sjoerg for (Instruction &I : BB) {
554*82d56013Sjoerg // Skip PHIs.
555*82d56013Sjoerg if (isa<PHINode>(I))
556*82d56013Sjoerg continue;
557*82d56013Sjoerg
558*82d56013Sjoerg // Collect dbg.values and dbg.declares.
559*82d56013Sjoerg if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) {
560*82d56013Sjoerg if (!SP)
561*82d56013Sjoerg continue;
562*82d56013Sjoerg // Skip inlined variables.
563*82d56013Sjoerg if (I.getDebugLoc().getInlinedAt())
564*82d56013Sjoerg continue;
565*82d56013Sjoerg // Skip undef values.
566*82d56013Sjoerg if (DVI->isUndef())
567*82d56013Sjoerg continue;
568*82d56013Sjoerg
569*82d56013Sjoerg auto *Var = DVI->getVariable();
570*82d56013Sjoerg DIPreservationAfter[NameOfWrappedPass].DIVariables[Var]++;
571*82d56013Sjoerg continue;
572*82d56013Sjoerg }
573*82d56013Sjoerg
574*82d56013Sjoerg // Skip debug instructions other than dbg.value and dbg.declare.
575*82d56013Sjoerg if (isa<DbgInfoIntrinsic>(&I))
576*82d56013Sjoerg continue;
577*82d56013Sjoerg
578*82d56013Sjoerg LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
579*82d56013Sjoerg
580*82d56013Sjoerg const DILocation *Loc = I.getDebugLoc().get();
581*82d56013Sjoerg bool HasLoc = Loc != nullptr;
582*82d56013Sjoerg
583*82d56013Sjoerg DIPreservationAfter[NameOfWrappedPass].DILocations.insert({&I, HasLoc});
584*82d56013Sjoerg }
585*82d56013Sjoerg }
586*82d56013Sjoerg }
587*82d56013Sjoerg
588*82d56013Sjoerg // TODO: The name of the module could be read better?
589*82d56013Sjoerg StringRef FileNameFromCU =
590*82d56013Sjoerg (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
591*82d56013Sjoerg ->getFilename();
592*82d56013Sjoerg
593*82d56013Sjoerg auto DIFunctionsBefore = DIPreservationMap[NameOfWrappedPass].DIFunctions;
594*82d56013Sjoerg auto DIFunctionsAfter = DIPreservationAfter[NameOfWrappedPass].DIFunctions;
595*82d56013Sjoerg
596*82d56013Sjoerg auto DILocsBefore = DIPreservationMap[NameOfWrappedPass].DILocations;
597*82d56013Sjoerg auto DILocsAfter = DIPreservationAfter[NameOfWrappedPass].DILocations;
598*82d56013Sjoerg
599*82d56013Sjoerg auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete;
600*82d56013Sjoerg
601*82d56013Sjoerg auto DIVarsBefore = DIPreservationMap[NameOfWrappedPass].DIVariables;
602*82d56013Sjoerg auto DIVarsAfter = DIPreservationAfter[NameOfWrappedPass].DIVariables;
603*82d56013Sjoerg
604*82d56013Sjoerg bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
605*82d56013Sjoerg llvm::json::Array Bugs;
606*82d56013Sjoerg
607*82d56013Sjoerg bool ResultForFunc =
608*82d56013Sjoerg checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,
609*82d56013Sjoerg FileNameFromCU, ShouldWriteIntoJSON, Bugs);
610*82d56013Sjoerg bool ResultForInsts = checkInstructions(
611*82d56013Sjoerg DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,
612*82d56013Sjoerg FileNameFromCU, ShouldWriteIntoJSON, Bugs);
613*82d56013Sjoerg
614*82d56013Sjoerg bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass,
615*82d56013Sjoerg FileNameFromCU, ShouldWriteIntoJSON, Bugs);
616*82d56013Sjoerg
617*82d56013Sjoerg bool Result = ResultForFunc && ResultForInsts && ResultForVars;
618*82d56013Sjoerg
619*82d56013Sjoerg StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;
620*82d56013Sjoerg if (ShouldWriteIntoJSON && !Bugs.empty())
621*82d56013Sjoerg writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass,
622*82d56013Sjoerg Bugs);
623*82d56013Sjoerg
624*82d56013Sjoerg if (Result)
625*82d56013Sjoerg dbg() << ResultBanner << ": PASS\n";
626*82d56013Sjoerg else
627*82d56013Sjoerg dbg() << ResultBanner << ": FAIL\n";
628*82d56013Sjoerg
629*82d56013Sjoerg LLVM_DEBUG(dbgs() << "\n\n");
630*82d56013Sjoerg return Result;
631*82d56013Sjoerg }
632*82d56013Sjoerg
633*82d56013Sjoerg namespace {
634*82d56013Sjoerg /// Return true if a mis-sized diagnostic is issued for \p DVI.
diagnoseMisSizedDbgValue(Module & M,DbgValueInst * DVI)635*82d56013Sjoerg bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
636*82d56013Sjoerg // The size of a dbg.value's value operand should match the size of the
637*82d56013Sjoerg // variable it corresponds to.
638*82d56013Sjoerg //
639*82d56013Sjoerg // TODO: This, along with a check for non-null value operands, should be
640*82d56013Sjoerg // promoted to verifier failures.
641*82d56013Sjoerg
642*82d56013Sjoerg // For now, don't try to interpret anything more complicated than an empty
643*82d56013Sjoerg // DIExpression. Eventually we should try to handle OP_deref and fragments.
644*82d56013Sjoerg if (DVI->getExpression()->getNumElements())
645*82d56013Sjoerg return false;
646*82d56013Sjoerg
647*82d56013Sjoerg Value *V = DVI->getVariableLocationOp(0);
648*82d56013Sjoerg if (!V)
649*82d56013Sjoerg return false;
650*82d56013Sjoerg
651*82d56013Sjoerg Type *Ty = V->getType();
652*82d56013Sjoerg uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);
653*82d56013Sjoerg Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits();
654*82d56013Sjoerg if (!ValueOperandSize || !DbgVarSize)
655*82d56013Sjoerg return false;
656*82d56013Sjoerg
657*82d56013Sjoerg bool HasBadSize = false;
658*82d56013Sjoerg if (Ty->isIntegerTy()) {
659*82d56013Sjoerg auto Signedness = DVI->getVariable()->getSignedness();
660*82d56013Sjoerg if (Signedness && *Signedness == DIBasicType::Signedness::Signed)
661*82d56013Sjoerg HasBadSize = ValueOperandSize < *DbgVarSize;
662*82d56013Sjoerg } else {
663*82d56013Sjoerg HasBadSize = ValueOperandSize != *DbgVarSize;
664*82d56013Sjoerg }
665*82d56013Sjoerg
666*82d56013Sjoerg if (HasBadSize) {
667*82d56013Sjoerg dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize
668*82d56013Sjoerg << ", but its variable has size " << *DbgVarSize << ": ";
669*82d56013Sjoerg DVI->print(dbg());
670*82d56013Sjoerg dbg() << "\n";
671*82d56013Sjoerg }
672*82d56013Sjoerg return HasBadSize;
673*82d56013Sjoerg }
674*82d56013Sjoerg
checkDebugifyMetadata(Module & M,iterator_range<Module::iterator> Functions,StringRef NameOfWrappedPass,StringRef Banner,bool Strip,DebugifyStatsMap * StatsMap)675*82d56013Sjoerg bool checkDebugifyMetadata(Module &M,
676*82d56013Sjoerg iterator_range<Module::iterator> Functions,
677*82d56013Sjoerg StringRef NameOfWrappedPass, StringRef Banner,
678*82d56013Sjoerg bool Strip, DebugifyStatsMap *StatsMap) {
679*82d56013Sjoerg // Skip modules without debugify metadata.
680*82d56013Sjoerg NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
681*82d56013Sjoerg if (!NMD) {
682*82d56013Sjoerg dbg() << Banner << ": Skipping module without debugify metadata\n";
683*82d56013Sjoerg return false;
684*82d56013Sjoerg }
685*82d56013Sjoerg
686*82d56013Sjoerg auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
687*82d56013Sjoerg return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
688*82d56013Sjoerg ->getZExtValue();
689*82d56013Sjoerg };
690*82d56013Sjoerg assert(NMD->getNumOperands() == 2 &&
691*82d56013Sjoerg "llvm.debugify should have exactly 2 operands!");
692*82d56013Sjoerg unsigned OriginalNumLines = getDebugifyOperand(0);
693*82d56013Sjoerg unsigned OriginalNumVars = getDebugifyOperand(1);
694*82d56013Sjoerg bool HasErrors = false;
695*82d56013Sjoerg
696*82d56013Sjoerg // Track debug info loss statistics if able.
697*82d56013Sjoerg DebugifyStatistics *Stats = nullptr;
698*82d56013Sjoerg if (StatsMap && !NameOfWrappedPass.empty())
699*82d56013Sjoerg Stats = &StatsMap->operator[](NameOfWrappedPass);
700*82d56013Sjoerg
701*82d56013Sjoerg BitVector MissingLines{OriginalNumLines, true};
702*82d56013Sjoerg BitVector MissingVars{OriginalNumVars, true};
703*82d56013Sjoerg for (Function &F : Functions) {
704*82d56013Sjoerg if (isFunctionSkipped(F))
705*82d56013Sjoerg continue;
706*82d56013Sjoerg
707*82d56013Sjoerg // Find missing lines.
708*82d56013Sjoerg for (Instruction &I : instructions(F)) {
709*82d56013Sjoerg if (isa<DbgValueInst>(&I))
710*82d56013Sjoerg continue;
711*82d56013Sjoerg
712*82d56013Sjoerg auto DL = I.getDebugLoc();
713*82d56013Sjoerg if (DL && DL.getLine() != 0) {
714*82d56013Sjoerg MissingLines.reset(DL.getLine() - 1);
715*82d56013Sjoerg continue;
716*82d56013Sjoerg }
717*82d56013Sjoerg
718*82d56013Sjoerg if (!isa<PHINode>(&I) && !DL) {
719*82d56013Sjoerg dbg() << "WARNING: Instruction with empty DebugLoc in function ";
720*82d56013Sjoerg dbg() << F.getName() << " --";
721*82d56013Sjoerg I.print(dbg());
722*82d56013Sjoerg dbg() << "\n";
723*82d56013Sjoerg }
724*82d56013Sjoerg }
725*82d56013Sjoerg
726*82d56013Sjoerg // Find missing variables and mis-sized debug values.
727*82d56013Sjoerg for (Instruction &I : instructions(F)) {
728*82d56013Sjoerg auto *DVI = dyn_cast<DbgValueInst>(&I);
729*82d56013Sjoerg if (!DVI)
730*82d56013Sjoerg continue;
731*82d56013Sjoerg
732*82d56013Sjoerg unsigned Var = ~0U;
733*82d56013Sjoerg (void)to_integer(DVI->getVariable()->getName(), Var, 10);
734*82d56013Sjoerg assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
735*82d56013Sjoerg bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI);
736*82d56013Sjoerg if (!HasBadSize)
737*82d56013Sjoerg MissingVars.reset(Var - 1);
738*82d56013Sjoerg HasErrors |= HasBadSize;
739*82d56013Sjoerg }
740*82d56013Sjoerg }
741*82d56013Sjoerg
742*82d56013Sjoerg // Print the results.
743*82d56013Sjoerg for (unsigned Idx : MissingLines.set_bits())
744*82d56013Sjoerg dbg() << "WARNING: Missing line " << Idx + 1 << "\n";
745*82d56013Sjoerg
746*82d56013Sjoerg for (unsigned Idx : MissingVars.set_bits())
747*82d56013Sjoerg dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
748*82d56013Sjoerg
749*82d56013Sjoerg // Update DI loss statistics.
750*82d56013Sjoerg if (Stats) {
751*82d56013Sjoerg Stats->NumDbgLocsExpected += OriginalNumLines;
752*82d56013Sjoerg Stats->NumDbgLocsMissing += MissingLines.count();
753*82d56013Sjoerg Stats->NumDbgValuesExpected += OriginalNumVars;
754*82d56013Sjoerg Stats->NumDbgValuesMissing += MissingVars.count();
755*82d56013Sjoerg }
756*82d56013Sjoerg
757*82d56013Sjoerg dbg() << Banner;
758*82d56013Sjoerg if (!NameOfWrappedPass.empty())
759*82d56013Sjoerg dbg() << " [" << NameOfWrappedPass << "]";
760*82d56013Sjoerg dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
761*82d56013Sjoerg
762*82d56013Sjoerg // Strip debugify metadata if required.
763*82d56013Sjoerg if (Strip)
764*82d56013Sjoerg return stripDebugifyMetadata(M);
765*82d56013Sjoerg
766*82d56013Sjoerg return false;
767*82d56013Sjoerg }
768*82d56013Sjoerg
769*82d56013Sjoerg /// ModulePass for attaching synthetic debug info to everything, used with the
770*82d56013Sjoerg /// legacy module pass manager.
771*82d56013Sjoerg struct DebugifyModulePass : public ModulePass {
runOnModule__anon4c892b280511::DebugifyModulePass772*82d56013Sjoerg bool runOnModule(Module &M) override {
773*82d56013Sjoerg return applyDebugify(M, Mode, DIPreservationMap, NameOfWrappedPass);
774*82d56013Sjoerg }
775*82d56013Sjoerg
DebugifyModulePass__anon4c892b280511::DebugifyModulePass776*82d56013Sjoerg DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
777*82d56013Sjoerg StringRef NameOfWrappedPass = "",
778*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr)
779*82d56013Sjoerg : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
780*82d56013Sjoerg DIPreservationMap(DIPreservationMap), Mode(Mode) {}
781*82d56013Sjoerg
getAnalysisUsage__anon4c892b280511::DebugifyModulePass782*82d56013Sjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
783*82d56013Sjoerg AU.setPreservesAll();
784*82d56013Sjoerg }
785*82d56013Sjoerg
786*82d56013Sjoerg static char ID; // Pass identification.
787*82d56013Sjoerg
788*82d56013Sjoerg private:
789*82d56013Sjoerg StringRef NameOfWrappedPass;
790*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap;
791*82d56013Sjoerg enum DebugifyMode Mode;
792*82d56013Sjoerg };
793*82d56013Sjoerg
794*82d56013Sjoerg /// FunctionPass for attaching synthetic debug info to instructions within a
795*82d56013Sjoerg /// single function, used with the legacy module pass manager.
796*82d56013Sjoerg struct DebugifyFunctionPass : public FunctionPass {
runOnFunction__anon4c892b280511::DebugifyFunctionPass797*82d56013Sjoerg bool runOnFunction(Function &F) override {
798*82d56013Sjoerg return applyDebugify(F, Mode, DIPreservationMap, NameOfWrappedPass);
799*82d56013Sjoerg }
800*82d56013Sjoerg
DebugifyFunctionPass__anon4c892b280511::DebugifyFunctionPass801*82d56013Sjoerg DebugifyFunctionPass(
802*82d56013Sjoerg enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
803*82d56013Sjoerg StringRef NameOfWrappedPass = "",
804*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr)
805*82d56013Sjoerg : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
806*82d56013Sjoerg DIPreservationMap(DIPreservationMap), Mode(Mode) {}
807*82d56013Sjoerg
getAnalysisUsage__anon4c892b280511::DebugifyFunctionPass808*82d56013Sjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
809*82d56013Sjoerg AU.setPreservesAll();
810*82d56013Sjoerg }
811*82d56013Sjoerg
812*82d56013Sjoerg static char ID; // Pass identification.
813*82d56013Sjoerg
814*82d56013Sjoerg private:
815*82d56013Sjoerg StringRef NameOfWrappedPass;
816*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap;
817*82d56013Sjoerg enum DebugifyMode Mode;
818*82d56013Sjoerg };
819*82d56013Sjoerg
820*82d56013Sjoerg /// ModulePass for checking debug info inserted by -debugify, used with the
821*82d56013Sjoerg /// legacy module pass manager.
822*82d56013Sjoerg struct CheckDebugifyModulePass : public ModulePass {
runOnModule__anon4c892b280511::CheckDebugifyModulePass823*82d56013Sjoerg bool runOnModule(Module &M) override {
824*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
825*82d56013Sjoerg return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
826*82d56013Sjoerg "CheckModuleDebugify", Strip, StatsMap);
827*82d56013Sjoerg return checkDebugInfoMetadata(
828*82d56013Sjoerg M, M.functions(), *DIPreservationMap,
829*82d56013Sjoerg "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
830*82d56013Sjoerg OrigDIVerifyBugsReportFilePath);
831*82d56013Sjoerg }
832*82d56013Sjoerg
CheckDebugifyModulePass__anon4c892b280511::CheckDebugifyModulePass833*82d56013Sjoerg CheckDebugifyModulePass(
834*82d56013Sjoerg bool Strip = false, StringRef NameOfWrappedPass = "",
835*82d56013Sjoerg DebugifyStatsMap *StatsMap = nullptr,
836*82d56013Sjoerg enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
837*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr,
838*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath = "")
839*82d56013Sjoerg : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
840*82d56013Sjoerg OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
841*82d56013Sjoerg StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
842*82d56013Sjoerg Strip(Strip) {}
843*82d56013Sjoerg
getAnalysisUsage__anon4c892b280511::CheckDebugifyModulePass844*82d56013Sjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
845*82d56013Sjoerg AU.setPreservesAll();
846*82d56013Sjoerg }
847*82d56013Sjoerg
848*82d56013Sjoerg static char ID; // Pass identification.
849*82d56013Sjoerg
850*82d56013Sjoerg private:
851*82d56013Sjoerg StringRef NameOfWrappedPass;
852*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath;
853*82d56013Sjoerg DebugifyStatsMap *StatsMap;
854*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap;
855*82d56013Sjoerg enum DebugifyMode Mode;
856*82d56013Sjoerg bool Strip;
857*82d56013Sjoerg };
858*82d56013Sjoerg
859*82d56013Sjoerg /// FunctionPass for checking debug info inserted by -debugify-function, used
860*82d56013Sjoerg /// with the legacy module pass manager.
861*82d56013Sjoerg struct CheckDebugifyFunctionPass : public FunctionPass {
runOnFunction__anon4c892b280511::CheckDebugifyFunctionPass862*82d56013Sjoerg bool runOnFunction(Function &F) override {
863*82d56013Sjoerg Module &M = *F.getParent();
864*82d56013Sjoerg auto FuncIt = F.getIterator();
865*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
866*82d56013Sjoerg return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
867*82d56013Sjoerg NameOfWrappedPass, "CheckFunctionDebugify",
868*82d56013Sjoerg Strip, StatsMap);
869*82d56013Sjoerg return checkDebugInfoMetadata(
870*82d56013Sjoerg M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap,
871*82d56013Sjoerg "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass,
872*82d56013Sjoerg OrigDIVerifyBugsReportFilePath);
873*82d56013Sjoerg }
874*82d56013Sjoerg
CheckDebugifyFunctionPass__anon4c892b280511::CheckDebugifyFunctionPass875*82d56013Sjoerg CheckDebugifyFunctionPass(
876*82d56013Sjoerg bool Strip = false, StringRef NameOfWrappedPass = "",
877*82d56013Sjoerg DebugifyStatsMap *StatsMap = nullptr,
878*82d56013Sjoerg enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
879*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap = nullptr,
880*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath = "")
881*82d56013Sjoerg : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
882*82d56013Sjoerg OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
883*82d56013Sjoerg StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode),
884*82d56013Sjoerg Strip(Strip) {}
885*82d56013Sjoerg
getAnalysisUsage__anon4c892b280511::CheckDebugifyFunctionPass886*82d56013Sjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
887*82d56013Sjoerg AU.setPreservesAll();
888*82d56013Sjoerg }
889*82d56013Sjoerg
890*82d56013Sjoerg static char ID; // Pass identification.
891*82d56013Sjoerg
892*82d56013Sjoerg private:
893*82d56013Sjoerg StringRef NameOfWrappedPass;
894*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath;
895*82d56013Sjoerg DebugifyStatsMap *StatsMap;
896*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap;
897*82d56013Sjoerg enum DebugifyMode Mode;
898*82d56013Sjoerg bool Strip;
899*82d56013Sjoerg };
900*82d56013Sjoerg
901*82d56013Sjoerg } // end anonymous namespace
902*82d56013Sjoerg
exportDebugifyStats(StringRef Path,const DebugifyStatsMap & Map)903*82d56013Sjoerg void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) {
904*82d56013Sjoerg std::error_code EC;
905*82d56013Sjoerg raw_fd_ostream OS{Path, EC};
906*82d56013Sjoerg if (EC) {
907*82d56013Sjoerg errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
908*82d56013Sjoerg return;
909*82d56013Sjoerg }
910*82d56013Sjoerg
911*82d56013Sjoerg OS << "Pass Name" << ',' << "# of missing debug values" << ','
912*82d56013Sjoerg << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
913*82d56013Sjoerg << "Missing/Expected location ratio" << '\n';
914*82d56013Sjoerg for (const auto &Entry : Map) {
915*82d56013Sjoerg StringRef Pass = Entry.first;
916*82d56013Sjoerg DebugifyStatistics Stats = Entry.second;
917*82d56013Sjoerg
918*82d56013Sjoerg OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
919*82d56013Sjoerg << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
920*82d56013Sjoerg << Stats.getEmptyLocationRatio() << '\n';
921*82d56013Sjoerg }
922*82d56013Sjoerg }
923*82d56013Sjoerg
createDebugifyModulePass(enum DebugifyMode Mode,llvm::StringRef NameOfWrappedPass,DebugInfoPerPassMap * DIPreservationMap)924*82d56013Sjoerg ModulePass *createDebugifyModulePass(enum DebugifyMode Mode,
925*82d56013Sjoerg llvm::StringRef NameOfWrappedPass,
926*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap) {
927*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
928*82d56013Sjoerg return new DebugifyModulePass();
929*82d56013Sjoerg assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
930*82d56013Sjoerg return new DebugifyModulePass(Mode, NameOfWrappedPass, DIPreservationMap);
931*82d56013Sjoerg }
932*82d56013Sjoerg
933*82d56013Sjoerg FunctionPass *
createDebugifyFunctionPass(enum DebugifyMode Mode,llvm::StringRef NameOfWrappedPass,DebugInfoPerPassMap * DIPreservationMap)934*82d56013Sjoerg createDebugifyFunctionPass(enum DebugifyMode Mode,
935*82d56013Sjoerg llvm::StringRef NameOfWrappedPass,
936*82d56013Sjoerg DebugInfoPerPassMap *DIPreservationMap) {
937*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
938*82d56013Sjoerg return new DebugifyFunctionPass();
939*82d56013Sjoerg assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
940*82d56013Sjoerg return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap);
941*82d56013Sjoerg }
942*82d56013Sjoerg
run(Module & M,ModuleAnalysisManager &)943*82d56013Sjoerg PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
944*82d56013Sjoerg applyDebugifyMetadata(M, M.functions(),
945*82d56013Sjoerg "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
946*82d56013Sjoerg return PreservedAnalyses::all();
947*82d56013Sjoerg }
948*82d56013Sjoerg
createCheckDebugifyModulePass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap,enum DebugifyMode Mode,DebugInfoPerPassMap * DIPreservationMap,StringRef OrigDIVerifyBugsReportFilePath)949*82d56013Sjoerg ModulePass *createCheckDebugifyModulePass(
950*82d56013Sjoerg bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
951*82d56013Sjoerg enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap,
952*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath) {
953*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
954*82d56013Sjoerg return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
955*82d56013Sjoerg assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
956*82d56013Sjoerg return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,
957*82d56013Sjoerg DIPreservationMap,
958*82d56013Sjoerg OrigDIVerifyBugsReportFilePath);
959*82d56013Sjoerg }
960*82d56013Sjoerg
createCheckDebugifyFunctionPass(bool Strip,StringRef NameOfWrappedPass,DebugifyStatsMap * StatsMap,enum DebugifyMode Mode,DebugInfoPerPassMap * DIPreservationMap,StringRef OrigDIVerifyBugsReportFilePath)961*82d56013Sjoerg FunctionPass *createCheckDebugifyFunctionPass(
962*82d56013Sjoerg bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap,
963*82d56013Sjoerg enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap,
964*82d56013Sjoerg StringRef OrigDIVerifyBugsReportFilePath) {
965*82d56013Sjoerg if (Mode == DebugifyMode::SyntheticDebugInfo)
966*82d56013Sjoerg return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
967*82d56013Sjoerg assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode");
968*82d56013Sjoerg return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,
969*82d56013Sjoerg DIPreservationMap,
970*82d56013Sjoerg OrigDIVerifyBugsReportFilePath);
971*82d56013Sjoerg }
972*82d56013Sjoerg
run(Module & M,ModuleAnalysisManager &)973*82d56013Sjoerg PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
974*82d56013Sjoerg ModuleAnalysisManager &) {
975*82d56013Sjoerg checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false,
976*82d56013Sjoerg nullptr);
977*82d56013Sjoerg return PreservedAnalyses::all();
978*82d56013Sjoerg }
979*82d56013Sjoerg
isIgnoredPass(StringRef PassID)980*82d56013Sjoerg static bool isIgnoredPass(StringRef PassID) {
981*82d56013Sjoerg return isSpecialPass(PassID, {"PassManager", "PassAdaptor",
982*82d56013Sjoerg "AnalysisManagerProxy", "PrintFunctionPass",
983*82d56013Sjoerg "PrintModulePass", "BitcodeWriterPass",
984*82d56013Sjoerg "ThinLTOBitcodeWriterPass", "VerifierPass"});
985*82d56013Sjoerg }
986*82d56013Sjoerg
registerCallbacks(PassInstrumentationCallbacks & PIC)987*82d56013Sjoerg void DebugifyEachInstrumentation::registerCallbacks(
988*82d56013Sjoerg PassInstrumentationCallbacks &PIC) {
989*82d56013Sjoerg PIC.registerBeforeNonSkippedPassCallback([](StringRef P, Any IR) {
990*82d56013Sjoerg if (isIgnoredPass(P))
991*82d56013Sjoerg return;
992*82d56013Sjoerg if (any_isa<const Function *>(IR))
993*82d56013Sjoerg applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR)));
994*82d56013Sjoerg else if (any_isa<const Module *>(IR))
995*82d56013Sjoerg applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR)));
996*82d56013Sjoerg });
997*82d56013Sjoerg PIC.registerAfterPassCallback([this](StringRef P, Any IR,
998*82d56013Sjoerg const PreservedAnalyses &PassPA) {
999*82d56013Sjoerg if (isIgnoredPass(P))
1000*82d56013Sjoerg return;
1001*82d56013Sjoerg if (any_isa<const Function *>(IR)) {
1002*82d56013Sjoerg auto &F = *const_cast<Function *>(any_cast<const Function *>(IR));
1003*82d56013Sjoerg Module &M = *F.getParent();
1004*82d56013Sjoerg auto It = F.getIterator();
1005*82d56013Sjoerg checkDebugifyMetadata(M, make_range(It, std::next(It)), P,
1006*82d56013Sjoerg "CheckFunctionDebugify", /*Strip=*/true, &StatsMap);
1007*82d56013Sjoerg } else if (any_isa<const Module *>(IR)) {
1008*82d56013Sjoerg auto &M = *const_cast<Module *>(any_cast<const Module *>(IR));
1009*82d56013Sjoerg checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify",
1010*82d56013Sjoerg /*Strip=*/true, &StatsMap);
1011*82d56013Sjoerg }
1012*82d56013Sjoerg });
1013*82d56013Sjoerg }
1014*82d56013Sjoerg
1015*82d56013Sjoerg char DebugifyModulePass::ID = 0;
1016*82d56013Sjoerg static RegisterPass<DebugifyModulePass> DM("debugify",
1017*82d56013Sjoerg "Attach debug info to everything");
1018*82d56013Sjoerg
1019*82d56013Sjoerg char CheckDebugifyModulePass::ID = 0;
1020*82d56013Sjoerg static RegisterPass<CheckDebugifyModulePass>
1021*82d56013Sjoerg CDM("check-debugify", "Check debug info from -debugify");
1022*82d56013Sjoerg
1023*82d56013Sjoerg char DebugifyFunctionPass::ID = 0;
1024*82d56013Sjoerg static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
1025*82d56013Sjoerg "Attach debug info to a function");
1026*82d56013Sjoerg
1027*82d56013Sjoerg char CheckDebugifyFunctionPass::ID = 0;
1028*82d56013Sjoerg static RegisterPass<CheckDebugifyFunctionPass>
1029*82d56013Sjoerg CDF("check-debugify-function", "Check debug info from -debugify-function");
1030