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