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