xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Transforms/Utils/Debugify.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- Debugify.h - 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 Interface to the `debugify` synthetic/original debug info testing
10 /// utility.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
15 #define LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
16 
17 #include "llvm/ADT/MapVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Bitcode/BitcodeWriterPass.h"
20 #include "llvm/IR/IRPrintingPasses.h"
21 #include "llvm/IR/LegacyPassManager.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/IR/PassInstrumentation.h"
24 #include "llvm/IR/PassManager.h"
25 #include "llvm/IR/ValueHandle.h"
26 #include "llvm/Pass.h"
27 
28 using DebugFnMap =
29     llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>;
30 using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>;
31 using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>;
32 using WeakInstValueMap =
33     llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>;
34 
35 /// Used to track the Debug Info Metadata information.
36 struct DebugInfoPerPass {
37   // This maps a function name to its associated DISubprogram.
38   DebugFnMap DIFunctions;
39   // This maps an instruction and the info about whether it has !dbg attached.
40   DebugInstMap DILocations;
41   // This tracks value (instruction) deletion. If an instruction gets deleted,
42   // WeakVH nulls itself.
43   WeakInstValueMap InstToDelete;
44   // Maps variable into dbg users (#dbg values/declares for this variable).
45   DebugVarMap DIVariables;
46 };
47 
48 namespace llvm {
49 class DIBuilder;
50 
51 /// Add synthesized debug information to a module.
52 ///
53 /// \param M The module to add debug information to.
54 /// \param Functions A range of functions to add debug information to.
55 /// \param Banner A prefix string to add to debug/error messages.
56 /// \param ApplyToMF A call back that will add debug information to the
57 ///                  MachineFunction for a Function. If nullptr, then the
58 ///                  MachineFunction (if any) will not be modified.
59 bool applyDebugifyMetadata(
60     Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
61     std::function<bool(DIBuilder &, Function &)> ApplyToMF);
62 
63 /// Strip out all of the metadata and debug info inserted by debugify. If no
64 /// llvm.debugify module-level named metadata is present, this is a no-op.
65 /// Returns true if any change was made.
66 bool stripDebugifyMetadata(Module &M);
67 
68 /// Collect original debug information before a pass.
69 ///
70 /// \param M The module to collect debug information from.
71 /// \param Functions A range of functions to collect debug information from.
72 /// \param DebugInfoBeforePass DI metadata before a pass.
73 /// \param Banner A prefix string to add to debug/error messages.
74 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
75 bool collectDebugInfoMetadata(Module &M,
76                               iterator_range<Module::iterator> Functions,
77                               DebugInfoPerPass &DebugInfoBeforePass,
78                               StringRef Banner, StringRef NameOfWrappedPass);
79 
80 /// Check original debug information after a pass.
81 ///
82 /// \param M The module to collect debug information from.
83 /// \param Functions A range of functions to collect debug information from.
84 /// \param DebugInfoBeforePass DI metadata before a pass.
85 /// \param Banner A prefix string to add to debug/error messages.
86 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
87 bool checkDebugInfoMetadata(Module &M,
88                             iterator_range<Module::iterator> Functions,
89                             DebugInfoPerPass &DebugInfoBeforePass,
90                             StringRef Banner, StringRef NameOfWrappedPass,
91                             StringRef OrigDIVerifyBugsReportFilePath);
92 } // namespace llvm
93 
94 /// Used to check whether we track synthetic or original debug info.
95 enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
96 
97 llvm::ModulePass *createDebugifyModulePass(
98     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
99     llvm::StringRef NameOfWrappedPass = "",
100     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
101 llvm::FunctionPass *createDebugifyFunctionPass(
102     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
103     llvm::StringRef NameOfWrappedPass = "",
104     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
105 
106 class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
107   llvm::StringRef NameOfWrappedPass;
108   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
109   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
110 public:
111   NewPMDebugifyPass(
112       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
113       llvm::StringRef NameOfWrappedPass = "",
114       DebugInfoPerPass *DebugInfoBeforePass = nullptr)
NameOfWrappedPass(NameOfWrappedPass)115       : NameOfWrappedPass(NameOfWrappedPass),
116         DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
117 
118   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
119 };
120 
121 /// Track how much `debugify` information (in the `synthetic` mode only)
122 /// has been lost.
123 struct DebugifyStatistics {
124   /// Number of missing dbg.values.
125   unsigned NumDbgValuesMissing = 0;
126 
127   /// Number of dbg.values expected.
128   unsigned NumDbgValuesExpected = 0;
129 
130   /// Number of instructions with empty debug locations.
131   unsigned NumDbgLocsMissing = 0;
132 
133   /// Number of instructions expected to have debug locations.
134   unsigned NumDbgLocsExpected = 0;
135 
136   /// Get the ratio of missing/expected dbg.values.
getMissingValueRatioDebugifyStatistics137   float getMissingValueRatio() const {
138     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
139   }
140 
141   /// Get the ratio of missing/expected instructions with locations.
getEmptyLocationRatioDebugifyStatistics142   float getEmptyLocationRatio() const {
143     return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
144   }
145 };
146 
147 /// Map pass names to a per-pass DebugifyStatistics instance.
148 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
149 
150 llvm::ModulePass *createCheckDebugifyModulePass(
151     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
152     DebugifyStatsMap *StatsMap = nullptr,
153     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
154     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
155     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
156 
157 llvm::FunctionPass *createCheckDebugifyFunctionPass(
158     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
159     DebugifyStatsMap *StatsMap = nullptr,
160     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
161     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
162     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
163 
164 class NewPMCheckDebugifyPass
165     : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
166   llvm::StringRef NameOfWrappedPass;
167   llvm::StringRef OrigDIVerifyBugsReportFilePath;
168   DebugifyStatsMap *StatsMap;
169   DebugInfoPerPass *DebugInfoBeforePass;
170   enum DebugifyMode Mode;
171   bool Strip;
172 public:
173   NewPMCheckDebugifyPass(
174       bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
175       DebugifyStatsMap *StatsMap = nullptr,
176       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
177       DebugInfoPerPass *DebugInfoBeforePass = nullptr,
178       llvm::StringRef OrigDIVerifyBugsReportFilePath = "")
NameOfWrappedPass(NameOfWrappedPass)179       : NameOfWrappedPass(NameOfWrappedPass),
180         OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
181         StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
182         Strip(Strip) {}
183 
184   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
185 };
186 
187 namespace llvm {
188 void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
189 
190 class DebugifyEachInstrumentation {
191   llvm::StringRef OrigDIVerifyBugsReportFilePath = "";
192   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
193   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
194   DebugifyStatsMap *DIStatsMap = nullptr;
195 
196 public:
197   void registerCallbacks(PassInstrumentationCallbacks &PIC,
198                          ModuleAnalysisManager &MAM);
199   // Used within DebugifyMode::SyntheticDebugInfo mode.
setDIStatsMap(DebugifyStatsMap & StatMap)200   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
getDebugifyStatsMap()201   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
202   // Used within DebugifyMode::OriginalDebugInfo mode.
setDebugInfoBeforePass(DebugInfoPerPass & PerPassMap)203   void setDebugInfoBeforePass(DebugInfoPerPass &PerPassMap) {
204     DebugInfoBeforePass = &PerPassMap;
205   }
getDebugInfoPerPass()206   DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; }
207 
setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath)208   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
209     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
210   }
getOrigDIVerifyBugsReportFilePath()211   StringRef getOrigDIVerifyBugsReportFilePath() const {
212     return OrigDIVerifyBugsReportFilePath;
213   }
214 
setDebugifyMode(enum DebugifyMode M)215   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
216 
isSyntheticDebugInfo()217   bool isSyntheticDebugInfo() const {
218     return Mode == DebugifyMode::SyntheticDebugInfo;
219   }
isOriginalDebugInfoMode()220   bool isOriginalDebugInfoMode() const {
221     return Mode == DebugifyMode::OriginalDebugInfo;
222   }
223 };
224 
225 /// DebugifyCustomPassManager wraps each pass with the debugify passes if
226 /// needed.
227 /// NOTE: We support legacy custom pass manager only.
228 /// TODO: Add New PM support for custom pass manager.
229 class DebugifyCustomPassManager : public legacy::PassManager {
230   StringRef OrigDIVerifyBugsReportFilePath;
231   DebugifyStatsMap *DIStatsMap = nullptr;
232   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
233   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
234 
235 public:
236   using super = legacy::PassManager;
237 
add(Pass * P)238   void add(Pass *P) override {
239     // Wrap each pass with (-check)-debugify passes if requested, making
240     // exceptions for passes which shouldn't see -debugify instrumentation.
241     bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify &&
242                             !P->getAsImmutablePass() && !isIRPrintingPass(P) &&
243                             !isBitcodeWriterPass(P);
244     if (!WrapWithDebugify) {
245       super::add(P);
246       return;
247     }
248 
249     // Either apply -debugify/-check-debugify before/after each pass and collect
250     // debug info loss statistics, or collect and check original debug info in
251     // the optimizations.
252     PassKind Kind = P->getPassKind();
253     StringRef Name = P->getPassName();
254 
255     // TODO: Implement Debugify for LoopPass.
256     switch (Kind) {
257     case PT_Function:
258       super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass));
259       super::add(P);
260       super::add(createCheckDebugifyFunctionPass(
261           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
262           OrigDIVerifyBugsReportFilePath));
263       break;
264     case PT_Module:
265       super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass));
266       super::add(P);
267       super::add(createCheckDebugifyModulePass(
268           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
269           OrigDIVerifyBugsReportFilePath));
270       break;
271     default:
272       super::add(P);
273       break;
274     }
275   }
276 
277   // Used within DebugifyMode::SyntheticDebugInfo mode.
setDIStatsMap(DebugifyStatsMap & StatMap)278   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
279   // Used within DebugifyMode::OriginalDebugInfo mode.
setDebugInfoBeforePass(DebugInfoPerPass & PerPassDI)280   void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) {
281     DebugInfoBeforePass = &PerPassDI;
282   }
setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath)283   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
284     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
285   }
getOrigDIVerifyBugsReportFilePath()286   StringRef getOrigDIVerifyBugsReportFilePath() const {
287     return OrigDIVerifyBugsReportFilePath;
288   }
289 
setDebugifyMode(enum DebugifyMode M)290   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
291 
isSyntheticDebugInfo()292   bool isSyntheticDebugInfo() const {
293     return Mode == DebugifyMode::SyntheticDebugInfo;
294   }
isOriginalDebugInfoMode()295   bool isOriginalDebugInfoMode() const {
296     return Mode == DebugifyMode::OriginalDebugInfo;
297   }
298 
getDebugifyStatsMap()299   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
getDebugInfoPerPass()300   DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; }
301 };
302 } // namespace llvm
303 
304 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
305