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