xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Transforms/Utils/Debugify.h (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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 
26 using DebugFnMap =
27     llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>;
28 using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>;
29 using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>;
30 using WeakInstValueMap =
31     llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>;
32 
33 /// Used to track the Debug Info Metadata information.
34 struct 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 
46 namespace llvm {
47 class 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.
57 bool 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.
64 bool 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.
73 bool 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.
85 bool 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.
93 enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
94 
95 llvm::ModulePass *createDebugifyModulePass(
96     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
97     llvm::StringRef NameOfWrappedPass = "",
98     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
99 llvm::FunctionPass *createDebugifyFunctionPass(
100     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
101     llvm::StringRef NameOfWrappedPass = "",
102     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
103 
104 struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
105   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
106 };
107 
108 /// Track how much `debugify` information (in the `synthetic` mode only)
109 /// has been lost.
110 struct DebugifyStatistics {
111   /// Number of missing dbg.values.
112   unsigned NumDbgValuesMissing = 0;
113 
114   /// Number of dbg.values expected.
115   unsigned NumDbgValuesExpected = 0;
116 
117   /// Number of instructions with empty debug locations.
118   unsigned NumDbgLocsMissing = 0;
119 
120   /// Number of instructions expected to have debug locations.
121   unsigned NumDbgLocsExpected = 0;
122 
123   /// Get the ratio of missing/expected dbg.values.
124   float getMissingValueRatio() const {
125     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
126   }
127 
128   /// Get the ratio of missing/expected instructions with locations.
129   float getEmptyLocationRatio() const {
130     return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
131   }
132 };
133 
134 /// Map pass names to a per-pass DebugifyStatistics instance.
135 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
136 
137 llvm::ModulePass *createCheckDebugifyModulePass(
138     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
139     DebugifyStatsMap *StatsMap = nullptr,
140     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
141     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
142     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
143 
144 llvm::FunctionPass *createCheckDebugifyFunctionPass(
145     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
146     DebugifyStatsMap *StatsMap = nullptr,
147     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
148     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
149     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
150 
151 struct NewPMCheckDebugifyPass
152     : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
153   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
154 };
155 
156 namespace llvm {
157 void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
158 
159 struct DebugifyEachInstrumentation {
160   DebugifyStatsMap StatsMap;
161 
162   void registerCallbacks(PassInstrumentationCallbacks &PIC);
163 };
164 
165 /// DebugifyCustomPassManager wraps each pass with the debugify passes if
166 /// needed.
167 /// NOTE: We support legacy custom pass manager only.
168 /// TODO: Add New PM support for custom pass manager.
169 class DebugifyCustomPassManager : public legacy::PassManager {
170   StringRef OrigDIVerifyBugsReportFilePath;
171   DebugifyStatsMap *DIStatsMap = nullptr;
172   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
173   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
174 
175 public:
176   using super = legacy::PassManager;
177 
178   void add(Pass *P) override {
179     // Wrap each pass with (-check)-debugify passes if requested, making
180     // exceptions for passes which shouldn't see -debugify instrumentation.
181     bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify &&
182                             !P->getAsImmutablePass() && !isIRPrintingPass(P) &&
183                             !isBitcodeWriterPass(P);
184     if (!WrapWithDebugify) {
185       super::add(P);
186       return;
187     }
188 
189     // Either apply -debugify/-check-debugify before/after each pass and collect
190     // debug info loss statistics, or collect and check original debug info in
191     // the optimizations.
192     PassKind Kind = P->getPassKind();
193     StringRef Name = P->getPassName();
194 
195     // TODO: Implement Debugify for LoopPass.
196     switch (Kind) {
197     case PT_Function:
198       super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass));
199       super::add(P);
200       super::add(createCheckDebugifyFunctionPass(
201           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
202           OrigDIVerifyBugsReportFilePath));
203       break;
204     case PT_Module:
205       super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass));
206       super::add(P);
207       super::add(createCheckDebugifyModulePass(
208           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
209           OrigDIVerifyBugsReportFilePath));
210       break;
211     default:
212       super::add(P);
213       break;
214     }
215   }
216 
217   // Used within DebugifyMode::SyntheticDebugInfo mode.
218   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
219   // Used within DebugifyMode::OriginalDebugInfo mode.
220   void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) {
221     DebugInfoBeforePass = &PerPassDI;
222   }
223   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
224     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
225   }
226   StringRef getOrigDIVerifyBugsReportFilePath() const {
227     return OrigDIVerifyBugsReportFilePath;
228   }
229 
230   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
231 
232   bool isSyntheticDebugInfo() const {
233     return Mode == DebugifyMode::SyntheticDebugInfo;
234   }
235   bool isOriginalDebugInfoMode() const {
236     return Mode == DebugifyMode::OriginalDebugInfo;
237   }
238 
239   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
240   DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; }
241 };
242 } // namespace llvm
243 
244 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
245