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