xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Transforms/Utils/Debugify.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1fe6060f1SDimitry Andric //===- Debugify.h - Check debug info preservation in optimizations --------===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file Interface to the `debugify` synthetic/original debug info testing
10fe6060f1SDimitry Andric /// utility.
11480093f4SDimitry Andric ///
12480093f4SDimitry Andric //===----------------------------------------------------------------------===//
13480093f4SDimitry Andric 
14fe6060f1SDimitry Andric #ifndef LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
15fe6060f1SDimitry Andric #define LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
16480093f4SDimitry Andric 
17480093f4SDimitry Andric #include "llvm/ADT/MapVector.h"
18e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
19e8d8bef9SDimitry Andric #include "llvm/Bitcode/BitcodeWriterPass.h"
20e8d8bef9SDimitry Andric #include "llvm/IR/IRPrintingPasses.h"
21e8d8bef9SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
22*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/PassInstrumentation.h"
24480093f4SDimitry Andric #include "llvm/IR/PassManager.h"
25fe6060f1SDimitry Andric #include "llvm/IR/ValueHandle.h"
261fd87a68SDimitry Andric #include "llvm/Pass.h"
27fe6060f1SDimitry Andric 
2881ad6265SDimitry Andric using DebugFnMap =
2981ad6265SDimitry Andric     llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>;
30fe6060f1SDimitry Andric using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>;
31fe6060f1SDimitry Andric using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>;
32fe6060f1SDimitry Andric using WeakInstValueMap =
33fe6060f1SDimitry Andric     llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>;
34fe6060f1SDimitry Andric 
35fe6060f1SDimitry Andric /// Used to track the Debug Info Metadata information.
36fe6060f1SDimitry Andric struct DebugInfoPerPass {
37fe6060f1SDimitry Andric   // This maps a function name to its associated DISubprogram.
38fe6060f1SDimitry Andric   DebugFnMap DIFunctions;
39fe6060f1SDimitry Andric   // This maps an instruction and the info about whether it has !dbg attached.
40fe6060f1SDimitry Andric   DebugInstMap DILocations;
41fe6060f1SDimitry Andric   // This tracks value (instruction) deletion. If an instruction gets deleted,
42fe6060f1SDimitry Andric   // WeakVH nulls itself.
43fe6060f1SDimitry Andric   WeakInstValueMap InstToDelete;
44fe6060f1SDimitry Andric   // Maps variable into dbg users (#dbg values/declares for this variable).
45fe6060f1SDimitry Andric   DebugVarMap DIVariables;
46fe6060f1SDimitry Andric };
47fe6060f1SDimitry Andric 
485ffd83dbSDimitry Andric namespace llvm {
495ffd83dbSDimitry Andric class DIBuilder;
505ffd83dbSDimitry Andric 
515ffd83dbSDimitry Andric /// Add synthesized debug information to a module.
525ffd83dbSDimitry Andric ///
535ffd83dbSDimitry Andric /// \param M The module to add debug information to.
545ffd83dbSDimitry Andric /// \param Functions A range of functions to add debug information to.
555ffd83dbSDimitry Andric /// \param Banner A prefix string to add to debug/error messages.
565ffd83dbSDimitry Andric /// \param ApplyToMF A call back that will add debug information to the
575ffd83dbSDimitry Andric ///                  MachineFunction for a Function. If nullptr, then the
585ffd83dbSDimitry Andric ///                  MachineFunction (if any) will not be modified.
595ffd83dbSDimitry Andric bool applyDebugifyMetadata(
605ffd83dbSDimitry Andric     Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
615ffd83dbSDimitry Andric     std::function<bool(DIBuilder &, Function &)> ApplyToMF);
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric /// Strip out all of the metadata and debug info inserted by debugify. If no
645ffd83dbSDimitry Andric /// llvm.debugify module-level named metadata is present, this is a no-op.
655ffd83dbSDimitry Andric /// Returns true if any change was made.
665ffd83dbSDimitry Andric bool stripDebugifyMetadata(Module &M);
675ffd83dbSDimitry Andric 
68fe6060f1SDimitry Andric /// Collect original debug information before a pass.
69fe6060f1SDimitry Andric ///
70fe6060f1SDimitry Andric /// \param M The module to collect debug information from.
71fe6060f1SDimitry Andric /// \param Functions A range of functions to collect debug information from.
7281ad6265SDimitry Andric /// \param DebugInfoBeforePass DI metadata before a pass.
73fe6060f1SDimitry Andric /// \param Banner A prefix string to add to debug/error messages.
74fe6060f1SDimitry Andric /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
75fe6060f1SDimitry Andric bool collectDebugInfoMetadata(Module &M,
76fe6060f1SDimitry Andric                               iterator_range<Module::iterator> Functions,
7781ad6265SDimitry Andric                               DebugInfoPerPass &DebugInfoBeforePass,
78fe6060f1SDimitry Andric                               StringRef Banner, StringRef NameOfWrappedPass);
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric /// Check original debug information after a pass.
81fe6060f1SDimitry Andric ///
82fe6060f1SDimitry Andric /// \param M The module to collect debug information from.
83fe6060f1SDimitry Andric /// \param Functions A range of functions to collect debug information from.
8481ad6265SDimitry Andric /// \param DebugInfoBeforePass DI metadata before a pass.
85fe6060f1SDimitry Andric /// \param Banner A prefix string to add to debug/error messages.
86fe6060f1SDimitry Andric /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
87fe6060f1SDimitry Andric bool checkDebugInfoMetadata(Module &M,
88fe6060f1SDimitry Andric                             iterator_range<Module::iterator> Functions,
8981ad6265SDimitry Andric                             DebugInfoPerPass &DebugInfoBeforePass,
90fe6060f1SDimitry Andric                             StringRef Banner, StringRef NameOfWrappedPass,
91fe6060f1SDimitry Andric                             StringRef OrigDIVerifyBugsReportFilePath);
92fe6060f1SDimitry Andric } // namespace llvm
93fe6060f1SDimitry Andric 
94fe6060f1SDimitry Andric /// Used to check whether we track synthetic or original debug info.
95fe6060f1SDimitry Andric enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric llvm::ModulePass *createDebugifyModulePass(
98fe6060f1SDimitry Andric     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
99fe6060f1SDimitry Andric     llvm::StringRef NameOfWrappedPass = "",
10081ad6265SDimitry Andric     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
101fe6060f1SDimitry Andric llvm::FunctionPass *createDebugifyFunctionPass(
102fe6060f1SDimitry Andric     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
103fe6060f1SDimitry Andric     llvm::StringRef NameOfWrappedPass = "",
10481ad6265SDimitry Andric     DebugInfoPerPass *DebugInfoBeforePass = nullptr);
105480093f4SDimitry Andric 
106753f127fSDimitry Andric class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
107753f127fSDimitry Andric   llvm::StringRef NameOfWrappedPass;
108753f127fSDimitry Andric   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
109753f127fSDimitry Andric   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
110753f127fSDimitry Andric public:
111753f127fSDimitry Andric   NewPMDebugifyPass(
112753f127fSDimitry Andric       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
113753f127fSDimitry Andric       llvm::StringRef NameOfWrappedPass = "",
114753f127fSDimitry Andric       DebugInfoPerPass *DebugInfoBeforePass = nullptr)
115753f127fSDimitry Andric       : NameOfWrappedPass(NameOfWrappedPass),
116753f127fSDimitry Andric         DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {}
117753f127fSDimitry Andric 
118480093f4SDimitry Andric   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
119480093f4SDimitry Andric };
120480093f4SDimitry Andric 
121fe6060f1SDimitry Andric /// Track how much `debugify` information (in the `synthetic` mode only)
122fe6060f1SDimitry Andric /// has been lost.
123480093f4SDimitry Andric struct DebugifyStatistics {
124480093f4SDimitry Andric   /// Number of missing dbg.values.
125480093f4SDimitry Andric   unsigned NumDbgValuesMissing = 0;
126480093f4SDimitry Andric 
127480093f4SDimitry Andric   /// Number of dbg.values expected.
128480093f4SDimitry Andric   unsigned NumDbgValuesExpected = 0;
129480093f4SDimitry Andric 
130480093f4SDimitry Andric   /// Number of instructions with empty debug locations.
131480093f4SDimitry Andric   unsigned NumDbgLocsMissing = 0;
132480093f4SDimitry Andric 
133480093f4SDimitry Andric   /// Number of instructions expected to have debug locations.
134480093f4SDimitry Andric   unsigned NumDbgLocsExpected = 0;
135480093f4SDimitry Andric 
136480093f4SDimitry Andric   /// Get the ratio of missing/expected dbg.values.
137480093f4SDimitry Andric   float getMissingValueRatio() const {
138480093f4SDimitry Andric     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
139480093f4SDimitry Andric   }
140480093f4SDimitry Andric 
141480093f4SDimitry Andric   /// Get the ratio of missing/expected instructions with locations.
142480093f4SDimitry Andric   float getEmptyLocationRatio() const {
143480093f4SDimitry Andric     return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
144480093f4SDimitry Andric   }
145480093f4SDimitry Andric };
146480093f4SDimitry Andric 
147480093f4SDimitry Andric /// Map pass names to a per-pass DebugifyStatistics instance.
148480093f4SDimitry Andric using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
149480093f4SDimitry Andric 
150fe6060f1SDimitry Andric llvm::ModulePass *createCheckDebugifyModulePass(
151fe6060f1SDimitry Andric     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
152fe6060f1SDimitry Andric     DebugifyStatsMap *StatsMap = nullptr,
153fe6060f1SDimitry Andric     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
15481ad6265SDimitry Andric     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
155fe6060f1SDimitry Andric     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
156e8d8bef9SDimitry Andric 
157fe6060f1SDimitry Andric llvm::FunctionPass *createCheckDebugifyFunctionPass(
158fe6060f1SDimitry Andric     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
159fe6060f1SDimitry Andric     DebugifyStatsMap *StatsMap = nullptr,
160fe6060f1SDimitry Andric     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
16181ad6265SDimitry Andric     DebugInfoPerPass *DebugInfoBeforePass = nullptr,
162fe6060f1SDimitry Andric     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
163480093f4SDimitry Andric 
164753f127fSDimitry Andric class NewPMCheckDebugifyPass
165480093f4SDimitry Andric     : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
166753f127fSDimitry Andric   llvm::StringRef NameOfWrappedPass;
167753f127fSDimitry Andric   llvm::StringRef OrigDIVerifyBugsReportFilePath;
168753f127fSDimitry Andric   DebugifyStatsMap *StatsMap;
169753f127fSDimitry Andric   DebugInfoPerPass *DebugInfoBeforePass;
170753f127fSDimitry Andric   enum DebugifyMode Mode;
171753f127fSDimitry Andric   bool Strip;
172753f127fSDimitry Andric public:
173753f127fSDimitry Andric   NewPMCheckDebugifyPass(
174753f127fSDimitry Andric       bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
175753f127fSDimitry Andric       DebugifyStatsMap *StatsMap = nullptr,
176753f127fSDimitry Andric       enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
177753f127fSDimitry Andric       DebugInfoPerPass *DebugInfoBeforePass = nullptr,
178753f127fSDimitry Andric       llvm::StringRef OrigDIVerifyBugsReportFilePath = "")
179753f127fSDimitry Andric       : NameOfWrappedPass(NameOfWrappedPass),
180753f127fSDimitry Andric         OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath),
181753f127fSDimitry Andric         StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode),
182753f127fSDimitry Andric         Strip(Strip) {}
183753f127fSDimitry Andric 
184480093f4SDimitry Andric   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
185480093f4SDimitry Andric };
186480093f4SDimitry Andric 
187fe6060f1SDimitry Andric namespace llvm {
188fe6060f1SDimitry Andric void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
189fe6060f1SDimitry Andric 
190753f127fSDimitry Andric class DebugifyEachInstrumentation {
191753f127fSDimitry Andric   llvm::StringRef OrigDIVerifyBugsReportFilePath = "";
192753f127fSDimitry Andric   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
193753f127fSDimitry Andric   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
194753f127fSDimitry Andric   DebugifyStatsMap *DIStatsMap = nullptr;
195753f127fSDimitry Andric 
196753f127fSDimitry Andric public:
19706c3fb27SDimitry Andric   void registerCallbacks(PassInstrumentationCallbacks &PIC,
19806c3fb27SDimitry Andric                          ModuleAnalysisManager &MAM);
199753f127fSDimitry Andric   // Used within DebugifyMode::SyntheticDebugInfo mode.
200753f127fSDimitry Andric   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
201753f127fSDimitry Andric   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
202753f127fSDimitry Andric   // Used within DebugifyMode::OriginalDebugInfo mode.
203753f127fSDimitry Andric   void setDebugInfoBeforePass(DebugInfoPerPass &PerPassMap) {
204753f127fSDimitry Andric     DebugInfoBeforePass = &PerPassMap;
205753f127fSDimitry Andric   }
206753f127fSDimitry Andric   DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; }
207753f127fSDimitry Andric 
208753f127fSDimitry Andric   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
209753f127fSDimitry Andric     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
210753f127fSDimitry Andric   }
211753f127fSDimitry Andric   StringRef getOrigDIVerifyBugsReportFilePath() const {
212753f127fSDimitry Andric     return OrigDIVerifyBugsReportFilePath;
213753f127fSDimitry Andric   }
214753f127fSDimitry Andric 
215753f127fSDimitry Andric   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
216753f127fSDimitry Andric 
217753f127fSDimitry Andric   bool isSyntheticDebugInfo() const {
218753f127fSDimitry Andric     return Mode == DebugifyMode::SyntheticDebugInfo;
219753f127fSDimitry Andric   }
220753f127fSDimitry Andric   bool isOriginalDebugInfoMode() const {
221753f127fSDimitry Andric     return Mode == DebugifyMode::OriginalDebugInfo;
222753f127fSDimitry Andric   }
223e8d8bef9SDimitry Andric };
224e8d8bef9SDimitry Andric 
225e8d8bef9SDimitry Andric /// DebugifyCustomPassManager wraps each pass with the debugify passes if
226e8d8bef9SDimitry Andric /// needed.
227e8d8bef9SDimitry Andric /// NOTE: We support legacy custom pass manager only.
228e8d8bef9SDimitry Andric /// TODO: Add New PM support for custom pass manager.
229e8d8bef9SDimitry Andric class DebugifyCustomPassManager : public legacy::PassManager {
230fe6060f1SDimitry Andric   StringRef OrigDIVerifyBugsReportFilePath;
231fe6060f1SDimitry Andric   DebugifyStatsMap *DIStatsMap = nullptr;
23281ad6265SDimitry Andric   DebugInfoPerPass *DebugInfoBeforePass = nullptr;
233fe6060f1SDimitry Andric   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
234e8d8bef9SDimitry Andric 
235e8d8bef9SDimitry Andric public:
236e8d8bef9SDimitry Andric   using super = legacy::PassManager;
237e8d8bef9SDimitry Andric 
238e8d8bef9SDimitry Andric   void add(Pass *P) override {
239e8d8bef9SDimitry Andric     // Wrap each pass with (-check)-debugify passes if requested, making
240e8d8bef9SDimitry Andric     // exceptions for passes which shouldn't see -debugify instrumentation.
241fe6060f1SDimitry Andric     bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify &&
242fe6060f1SDimitry Andric                             !P->getAsImmutablePass() && !isIRPrintingPass(P) &&
243fe6060f1SDimitry Andric                             !isBitcodeWriterPass(P);
244e8d8bef9SDimitry Andric     if (!WrapWithDebugify) {
245e8d8bef9SDimitry Andric       super::add(P);
246e8d8bef9SDimitry Andric       return;
247e8d8bef9SDimitry Andric     }
248e8d8bef9SDimitry Andric 
249fe6060f1SDimitry Andric     // Either apply -debugify/-check-debugify before/after each pass and collect
250fe6060f1SDimitry Andric     // debug info loss statistics, or collect and check original debug info in
251fe6060f1SDimitry Andric     // the optimizations.
252e8d8bef9SDimitry Andric     PassKind Kind = P->getPassKind();
253e8d8bef9SDimitry Andric     StringRef Name = P->getPassName();
254e8d8bef9SDimitry Andric 
255e8d8bef9SDimitry Andric     // TODO: Implement Debugify for LoopPass.
256e8d8bef9SDimitry Andric     switch (Kind) {
257e8d8bef9SDimitry Andric     case PT_Function:
25881ad6265SDimitry Andric       super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass));
259e8d8bef9SDimitry Andric       super::add(P);
260fe6060f1SDimitry Andric       super::add(createCheckDebugifyFunctionPass(
26181ad6265SDimitry Andric           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
262fe6060f1SDimitry Andric           OrigDIVerifyBugsReportFilePath));
263e8d8bef9SDimitry Andric       break;
264e8d8bef9SDimitry Andric     case PT_Module:
26581ad6265SDimitry Andric       super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass));
266e8d8bef9SDimitry Andric       super::add(P);
267fe6060f1SDimitry Andric       super::add(createCheckDebugifyModulePass(
26881ad6265SDimitry Andric           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass,
269fe6060f1SDimitry Andric           OrigDIVerifyBugsReportFilePath));
270e8d8bef9SDimitry Andric       break;
271e8d8bef9SDimitry Andric     default:
272e8d8bef9SDimitry Andric       super::add(P);
273e8d8bef9SDimitry Andric       break;
274e8d8bef9SDimitry Andric     }
275e8d8bef9SDimitry Andric   }
276e8d8bef9SDimitry Andric 
277fe6060f1SDimitry Andric   // Used within DebugifyMode::SyntheticDebugInfo mode.
278fe6060f1SDimitry Andric   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
279fe6060f1SDimitry Andric   // Used within DebugifyMode::OriginalDebugInfo mode.
28081ad6265SDimitry Andric   void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) {
28181ad6265SDimitry Andric     DebugInfoBeforePass = &PerPassDI;
282fe6060f1SDimitry Andric   }
283fe6060f1SDimitry Andric   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
284fe6060f1SDimitry Andric     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
285fe6060f1SDimitry Andric   }
286fe6060f1SDimitry Andric   StringRef getOrigDIVerifyBugsReportFilePath() const {
287fe6060f1SDimitry Andric     return OrigDIVerifyBugsReportFilePath;
288fe6060f1SDimitry Andric   }
289e8d8bef9SDimitry Andric 
290fe6060f1SDimitry Andric   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
291fe6060f1SDimitry Andric 
292fe6060f1SDimitry Andric   bool isSyntheticDebugInfo() const {
293fe6060f1SDimitry Andric     return Mode == DebugifyMode::SyntheticDebugInfo;
294fe6060f1SDimitry Andric   }
295fe6060f1SDimitry Andric   bool isOriginalDebugInfoMode() const {
296fe6060f1SDimitry Andric     return Mode == DebugifyMode::OriginalDebugInfo;
297fe6060f1SDimitry Andric   }
298fe6060f1SDimitry Andric 
299fe6060f1SDimitry Andric   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
30081ad6265SDimitry Andric   DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; }
301e8d8bef9SDimitry Andric };
302e8d8bef9SDimitry Andric } // namespace llvm
303e8d8bef9SDimitry Andric 
304fe6060f1SDimitry Andric #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
305