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
26using DebugFnMap =
27 llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>;
28using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>;
29using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>;
30using WeakInstValueMap =
31 llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>;
32
33/// Used to track the Debug Info Metadata information.
34struct 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
46namespace llvm {
47class 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.
57bool 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.
64bool 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.
73bool 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.
85bool 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.
93enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
94
95llvm::ModulePass *createDebugifyModulePass(
96 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
97 llvm::StringRef NameOfWrappedPass = "",
98 DebugInfoPerPass *DebugInfoBeforePass = nullptr);
99llvm::FunctionPass *createDebugifyFunctionPass(
100 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
101 llvm::StringRef NameOfWrappedPass = "",
102 DebugInfoPerPass *DebugInfoBeforePass = nullptr);
103
104class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
105 llvm::StringRef NameOfWrappedPass;
106 DebugInfoPerPass *DebugInfoBeforePass = nullptr;
107 enum DebugifyMode Mode = DebugifyMode::NoDebugify;
108public:
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.
121struct 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.
146using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
147
148llvm::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
155llvm::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
162class 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;
170public:
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
185namespace llvm {
186void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
187
188class DebugifyEachInstrumentation {
189 llvm::StringRef OrigDIVerifyBugsReportFilePath = "";
190 DebugInfoPerPass *DebugInfoBeforePass = nullptr;
191 enum DebugifyMode Mode = DebugifyMode::NoDebugify;
192 DebugifyStatsMap *DIStatsMap = nullptr;
193
194public:
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.
227class DebugifyCustomPassManager : public legacy::PassManager {
228 StringRef OrigDIVerifyBugsReportFilePath;
229 DebugifyStatsMap *DIStatsMap = nullptr;
230 DebugInfoPerPass *DebugInfoBeforePass = nullptr;
231 enum DebugifyMode Mode = DebugifyMode::NoDebugify;
232
233public:
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(P: createDebugifyFunctionPass(Mode, NameOfWrappedPass: Name, DebugInfoBeforePass));
257 super::add(P);
258 super::add(P: createCheckDebugifyFunctionPass(
259 Strip: isSyntheticDebugInfo(), NameOfWrappedPass: Name, StatsMap: DIStatsMap, Mode, DebugInfoBeforePass,
260 OrigDIVerifyBugsReportFilePath));
261 break;
262 case PT_Module:
263 super::add(P: createDebugifyModulePass(Mode, NameOfWrappedPass: Name, DebugInfoBeforePass));
264 super::add(P);
265 super::add(P: createCheckDebugifyModulePass(
266 Strip: isSyntheticDebugInfo(), NameOfWrappedPass: Name, StatsMap: 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

source code of llvm/include/llvm/Transforms/Utils/Debugify.h