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