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
26using DebugFnMap = llvm::DenseMap<llvm::StringRef, const llvm::DISubprogram *>;
27using DebugInstMap = llvm::DenseMap<const llvm::Instruction *, bool>;
28using WeakInstValueMap =
29 llvm::DenseMap<const llvm::Instruction *, llvm::WeakVH>;
30
31/// Used to track the Debug Info Metadata information.
32struct 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.
43using DebugInfoPerPassMap = llvm::MapVector<llvm::StringRef, DebugInfoPerPass>;
44
45namespace llvm {
46class 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.
56bool 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.
63bool 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.
72bool 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.
84bool 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.
92enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
93
94llvm::ModulePass *createDebugifyModulePass(
95 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
96 llvm::StringRef NameOfWrappedPass = "",
97 DebugInfoPerPassMap *DIPreservationMap = nullptr);
98llvm::FunctionPass *createDebugifyFunctionPass(
99 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
100 llvm::StringRef NameOfWrappedPass = "",
101 DebugInfoPerPassMap *DIPreservationMap = nullptr);
102
103struct 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.
109struct 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.
134using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
135
136llvm::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
143llvm::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
150struct NewPMCheckDebugifyPass
151 : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
152 llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
153};
154
155namespace llvm {
156void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
157
158struct 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.
168class DebugifyCustomPassManager : public legacy::PassManager {
169 StringRef OrigDIVerifyBugsReportFilePath;
170 DebugifyStatsMap *DIStatsMap = nullptr;
171 DebugInfoPerPassMap *DIPreservationMap = nullptr;
172 enum DebugifyMode Mode = DebugifyMode::NoDebugify;
173
174public:
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