LLVM: lib/Transforms/Utils/Debugify.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
30#include
31
32#define DEBUG_TYPE "debugify"
33
34using namespace llvm;
35
36namespace {
37
39 cl::desc("Suppress verbose debugify output"));
40
42 "debugify-func-limit",
43 cl::desc("Set max number of processed functions per pass."),
45
46enum class Level {
47 Locations,
48 LocationsAndVariables
49};
50
52 "debugify-level", cl::desc("Kind of debug info to add"),
54 clEnumValN(Level::LocationsAndVariables, "location+variables",
55 "Locations and Variables")),
56 cl::init(Level::LocationsAndVariables));
57
59
61 return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
62}
63
64bool isFunctionSkipped(Function &F) {
65 return F.isDeclaration() || .hasExactDefinition();
66}
67
68
69
70
71
74 return I;
76 return I;
78}
79}
80
84
85 if (M.getNamedMetadata("llvm.dbg.cu")) {
86 dbg() << Banner << "Skipping module with debug info\n";
87 return false;
88 }
89
93
94
96 auto getCachedDIType = [&](Type *Ty) -> DIType * {
99 if (!DTy) {
100 std::string Name = "ty" + utostr(Size);
102 }
103 return DTy;
104 };
105
106 unsigned NextLine = 1;
107 unsigned NextVar = 1;
110 true, "", 0);
111
112
114 if (isFunctionSkipped(F))
115 continue;
116
117 bool InsertedDbgVal = false;
120 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized;
121 if (F.hasPrivateLinkage() || F.hasInternalLinkage())
122 SPFlags |= DISubprogram::SPFlagLocalToUnit;
123 auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine,
124 SPType, NextLine, DINode::FlagZero, SPFlags);
125 F.setSubprogram(SP);
126
127
128
129 auto insertDbgVal = [&](Instruction &TemplateInst,
131 std::string Name = utostr(NextVar++);
134 V = ConstantInt::get(Int32Ty, 0);
137 getCachedDIType(V->getType()),
138 true);
139 DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc,
140 InsertBefore);
141 };
142
144
146 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
147
148 if (DebugifyLevel < Level::LocationsAndVariables)
149 continue;
150
151
152 if (BB.isEHPad())
153 continue;
154
155
156
157 Instruction *LastInst = findTerminatingInstruction(BB);
158 assert(LastInst && "Expected basic block with a terminator");
159
160
161
163 assert(InsertPt != BB.end() && "Expected to find an insertion point");
165
166
167 for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) {
168
169 if (I->getType()->isVoidTy())
170 continue;
171
172
173
174 if (!isa(I) && ->isEHPad())
175 InsertBefore = I->getNextNode();
176
177 insertDbgVal(*I, InsertBefore);
178 InsertedDbgVal = true;
179 }
180 }
181
182
183
184
185
186 if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) {
187 auto *Term = findTerminatingInstruction(F.getEntryBlock());
188 insertDbgVal(*Term, Term);
189 }
190 if (ApplyToMF)
191 ApplyToMF(DIB, F);
193 }
195
196
197 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
198 auto addDebugifyOperand = [&](unsigned N) {
201 };
202 addDebugifyOperand(NextLine - 1);
203 addDebugifyOperand(NextVar - 1);
205 "llvm.debugify should have exactly 2 operands!");
206
207
208 StringRef DIVersionKey = "Debug Info Version";
209 if (.getModuleFlag(DIVersionKey))
211
212 return true;
213}
214
215static bool
219 StringRef NameOfWrappedPass = "") {
220 Module &M = *F.getParent();
221 auto FuncIt = F.getIterator();
224 "FunctionDebugify: ", nullptr);
225 assert(DebugInfoBeforePass);
227 "FunctionDebugify (original debuginfo)",
228 NameOfWrappedPass);
229}
230
231static bool
235 StringRef NameOfWrappedPass = "") {
238 "ModuleDebugify: ", nullptr);
240 "ModuleDebugify (original debuginfo)",
241 NameOfWrappedPass);
242}
243
245 bool Changed = false;
246
247
248 NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify");
249 if (DebugifyMD) {
250 M.eraseNamedMetadata(DebugifyMD);
251 Changed = true;
252 }
253
254 if (auto *MIRDebugifyMD = M.getNamedMetadata("llvm.mir.debugify")) {
255 M.eraseNamedMetadata(MIRDebugifyMD);
256 Changed = true;
257 }
258
259
260
262
263
264 Function *DbgValF = M.getFunction("llvm.dbg.value");
265 if (DbgValF) {
267 "Not all debug info stripped?");
269 Changed = true;
270 }
271
272
273
274 NamedMDNode *NMD = M.getModuleFlagsMetadata();
275 if (!NMD)
276 return Changed;
279 for (MDNode *Flag : Flags) {
280 auto *Key = cast(Flag->getOperand(1));
281 if (Key->getString() == "Debug Info Version") {
282 Changed = true;
283 continue;
284 }
286 }
287
290
291 return Changed;
292}
293
299 LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n');
300
301 if (!M.getNamedMetadata("llvm.dbg.cu")) {
302 dbg() << Banner << ": Skipping module without debug info\n";
303 return false;
304 }
305
307
309
311 continue;
312
313 if (isFunctionSkipped(F))
314 continue;
315
316
317 if (++FunctionsCnt >= DebugifyFunctionsLimit)
318 break;
319
320 auto *SP = F.getSubprogram();
322 if (SP) {
323 LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
324 for (const DINode *DN : SP->getRetainedNodes()) {
325 if (const auto *DV = dyn_cast(DN)) {
327 }
328 }
329 }
330
332
334
335 if (isa(I))
336 continue;
337
338
339 if (DebugifyLevel > Level::Locations) {
340 auto HandleDbgVariable = [&](auto *DbgVar) {
341 if (!SP)
342 return;
343
344 if (DbgVar->getDebugLoc().getInlinedAt())
345 return;
346
347 if (DbgVar->isKillLocation())
348 return;
349
350 auto *Var = DbgVar->getVariable();
352 };
354 HandleDbgVariable(&DVR);
355 if (auto *DVI = dyn_cast(&I))
356 HandleDbgVariable(DVI);
357 }
358
359
360 if (isa(&I))
361 continue;
362
363 LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
365
366 const DILocation *Loc = I.getDebugLoc().get();
367 bool HasLoc = Loc != nullptr;
369 }
370 }
371 }
372
373 return true;
374}
375
376
380 StringRef FileNameFromCU, bool ShouldWriteIntoJSON,
382 bool Preserved = true;
383 for (const auto &F : DIFunctionsAfter) {
384 if (F.second)
385 continue;
386 auto SPIt = DIFunctionsBefore.find(F.first);
387 if (SPIt == DIFunctionsBefore.end()) {
388 if (ShouldWriteIntoJSON)
390 {"name", F.first->getName()},
391 {"action", "not-generate"}}));
392 else
393 dbg() << "ERROR: " << NameOfWrappedPass
394 << " did not generate DISubprogram for " << F.first->getName()
395 << " from " << FileNameFromCU << '\n';
396 Preserved = false;
397 } else {
398 auto SP = SPIt->second;
399 if (!SP)
400 continue;
401
402
403 if (ShouldWriteIntoJSON)
405 {"name", F.first->getName()},
406 {"action", "drop"}}));
407 else
408 dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of "
409 << F.first->getName() << " from " << FileNameFromCU << '\n';
410 Preserved = false;
411 }
412 }
413
414 return Preserved;
415}
416
417
418
424 bool ShouldWriteIntoJSON,
426 bool Preserved = true;
427 for (const auto &L : DILocsAfter) {
428 if (L.second)
429 continue;
430 auto Instr = L.first;
431
432
433
434 auto WeakInstrPtr = InstToDelete.find(Instr);
435 if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
436 continue;
437
438 auto FnName = Instr->getFunction()->getName();
439 auto BB = Instr->getParent();
440 auto BBName = BB->hasName() ? BB->getName() : "no-name";
442
443 auto InstrIt = DILocsBefore.find(Instr);
444 if (InstrIt == DILocsBefore.end()) {
445 if (ShouldWriteIntoJSON)
447 {"fn-name", FnName.str()},
448 {"bb-name", BBName.str()},
449 {"instr", InstName},
450 {"action", "not-generate"}}));
451 else
452 dbg() << "WARNING: " << NameOfWrappedPass
453 << " did not generate DILocation for " << *Instr
454 << " (BB: " << BBName << ", Fn: " << FnName
455 << ", File: " << FileNameFromCU << ")\n";
456 Preserved = false;
457 } else {
458 if (!InstrIt->second)
459 continue;
460
461
462 if (ShouldWriteIntoJSON)
464 {"fn-name", FnName.str()},
465 {"bb-name", BBName.str()},
466 {"instr", InstName},
467 {"action", "drop"}}));
468 else
469 dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
470 << *Instr << " (BB: " << BBName << ", Fn: " << FnName
471 << ", File: " << FileNameFromCU << ")\n";
472 Preserved = false;
473 }
474 }
475
476 return Preserved;
477}
478
479
484 bool Preserved = true;
485 for (const auto &V : DIVarsBefore) {
486 auto VarIt = DIVarsAfter.find(V.first);
487 if (VarIt == DIVarsAfter.end())
488 continue;
489
490 unsigned NumOfDbgValsAfter = VarIt->second;
491
492 if (V.second > NumOfDbgValsAfter) {
493 if (ShouldWriteIntoJSON)
495 {{"metadata", "dbg-var-intrinsic"},
496 {"name", V.first->getName()},
498 {"action", "drop"}}));
499 else
500 dbg() << "WARNING: " << NameOfWrappedPass
501 << " drops dbg.value()/dbg.declare() for " << V.first->getName()
502 << " from "
503 << "function " << V.first->getScope()->getSubprogram()->getName()
504 << " (file " << FileNameFromCU << ")\n";
505 Preserved = false;
506 }
507 }
508
509 return Preserved;
510}
511
512
516 std::error_code EC;
517 raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC,
519 if (EC) {
520 errs() << "Could not open file: " << EC.message() << ", "
521 << OrigDIVerifyBugsReportFilePath << '\n';
522 return;
523 }
524
525 if (auto L = OS_FILE.lock()) {
526 OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", ";
527
529 NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name";
530 OS_FILE << "\"pass\":\"" << PassName << "\", ";
531
533 OS_FILE << "\"bugs\": " << BugsToPrint;
534
535 OS_FILE << "}\n";
536 }
537 OS_FILE.close();
538}
539
544 StringRef OrigDIVerifyBugsReportFilePath) {
545 LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n');
546
547 if (!M.getNamedMetadata("llvm.dbg.cu")) {
548 dbg() << Banner << ": Skipping module without debug info\n";
549 return false;
550 }
551
552
554
555
557 if (isFunctionSkipped(F))
558 continue;
559
560
562 continue;
563
564
565 auto *SP = F.getSubprogram();
567
568 if (SP) {
569 LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n');
570 for (const DINode *DN : SP->getRetainedNodes()) {
571 if (const auto *DV = dyn_cast(DN)) {
573 }
574 }
575 }
576
578
580
581 if (isa(I))
582 continue;
583
584
585 if (DebugifyLevel > Level::Locations) {
586 auto HandleDbgVariable = [&](auto *DbgVar) {
587 if (!SP)
588 return;
589
590 if (DbgVar->getDebugLoc().getInlinedAt())
591 return;
592
593 if (DbgVar->isKillLocation())
594 return;
595
596 auto *Var = DbgVar->getVariable();
598 };
600 HandleDbgVariable(&DVR);
601 if (auto *DVI = dyn_cast(&I))
602 HandleDbgVariable(DVI);
603 }
604
605
606 if (isa(&I))
607 continue;
608
609 LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
610
611 const DILocation *Loc = I.getDebugLoc().get();
612 bool HasLoc = Loc != nullptr;
613
615 }
616 }
617 }
618
619
621 (cast(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
623
624 auto DIFunctionsBefore = DebugInfoBeforePass.DIFunctions;
625 auto DIFunctionsAfter = DebugInfoAfterPass.DIFunctions;
626
627 auto DILocsBefore = DebugInfoBeforePass.DILocations;
628 auto DILocsAfter = DebugInfoAfterPass.DILocations;
629
630 auto InstToDelete = DebugInfoBeforePass.InstToDelete;
631
632 auto DIVarsBefore = DebugInfoBeforePass.DIVariables;
633 auto DIVarsAfter = DebugInfoAfterPass.DIVariables;
634
635 bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
637
638 bool ResultForFunc =
639 checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,
640 FileNameFromCU, ShouldWriteIntoJSON, Bugs);
642 DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,
643 FileNameFromCU, ShouldWriteIntoJSON, Bugs);
644
645 bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass,
646 FileNameFromCU, ShouldWriteIntoJSON, Bugs);
647
648 bool Result = ResultForFunc && ResultForInsts && ResultForVars;
649
650 StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner;
651 if (ShouldWriteIntoJSON && !Bugs.empty())
652 writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass,
653 Bugs);
654
655 if (Result)
656 dbg() << ResultBanner << ": PASS\n";
657 else
658 dbg() << ResultBanner << ": FAIL\n";
659
660
661
662
663 DebugInfoBeforePass = DebugInfoAfterPass;
664
666 return Result;
667}
668
669namespace {
670
671template
672bool diagnoseMisSizedDbgValue(Module &M, DbgValTy *DbgVal) {
673
674
675
676
677
678
679
680
681 if (DbgVal->getExpression()->getNumElements())
682 return false;
683
684 Value *V = DbgVal->getVariableLocationOp(0);
685 if (!V)
686 return false;
687
688 Type *Ty = V->getType();
689 uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty);
690 std::optional<uint64_t> DbgVarSize = DbgVal->getFragmentSizeInBits();
691 if (!ValueOperandSize || !DbgVarSize)
692 return false;
693
694 bool HasBadSize = false;
696 auto Signedness = DbgVal->getVariable()->getSignedness();
697 if (Signedness && *Signedness == DIBasicType::Signedness::Signed)
698 HasBadSize = ValueOperandSize < *DbgVarSize;
699 } else {
700 HasBadSize = ValueOperandSize != *DbgVarSize;
701 }
702
703 if (HasBadSize) {
704 dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize
705 << ", but its variable has size " << *DbgVarSize << ": ";
706 DbgVal->print(dbg());
707 dbg() << "\n";
708 }
709 return HasBadSize;
710}
711
712bool checkDebugifyMetadata(Module &M,
716
717 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
718 if (!NMD) {
719 dbg() << Banner << ": Skipping module without debugify metadata\n";
720 return false;
721 }
722
723 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
725 ->getZExtValue();
726 };
728 "llvm.debugify should have exactly 2 operands!");
729 unsigned OriginalNumLines = getDebugifyOperand(0);
730 unsigned OriginalNumVars = getDebugifyOperand(1);
731 bool HasErrors = false;
732
733
735 if (StatsMap && !NameOfWrappedPass.empty())
736 Stats = &StatsMap->operator[](NameOfWrappedPass);
737
738 BitVector MissingLines{OriginalNumLines, true};
739 BitVector MissingVars{OriginalNumVars, true};
741 if (isFunctionSkipped(F))
742 continue;
743
744
746 if (isa(&I))
747 continue;
748
749 auto DL = I.getDebugLoc();
750 if (DL && DL.getLine() != 0) {
751 MissingLines.reset(DL.getLine() - 1);
752 continue;
753 }
754
755 if (!isa(&I) && ) {
756 dbg() << "WARNING: Instruction with empty DebugLoc in function ";
757 dbg() << F.getName() << " --";
758 I.print(dbg());
759 dbg() << "\n";
760 }
761 }
762
763
764 auto CheckForMisSized = [&](auto *DbgVal) {
765 unsigned Var = ~0U;
766 (void)to_integer(DbgVal->getVariable()->getName(), Var, 10);
767 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
768 bool HasBadSize = diagnoseMisSizedDbgValue(M, DbgVal);
769 if (!HasBadSize)
770 MissingVars.reset(Var - 1);
771 HasErrors |= HasBadSize;
772 };
775 if (DVR.isDbgValue() || DVR.isDbgAssign())
776 CheckForMisSized(&DVR);
777 auto *DVI = dyn_cast(&I);
778 if (!DVI)
779 continue;
780 CheckForMisSized(DVI);
781 }
782 }
783
784
785 for (unsigned Idx : MissingLines.set_bits())
786 dbg() << "WARNING: Missing line " << Idx + 1 << "\n";
787
788 for (unsigned Idx : MissingVars.set_bits())
789 dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
790
791
793 Stats->NumDbgLocsExpected += OriginalNumLines;
794 Stats->NumDbgLocsMissing += MissingLines.count();
795 Stats->NumDbgValuesExpected += OriginalNumVars;
796 Stats->NumDbgValuesMissing += MissingVars.count();
797 }
798
799 dbg() << Banner;
800 if (!NameOfWrappedPass.empty())
801 dbg() << " [" << NameOfWrappedPass << "]";
802 dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
803
804
805 bool Ret = false;
806 if (Strip)
808
809 return Ret;
810}
811
812
813
814struct DebugifyModulePass : public ModulePass {
817 applyDebugify(M, Mode, DebugInfoBeforePass, NameOfWrappedPass);
819 }
820
821 DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
822 StringRef NameOfWrappedPass = "",
824 : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
825 DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
826
829 }
830
831 static char ID;
832
833private:
837};
838
839
840
841struct DebugifyFunctionPass : public FunctionPass {
844 applyDebugify(F, Mode, DebugInfoBeforePass, NameOfWrappedPass);
846 }
847
848 DebugifyFunctionPass(
849 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
850 StringRef NameOfWrappedPass = "",
852 : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
853 DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
854
857 }
858
859 static char ID;
860
861private:
865};
866
867
868
869struct CheckDebugifyModulePass : public ModulePass {
872 if (Mode == DebugifyMode::SyntheticDebugInfo)
873 Result = checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
874 "CheckModuleDebugify", Strip, StatsMap);
875 else
877 M, M.functions(), *DebugInfoBeforePass,
878 "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
879 OrigDIVerifyBugsReportFilePath);
880
882 }
883
884 CheckDebugifyModulePass(
885 bool Strip = false, StringRef NameOfWrappedPass = "",
887 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
889 StringRef OrigDIVerifyBugsReportFilePath = "")
890 : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass),
891 OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
892 StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
893 Strip(Strip) {}
894
897 }
898
899 static char ID;
900
901private:
903 StringRef OrigDIVerifyBugsReportFilePath;
907 bool Strip;
908};
909
910
911
912struct CheckDebugifyFunctionPass : public FunctionPass {
915 auto FuncIt = F.getIterator();
917 if (Mode == DebugifyMode::SyntheticDebugInfo)
918 Result = checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
919 NameOfWrappedPass, "CheckFunctionDebugify",
920 Strip, StatsMap);
921 else
923 M, make_range(FuncIt, std::next(FuncIt)), *DebugInfoBeforePass,
924 "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass,
925 OrigDIVerifyBugsReportFilePath);
926
928 }
929
930 CheckDebugifyFunctionPass(
931 bool Strip = false, StringRef NameOfWrappedPass = "",
933 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
935 StringRef OrigDIVerifyBugsReportFilePath = "")
936 : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass),
937 OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
938 StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
939 Strip(Strip) {}
940
943 }
944
945 static char ID;
946
947private:
949 StringRef OrigDIVerifyBugsReportFilePath;
953 bool Strip;
954};
955
956}
957
959 std::error_code EC;
961 if (EC) {
962 errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
963 return;
964 }
965
966 OS << "Pass Name" << ',' << "# of missing debug values" << ','
967 << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
968 << "Missing/Expected location ratio" << '\n';
969 for (const auto &Entry : Map) {
972
973 OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
974 << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
975 << Stats.getEmptyLocationRatio() << '\n';
976 }
977}
978
983 return new DebugifyModulePass();
985 return new DebugifyModulePass(Mode, NameOfWrappedPass, DebugInfoBeforePass);
986}
987
993 return new DebugifyFunctionPass();
995 return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DebugInfoBeforePass);
996}
997
999 if (Mode == DebugifyMode::SyntheticDebugInfo)
1001 "ModuleDebugify: ", nullptr);
1002 else
1004 "ModuleDebugify (original debuginfo)",
1005 NameOfWrappedPass);
1006
1009 return PA;
1010}
1011
1015 StringRef OrigDIVerifyBugsReportFilePath) {
1017 return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
1019 return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode,
1020 DebugInfoBeforePass,
1021 OrigDIVerifyBugsReportFilePath);
1022}
1023
1027 StringRef OrigDIVerifyBugsReportFilePath) {
1029 return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
1031 return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode,
1032 DebugInfoBeforePass,
1033 OrigDIVerifyBugsReportFilePath);
1034}
1035
1038 if (Mode == DebugifyMode::SyntheticDebugInfo)
1039 checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
1040 "CheckModuleDebugify", Strip, StatsMap);
1041 else
1043 M, M.functions(), *DebugInfoBeforePass,
1044 "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass,
1045 OrigDIVerifyBugsReportFilePath);
1046
1048}
1049
1051 return isSpecialPass(PassID, {"PassManager", "PassAdaptor",
1052 "AnalysisManagerProxy", "PrintFunctionPass",
1053 "PrintModulePass", "BitcodeWriterPass",
1054 "ThinLTOBitcodeWriterPass", "VerifierPass"});
1055}
1056
1061 return;
1064 if (const auto **CF = llvm::any_cast<const Function *>(&IR)) {
1068 .getManager()
1069 .invalidate(F, PA);
1070 } else if (const auto **CM = llvm::any_cast<const Module *>(&IR)) {
1074 }
1075 });
1079 return;
1082 if (const auto **CF = llvm::any_cast<const Function *>(&IR)) {
1083 auto &F = *const_cast<Function *>(*CF);
1084 Module &M = *F.getParent();
1085 auto It = F.getIterator();
1086 if (Mode == DebugifyMode::SyntheticDebugInfo)
1087 checkDebugifyMetadata(M, make_range(It, std::next(It)), P,
1088 "CheckFunctionDebugify", true,
1089 DIStatsMap);
1090 else
1092 *DebugInfoBeforePass,
1093 "CheckModuleDebugify (original debuginfo)",
1094 P, OrigDIVerifyBugsReportFilePath);
1096 .getManager()
1097 .invalidate(F, PA);
1098 } else if (const auto **CM = llvm::any_cast<const Module *>(&IR)) {
1100 if (Mode == DebugifyMode::SyntheticDebugInfo)
1101 checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify",
1102 true, DIStatsMap);
1103 else
1105 "CheckModuleDebugify (original debuginfo)",
1106 P, OrigDIVerifyBugsReportFilePath);
1108 }
1109 });
1110}
1111
1112char DebugifyModulePass::ID = 0;
1114 "Attach debug info to everything");
1115
1116char CheckDebugifyModulePass::ID = 0;
1118 CDM("check-debugify", "Check debug info from -debugify");
1119
1120char DebugifyFunctionPass::ID = 0;
1122 "Attach debug info to a function");
1123
1124char CheckDebugifyFunctionPass::ID = 0;
1126 CDF("check-debugify-function", "Check debug info from -debugify-function");
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
This file implements the BitVector class.
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static DISubprogram * getSubprogram(bool IsDistinct, Ts &&...Args)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static RegisterPass< CheckDebugifyModulePass > CDM("check-debugify", "Check debug info from -debugify")
ModulePass * createDebugifyModulePass(enum DebugifyMode Mode, llvm::StringRef NameOfWrappedPass, DebugInfoPerPass *DebugInfoBeforePass)
FunctionPass * createDebugifyFunctionPass(enum DebugifyMode Mode, llvm::StringRef NameOfWrappedPass, DebugInfoPerPass *DebugInfoBeforePass)
static bool isIgnoredPass(StringRef PassID)
static bool applyDebugify(Function &F, enum DebugifyMode Mode=DebugifyMode::SyntheticDebugInfo, DebugInfoPerPass *DebugInfoBeforePass=nullptr, StringRef NameOfWrappedPass="")
ModulePass * createCheckDebugifyModulePass(bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass, StringRef OrigDIVerifyBugsReportFilePath)
static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath, StringRef FileNameFromCU, StringRef NameOfWrappedPass, llvm::json::Array &Bugs)
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, const DebugFnMap &DIFunctionsAfter, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)
static RegisterPass< CheckDebugifyFunctionPass > CDF("check-debugify-function", "Check debug info from -debugify-function")
FunctionPass * createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, enum DebugifyMode Mode, DebugInfoPerPass *DebugInfoBeforePass, StringRef OrigDIVerifyBugsReportFilePath)
static bool checkVars(const DebugVarMap &DIVarsBefore, const DebugVarMap &DIVarsAfter, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)
static bool checkInstructions(const DebugInstMap &DILocsBefore, const DebugInstMap &DILocsAfter, const WeakInstValueMap &InstToDelete, StringRef NameOfWrappedPass, StringRef FileNameFromCU, bool ShouldWriteIntoJSON, llvm::json::Array &Bugs)
DebugifyMode
Used to check whether we track synthetic or original debug info.
static SmallString< 128 > getFilename(const DISubprogram *SP)
Extract a filename for a DISubprogram.
Module.h This file contains the declarations for the Module class.
This file supports working with JSON data.
Legalize the Machine IR a function s Machine IR
block placement Basic Block Placement Stats
ModuleAnalysisManager MAM
PassInstrumentationCallbacks PIC
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const char PassName[]
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM)
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM)
A container for analyses that lazily runs them and caches their results.
void invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Invalidate cached analyses for an IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
LLVM Basic Block Representation.
const CallInst * getTerminatingDeoptimizeCall() const
Returns the call instruction calling @llvm.experimental.deoptimize prior to the terminating return in...
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
const CallInst * getTerminatingMustTailCall() const
Returns the call instruction marked 'musttail' prior to the terminating return instruction of this ba...
Represents analyses that only rely on functions' control flow.
void finalize()
Construct any deferred debug info descriptors.
DISubroutineType * createSubroutineType(DITypeRefArray ParameterTypes, DINode::DIFlags Flags=DINode::FlagZero, unsigned CC=0)
Create subroutine type.
void finalizeSubprogram(DISubprogram *SP)
Finalize a specific subprogram - no new variables may be added to this subprogram afterwards.
DICompileUnit * createCompileUnit(unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName=StringRef(), DICompileUnit::DebugEmissionKind Kind=DICompileUnit::DebugEmissionKind::FullDebug, uint64_t DWOId=0, bool SplitDebugInlining=true, bool DebugInfoForProfiling=false, DICompileUnit::DebugNameTableKind NameTableKind=DICompileUnit::DebugNameTableKind::Default, bool RangesBaseAddress=false, StringRef SysRoot={}, StringRef SDK={})
A CompileUnit provides an anchor for all debugging information generated during this instance of comp...
DISubprogram * createFunction(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, DINode::DIFlags Flags=DINode::FlagZero, DISubprogram::DISPFlags SPFlags=DISubprogram::SPFlagZero, DITemplateParameterArray TParams=nullptr, DISubprogram *Decl=nullptr, DITypeArray ThrownTypes=nullptr, DINodeArray Annotations=nullptr, StringRef TargetFuncName="")
Create a new descriptor for the specified subprogram.
DIBasicType * createBasicType(StringRef Name, uint64_t SizeInBits, unsigned Encoding, DINode::DIFlags Flags=DINode::FlagZero, uint32_t NumExtraInhabitants=0)
Create debugging information entry for a basic type.
DITypeRefArray getOrCreateTypeArray(ArrayRef< Metadata * > Elements)
Get a DITypeRefArray, create one if required.
DIExpression * createExpression(ArrayRef< uint64_t > Addr={})
Create a new descriptor for the specified variable which has a complex address expression for its add...
DILocalVariable * createAutoVariable(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve=false, DINode::DIFlags Flags=DINode::FlagZero, uint32_t AlignInBits=0)
Create a new descriptor for an auto variable.
DIFile * createFile(StringRef Filename, StringRef Directory, std::optional< DIFile::ChecksumInfo< StringRef > > Checksum=std::nullopt, std::optional< StringRef > Source=std::nullopt)
Create a file descriptor to hold debugging information for a file.
Tagged DWARF-like metadata node.
DISPFlags
Debug info subprogram flags.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
DILocation * get() const
Get the underlying DILocation.
void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM)
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const char * getOpcodeName() const
This is an important class for using LLVM in a threaded context.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
size_type count(const KeyT &Key) const
iterator find(const KeyT &Key)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
@ Warning
Emits a warning if two values disagree.
void eraseFromParent()
Drop all references and remove the node from parent module.
MDNode * getOperand(unsigned i) const
unsigned getNumOperands() const
void clearOperands()
Drop all references to this node's operands.
iterator_range< op_iterator > operands()
void addOperand(MDNode *M)
Pass interface - Implemented by all 'passes'.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
static IntegerType * getInt32Ty(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
A range adaptor for a pair of iterators.
An Array is a JSON array, which contains heterogeneous JSON values.
void push_back(const Value &E)
An Object is a JSON object, which maps strings to heterogenous JSON values.
A Value is an JSON value of unknown type.
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
@ OF_Append
The file should be opened in append mode.
This is an optimization pass for GlobalISel generic memory operations.
bool applyDebugifyMetadata(Module &M, iterator_range< Module::iterator > Functions, StringRef Banner, std::function< bool(DIBuilder &, Function &)> ApplyToMF)
Add synthesized debug information to a module.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool stripDebugifyMetadata(Module &M)
Strip out all of the metadata and debug info inserted by debugify.
void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map)
bool collectDebugInfoMetadata(Module &M, iterator_range< Module::iterator > Functions, DebugInfoPerPass &DebugInfoBeforePass, StringRef Banner, StringRef NameOfWrappedPass)
Collect original debug information before a pass.
bool checkDebugInfoMetadata(Module &M, iterator_range< Module::iterator > Functions, DebugInfoPerPass &DebugInfoBeforePass, StringRef Banner, StringRef NameOfWrappedPass, StringRef OrigDIVerifyBugsReportFilePath)
Check original debug information after a pass.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isSpecialPass(StringRef PassID, const std::vector< StringRef > &Specials)
raw_ostream & nulls()
This returns a reference to a raw_ostream which simply discards output.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool StripDebugInfo(Module &M)
Strip debug info in the module if it exists.
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
Used to track the Debug Info Metadata information.
WeakInstValueMap InstToDelete
Track how much debugify information (in the synthetic mode only) has been lost.
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
void registerBeforeNonSkippedPassCallback(CallableT C)
void registerAfterPassCallback(CallableT C, bool ToFront=false)
RegisterPass template - This template class is used to notify the system that a Pass is available ...