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