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