xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Transforms/Utils/Debugify.h (revision c9ccf3a32da427475985b85d7df023ccfb138c27)
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 = llvm::MapVector<llvm::StringRef, const llvm::DISubprogram *>;
27 using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>;
28 using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>;
29 using WeakInstValueMap =
30     llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>;
31 
32 /// Used to track the Debug Info Metadata information.
33 struct DebugInfoPerPass {
34   // This maps a function name to its associated DISubprogram.
35   DebugFnMap DIFunctions;
36   // This maps an instruction and the info about whether it has !dbg attached.
37   DebugInstMap DILocations;
38   // This tracks value (instruction) deletion. If an instruction gets deleted,
39   // WeakVH nulls itself.
40   WeakInstValueMap InstToDelete;
41   // Maps variable into dbg users (#dbg values/declares for this variable).
42   DebugVarMap DIVariables;
43 };
44 
45 /// Map pass names to a per-pass DebugInfoPerPass instance.
46 using DebugInfoPerPassMap = llvm::MapVector<llvm::StringRef, DebugInfoPerPass>;
47 
48 namespace llvm {
49 class DIBuilder;
50 
51 /// Add synthesized debug information to a module.
52 ///
53 /// \param M The module to add debug information to.
54 /// \param Functions A range of functions to add debug information to.
55 /// \param Banner A prefix string to add to debug/error messages.
56 /// \param ApplyToMF A call back that will add debug information to the
57 ///                  MachineFunction for a Function. If nullptr, then the
58 ///                  MachineFunction (if any) will not be modified.
59 bool applyDebugifyMetadata(
60     Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
61     std::function<bool(DIBuilder &, Function &)> ApplyToMF);
62 
63 /// Strip out all of the metadata and debug info inserted by debugify. If no
64 /// llvm.debugify module-level named metadata is present, this is a no-op.
65 /// Returns true if any change was made.
66 bool stripDebugifyMetadata(Module &M);
67 
68 /// Collect original debug information before a pass.
69 ///
70 /// \param M The module to collect debug information from.
71 /// \param Functions A range of functions to collect debug information from.
72 /// \param DIPreservationMap A map to collect the DI metadata.
73 /// \param Banner A prefix string to add to debug/error messages.
74 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
75 bool collectDebugInfoMetadata(Module &M,
76                               iterator_range<Module::iterator> Functions,
77                               DebugInfoPerPassMap &DIPreservationMap,
78                               StringRef Banner, StringRef NameOfWrappedPass);
79 
80 /// Check original debug information after a pass.
81 ///
82 /// \param M The module to collect debug information from.
83 /// \param Functions A range of functions to collect debug information from.
84 /// \param DIPreservationMap A map used to check collected the DI metadata.
85 /// \param Banner A prefix string to add to debug/error messages.
86 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages.
87 bool checkDebugInfoMetadata(Module &M,
88                             iterator_range<Module::iterator> Functions,
89                             DebugInfoPerPassMap &DIPreservationMap,
90                             StringRef Banner, StringRef NameOfWrappedPass,
91                             StringRef OrigDIVerifyBugsReportFilePath);
92 } // namespace llvm
93 
94 /// Used to check whether we track synthetic or original debug info.
95 enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo };
96 
97 llvm::ModulePass *createDebugifyModulePass(
98     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
99     llvm::StringRef NameOfWrappedPass = "",
100     DebugInfoPerPassMap *DIPreservationMap = nullptr);
101 llvm::FunctionPass *createDebugifyFunctionPass(
102     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
103     llvm::StringRef NameOfWrappedPass = "",
104     DebugInfoPerPassMap *DIPreservationMap = nullptr);
105 
106 struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
107   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
108 };
109 
110 /// Track how much `debugify` information (in the `synthetic` mode only)
111 /// has been lost.
112 struct DebugifyStatistics {
113   /// Number of missing dbg.values.
114   unsigned NumDbgValuesMissing = 0;
115 
116   /// Number of dbg.values expected.
117   unsigned NumDbgValuesExpected = 0;
118 
119   /// Number of instructions with empty debug locations.
120   unsigned NumDbgLocsMissing = 0;
121 
122   /// Number of instructions expected to have debug locations.
123   unsigned NumDbgLocsExpected = 0;
124 
125   /// Get the ratio of missing/expected dbg.values.
126   float getMissingValueRatio() const {
127     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
128   }
129 
130   /// Get the ratio of missing/expected instructions with locations.
131   float getEmptyLocationRatio() const {
132     return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
133   }
134 };
135 
136 /// Map pass names to a per-pass DebugifyStatistics instance.
137 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
138 
139 llvm::ModulePass *createCheckDebugifyModulePass(
140     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
141     DebugifyStatsMap *StatsMap = nullptr,
142     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
143     DebugInfoPerPassMap *DIPreservationMap = nullptr,
144     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
145 
146 llvm::FunctionPass *createCheckDebugifyFunctionPass(
147     bool Strip = false, llvm::StringRef NameOfWrappedPass = "",
148     DebugifyStatsMap *StatsMap = nullptr,
149     enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo,
150     DebugInfoPerPassMap *DIPreservationMap = nullptr,
151     llvm::StringRef OrigDIVerifyBugsReportFilePath = "");
152 
153 struct NewPMCheckDebugifyPass
154     : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
155   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
156 };
157 
158 namespace llvm {
159 void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map);
160 
161 struct DebugifyEachInstrumentation {
162   DebugifyStatsMap StatsMap;
163 
164   void registerCallbacks(PassInstrumentationCallbacks &PIC);
165 };
166 
167 /// DebugifyCustomPassManager wraps each pass with the debugify passes if
168 /// needed.
169 /// NOTE: We support legacy custom pass manager only.
170 /// TODO: Add New PM support for custom pass manager.
171 class DebugifyCustomPassManager : public legacy::PassManager {
172   StringRef OrigDIVerifyBugsReportFilePath;
173   DebugifyStatsMap *DIStatsMap = nullptr;
174   DebugInfoPerPassMap *DIPreservationMap = nullptr;
175   enum DebugifyMode Mode = DebugifyMode::NoDebugify;
176 
177 public:
178   using super = legacy::PassManager;
179 
180   void add(Pass *P) override {
181     // Wrap each pass with (-check)-debugify passes if requested, making
182     // exceptions for passes which shouldn't see -debugify instrumentation.
183     bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify &&
184                             !P->getAsImmutablePass() && !isIRPrintingPass(P) &&
185                             !isBitcodeWriterPass(P);
186     if (!WrapWithDebugify) {
187       super::add(P);
188       return;
189     }
190 
191     // Either apply -debugify/-check-debugify before/after each pass and collect
192     // debug info loss statistics, or collect and check original debug info in
193     // the optimizations.
194     PassKind Kind = P->getPassKind();
195     StringRef Name = P->getPassName();
196 
197     // TODO: Implement Debugify for LoopPass.
198     switch (Kind) {
199     case PT_Function:
200       super::add(createDebugifyFunctionPass(Mode, Name, DIPreservationMap));
201       super::add(P);
202       super::add(createCheckDebugifyFunctionPass(
203           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DIPreservationMap,
204           OrigDIVerifyBugsReportFilePath));
205       break;
206     case PT_Module:
207       super::add(createDebugifyModulePass(Mode, Name, DIPreservationMap));
208       super::add(P);
209       super::add(createCheckDebugifyModulePass(
210           isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DIPreservationMap,
211           OrigDIVerifyBugsReportFilePath));
212       break;
213     default:
214       super::add(P);
215       break;
216     }
217   }
218 
219   // Used within DebugifyMode::SyntheticDebugInfo mode.
220   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
221   // Used within DebugifyMode::OriginalDebugInfo mode.
222   void setDIPreservationMap(DebugInfoPerPassMap &PerPassMap) {
223     DIPreservationMap = &PerPassMap;
224   }
225   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
226     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
227   }
228   StringRef getOrigDIVerifyBugsReportFilePath() const {
229     return OrigDIVerifyBugsReportFilePath;
230   }
231 
232   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
233 
234   bool isSyntheticDebugInfo() const {
235     return Mode == DebugifyMode::SyntheticDebugInfo;
236   }
237   bool isOriginalDebugInfoMode() const {
238     return Mode == DebugifyMode::OriginalDebugInfo;
239   }
240 
241   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
242   DebugInfoPerPassMap &getDebugInfoPerPassMap() { return *DIPreservationMap; }
243 };
244 } // namespace llvm
245 
246 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
247