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 | |