1 //===- Debugify.h - Attach synthetic debug info to everything -------------===//
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 debug info testing utility.
10 ///
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_TRANSFORM_UTILS_DEBUGIFY_H
14 #define LLVM_TRANSFORM_UTILS_DEBUGIFY_H
15 
16 #include "llvm/ADT/MapVector.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Bitcode/BitcodeWriterPass.h"
19 #include "llvm/IR/IRPrintingPasses.h"
20 #include "llvm/IR/LegacyPassManager.h"
21 #include "llvm/IR/PassManager.h"
22 
23 namespace llvm {
24 class DIBuilder;
25 
26 /// Add synthesized debug information to a module.
27 ///
28 /// \param M The module to add debug information to.
29 /// \param Functions A range of functions to add debug information to.
30 /// \param Banner A prefix string to add to debug/error messages.
31 /// \param ApplyToMF A call back that will add debug information to the
32 ///                  MachineFunction for a Function. If nullptr, then the
33 ///                  MachineFunction (if any) will not be modified.
34 bool applyDebugifyMetadata(
35     Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
36     std::function<bool(DIBuilder &, Function &)> ApplyToMF);
37 
38 /// Strip out all of the metadata and debug info inserted by debugify. If no
39 /// llvm.debugify module-level named metadata is present, this is a no-op.
40 /// Returns true if any change was made.
41 bool stripDebugifyMetadata(Module &M);
42 
43 } // namespace llvm
44 
45 llvm::ModulePass *createDebugifyModulePass();
46 llvm::FunctionPass *createDebugifyFunctionPass();
47 
48 struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
49   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
50 };
51 
52 /// Track how much `debugify` information has been lost.
53 struct DebugifyStatistics {
54   /// Number of missing dbg.values.
55   unsigned NumDbgValuesMissing = 0;
56 
57   /// Number of dbg.values expected.
58   unsigned NumDbgValuesExpected = 0;
59 
60   /// Number of instructions with empty debug locations.
61   unsigned NumDbgLocsMissing = 0;
62 
63   /// Number of instructions expected to have debug locations.
64   unsigned NumDbgLocsExpected = 0;
65 
66   /// Get the ratio of missing/expected dbg.values.
67   float getMissingValueRatio() const {
68     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
69   }
70 
71   /// Get the ratio of missing/expected instructions with locations.
72   float getEmptyLocationRatio() const {
73     return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
74   }
75 };
76 
77 /// Map pass names to a per-pass DebugifyStatistics instance.
78 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
79 
80 llvm::ModulePass *
81 createCheckDebugifyModulePass(bool Strip = false,
82                               llvm::StringRef NameOfWrappedPass = "",
83                               DebugifyStatsMap *StatsMap = nullptr);
84 
85 llvm::FunctionPass *
86 createCheckDebugifyFunctionPass(bool Strip = false,
87                                 llvm::StringRef NameOfWrappedPass = "",
88                                 DebugifyStatsMap *StatsMap = nullptr);
89 
90 struct NewPMCheckDebugifyPass
91     : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
92   llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
93 };
94 
95 namespace llvm {
96 /// DebugifyCustomPassManager wraps each pass with the debugify passes if
97 /// needed.
98 /// NOTE: We support legacy custom pass manager only.
99 /// TODO: Add New PM support for custom pass manager.
100 class DebugifyCustomPassManager : public legacy::PassManager {
101   DebugifyStatsMap DIStatsMap;
102   bool EnableDebugifyEach = false;
103 
104 public:
105   using super = legacy::PassManager;
106 
107   void add(Pass *P) override {
108     // Wrap each pass with (-check)-debugify passes if requested, making
109     // exceptions for passes which shouldn't see -debugify instrumentation.
110     bool WrapWithDebugify = EnableDebugifyEach && !P->getAsImmutablePass() &&
111                             !isIRPrintingPass(P) && !isBitcodeWriterPass(P);
112     if (!WrapWithDebugify) {
113       super::add(P);
114       return;
115     }
116 
117     // Apply -debugify/-check-debugify before/after each pass and collect
118     // debug info loss statistics.
119     PassKind Kind = P->getPassKind();
120     StringRef Name = P->getPassName();
121 
122     // TODO: Implement Debugify for LoopPass.
123     switch (Kind) {
124     case PT_Function:
125       super::add(createDebugifyFunctionPass());
126       super::add(P);
127       super::add(createCheckDebugifyFunctionPass(true, Name, &DIStatsMap));
128       break;
129     case PT_Module:
130       super::add(createDebugifyModulePass());
131       super::add(P);
132       super::add(createCheckDebugifyModulePass(true, Name, &DIStatsMap));
133       break;
134     default:
135       super::add(P);
136       break;
137     }
138   }
139 
140   void enableDebugifyEach() { EnableDebugifyEach = true; }
141 
142   const DebugifyStatsMap &getDebugifyStatsMap() const { return DIStatsMap; }
143 };
144 } // namespace llvm
145 
146 #endif // LLVM_TRANSFORM_UTILS_DEBUGIFY_H
147