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 = 27 llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>; 28 using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>; 29 using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>; 30 using WeakInstValueMap = 31 llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>; 32 33 /// Used to track the Debug Info Metadata information. 34 struct DebugInfoPerPass { 35 // This maps a function name to its associated DISubprogram. 36 DebugFnMap DIFunctions; 37 // This maps an instruction and the info about whether it has !dbg attached. 38 DebugInstMap DILocations; 39 // This tracks value (instruction) deletion. If an instruction gets deleted, 40 // WeakVH nulls itself. 41 WeakInstValueMap InstToDelete; 42 // Maps variable into dbg users (#dbg values/declares for this variable). 43 DebugVarMap DIVariables; 44 }; 45 46 namespace llvm { 47 class DIBuilder; 48 49 /// Add synthesized debug information to a module. 50 /// 51 /// \param M The module to add debug information to. 52 /// \param Functions A range of functions to add debug information to. 53 /// \param Banner A prefix string to add to debug/error messages. 54 /// \param ApplyToMF A call back that will add debug information to the 55 /// MachineFunction for a Function. If nullptr, then the 56 /// MachineFunction (if any) will not be modified. 57 bool applyDebugifyMetadata( 58 Module &M, iterator_range<Module::iterator> Functions, StringRef Banner, 59 std::function<bool(DIBuilder &, Function &)> ApplyToMF); 60 61 /// Strip out all of the metadata and debug info inserted by debugify. If no 62 /// llvm.debugify module-level named metadata is present, this is a no-op. 63 /// Returns true if any change was made. 64 bool stripDebugifyMetadata(Module &M); 65 66 /// Collect original debug information before a pass. 67 /// 68 /// \param M The module to collect debug information from. 69 /// \param Functions A range of functions to collect debug information from. 70 /// \param DebugInfoBeforePass DI metadata before a pass. 71 /// \param Banner A prefix string to add to debug/error messages. 72 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages. 73 bool collectDebugInfoMetadata(Module &M, 74 iterator_range<Module::iterator> Functions, 75 DebugInfoPerPass &DebugInfoBeforePass, 76 StringRef Banner, StringRef NameOfWrappedPass); 77 78 /// Check original debug information after a pass. 79 /// 80 /// \param M The module to collect debug information from. 81 /// \param Functions A range of functions to collect debug information from. 82 /// \param DebugInfoBeforePass DI metadata before a pass. 83 /// \param Banner A prefix string to add to debug/error messages. 84 /// \param NameOfWrappedPass A name of a pass to add to debug/error messages. 85 bool checkDebugInfoMetadata(Module &M, 86 iterator_range<Module::iterator> Functions, 87 DebugInfoPerPass &DebugInfoBeforePass, 88 StringRef Banner, StringRef NameOfWrappedPass, 89 StringRef OrigDIVerifyBugsReportFilePath); 90 } // namespace llvm 91 92 /// Used to check whether we track synthetic or original debug info. 93 enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo }; 94 95 llvm::ModulePass *createDebugifyModulePass( 96 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 97 llvm::StringRef NameOfWrappedPass = "", 98 DebugInfoPerPass *DebugInfoBeforePass = nullptr); 99 llvm::FunctionPass *createDebugifyFunctionPass( 100 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 101 llvm::StringRef NameOfWrappedPass = "", 102 DebugInfoPerPass *DebugInfoBeforePass = nullptr); 103 104 struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> { 105 llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 106 }; 107 108 /// Track how much `debugify` information (in the `synthetic` mode only) 109 /// has been lost. 110 struct DebugifyStatistics { 111 /// Number of missing dbg.values. 112 unsigned NumDbgValuesMissing = 0; 113 114 /// Number of dbg.values expected. 115 unsigned NumDbgValuesExpected = 0; 116 117 /// Number of instructions with empty debug locations. 118 unsigned NumDbgLocsMissing = 0; 119 120 /// Number of instructions expected to have debug locations. 121 unsigned NumDbgLocsExpected = 0; 122 123 /// Get the ratio of missing/expected dbg.values. 124 float getMissingValueRatio() const { 125 return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); 126 } 127 128 /// Get the ratio of missing/expected instructions with locations. 129 float getEmptyLocationRatio() const { 130 return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); 131 } 132 }; 133 134 /// Map pass names to a per-pass DebugifyStatistics instance. 135 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>; 136 137 llvm::ModulePass *createCheckDebugifyModulePass( 138 bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 139 DebugifyStatsMap *StatsMap = nullptr, 140 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 141 DebugInfoPerPass *DebugInfoBeforePass = nullptr, 142 llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 143 144 llvm::FunctionPass *createCheckDebugifyFunctionPass( 145 bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 146 DebugifyStatsMap *StatsMap = nullptr, 147 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 148 DebugInfoPerPass *DebugInfoBeforePass = nullptr, 149 llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 150 151 struct NewPMCheckDebugifyPass 152 : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> { 153 llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 154 }; 155 156 namespace llvm { 157 void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map); 158 159 struct DebugifyEachInstrumentation { 160 DebugifyStatsMap StatsMap; 161 162 void registerCallbacks(PassInstrumentationCallbacks &PIC); 163 }; 164 165 /// DebugifyCustomPassManager wraps each pass with the debugify passes if 166 /// needed. 167 /// NOTE: We support legacy custom pass manager only. 168 /// TODO: Add New PM support for custom pass manager. 169 class DebugifyCustomPassManager : public legacy::PassManager { 170 StringRef OrigDIVerifyBugsReportFilePath; 171 DebugifyStatsMap *DIStatsMap = nullptr; 172 DebugInfoPerPass *DebugInfoBeforePass = nullptr; 173 enum DebugifyMode Mode = DebugifyMode::NoDebugify; 174 175 public: 176 using super = legacy::PassManager; 177 178 void add(Pass *P) override { 179 // Wrap each pass with (-check)-debugify passes if requested, making 180 // exceptions for passes which shouldn't see -debugify instrumentation. 181 bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify && 182 !P->getAsImmutablePass() && !isIRPrintingPass(P) && 183 !isBitcodeWriterPass(P); 184 if (!WrapWithDebugify) { 185 super::add(P); 186 return; 187 } 188 189 // Either apply -debugify/-check-debugify before/after each pass and collect 190 // debug info loss statistics, or collect and check original debug info in 191 // the optimizations. 192 PassKind Kind = P->getPassKind(); 193 StringRef Name = P->getPassName(); 194 195 // TODO: Implement Debugify for LoopPass. 196 switch (Kind) { 197 case PT_Function: 198 super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass)); 199 super::add(P); 200 super::add(createCheckDebugifyFunctionPass( 201 isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 202 OrigDIVerifyBugsReportFilePath)); 203 break; 204 case PT_Module: 205 super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass)); 206 super::add(P); 207 super::add(createCheckDebugifyModulePass( 208 isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 209 OrigDIVerifyBugsReportFilePath)); 210 break; 211 default: 212 super::add(P); 213 break; 214 } 215 } 216 217 // Used within DebugifyMode::SyntheticDebugInfo mode. 218 void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } 219 // Used within DebugifyMode::OriginalDebugInfo mode. 220 void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) { 221 DebugInfoBeforePass = &PerPassDI; 222 } 223 void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { 224 OrigDIVerifyBugsReportFilePath = BugsReportFilePath; 225 } 226 StringRef getOrigDIVerifyBugsReportFilePath() const { 227 return OrigDIVerifyBugsReportFilePath; 228 } 229 230 void setDebugifyMode(enum DebugifyMode M) { Mode = M; } 231 232 bool isSyntheticDebugInfo() const { 233 return Mode == DebugifyMode::SyntheticDebugInfo; 234 } 235 bool isOriginalDebugInfoMode() const { 236 return Mode == DebugifyMode::OriginalDebugInfo; 237 } 238 239 const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } 240 DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } 241 }; 242 } // namespace llvm 243 244 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H 245