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