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