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