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 28 using DebugFnMap = 29 llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>; 30 using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>; 31 using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>; 32 using WeakInstValueMap = 33 llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>; 34 35 /// Used to track the Debug Info Metadata information. 36 struct DebugInfoPerPass { 37 // This maps a function name to its associated DISubprogram. 38 DebugFnMap DIFunctions; 39 // This maps an instruction and the info about whether it has !dbg attached. 40 DebugInstMap DILocations; 41 // This tracks value (instruction) deletion. If an instruction gets deleted, 42 // WeakVH nulls itself. 43 WeakInstValueMap InstToDelete; 44 // Maps variable into dbg users (#dbg values/declares for this variable). 45 DebugVarMap DIVariables; 46 }; 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 DebugInfoBeforePass DI metadata before a pass. 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 DebugInfoPerPass &DebugInfoBeforePass, 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 DebugInfoBeforePass DI metadata before a pass. 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 DebugInfoPerPass &DebugInfoBeforePass, 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 DebugInfoPerPass *DebugInfoBeforePass = nullptr); 101 llvm::FunctionPass *createDebugifyFunctionPass( 102 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 103 llvm::StringRef NameOfWrappedPass = "", 104 DebugInfoPerPass *DebugInfoBeforePass = nullptr); 105 106 class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> { 107 llvm::StringRef NameOfWrappedPass; 108 DebugInfoPerPass *DebugInfoBeforePass = nullptr; 109 enum DebugifyMode Mode = DebugifyMode::NoDebugify; 110 public: 111 NewPMDebugifyPass( 112 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 113 llvm::StringRef NameOfWrappedPass = "", 114 DebugInfoPerPass *DebugInfoBeforePass = nullptr) NameOfWrappedPass(NameOfWrappedPass)115 : NameOfWrappedPass(NameOfWrappedPass), 116 DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {} 117 118 llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 119 }; 120 121 /// Track how much `debugify` information (in the `synthetic` mode only) 122 /// has been lost. 123 struct DebugifyStatistics { 124 /// Number of missing dbg.values. 125 unsigned NumDbgValuesMissing = 0; 126 127 /// Number of dbg.values expected. 128 unsigned NumDbgValuesExpected = 0; 129 130 /// Number of instructions with empty debug locations. 131 unsigned NumDbgLocsMissing = 0; 132 133 /// Number of instructions expected to have debug locations. 134 unsigned NumDbgLocsExpected = 0; 135 136 /// Get the ratio of missing/expected dbg.values. getMissingValueRatioDebugifyStatistics137 float getMissingValueRatio() const { 138 return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); 139 } 140 141 /// Get the ratio of missing/expected instructions with locations. getEmptyLocationRatioDebugifyStatistics142 float getEmptyLocationRatio() const { 143 return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); 144 } 145 }; 146 147 /// Map pass names to a per-pass DebugifyStatistics instance. 148 using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>; 149 150 llvm::ModulePass *createCheckDebugifyModulePass( 151 bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 152 DebugifyStatsMap *StatsMap = nullptr, 153 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 154 DebugInfoPerPass *DebugInfoBeforePass = nullptr, 155 llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 156 157 llvm::FunctionPass *createCheckDebugifyFunctionPass( 158 bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 159 DebugifyStatsMap *StatsMap = nullptr, 160 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 161 DebugInfoPerPass *DebugInfoBeforePass = nullptr, 162 llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 163 164 class NewPMCheckDebugifyPass 165 : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> { 166 llvm::StringRef NameOfWrappedPass; 167 llvm::StringRef OrigDIVerifyBugsReportFilePath; 168 DebugifyStatsMap *StatsMap; 169 DebugInfoPerPass *DebugInfoBeforePass; 170 enum DebugifyMode Mode; 171 bool Strip; 172 public: 173 NewPMCheckDebugifyPass( 174 bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 175 DebugifyStatsMap *StatsMap = nullptr, 176 enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 177 DebugInfoPerPass *DebugInfoBeforePass = nullptr, 178 llvm::StringRef OrigDIVerifyBugsReportFilePath = "") NameOfWrappedPass(NameOfWrappedPass)179 : NameOfWrappedPass(NameOfWrappedPass), 180 OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), 181 StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode), 182 Strip(Strip) {} 183 184 llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 185 }; 186 187 namespace llvm { 188 void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map); 189 190 class DebugifyEachInstrumentation { 191 llvm::StringRef OrigDIVerifyBugsReportFilePath = ""; 192 DebugInfoPerPass *DebugInfoBeforePass = nullptr; 193 enum DebugifyMode Mode = DebugifyMode::NoDebugify; 194 DebugifyStatsMap *DIStatsMap = nullptr; 195 196 public: 197 void registerCallbacks(PassInstrumentationCallbacks &PIC, 198 ModuleAnalysisManager &MAM); 199 // Used within DebugifyMode::SyntheticDebugInfo mode. setDIStatsMap(DebugifyStatsMap & StatMap)200 void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } getDebugifyStatsMap()201 const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } 202 // Used within DebugifyMode::OriginalDebugInfo mode. setDebugInfoBeforePass(DebugInfoPerPass & PerPassMap)203 void setDebugInfoBeforePass(DebugInfoPerPass &PerPassMap) { 204 DebugInfoBeforePass = &PerPassMap; 205 } getDebugInfoPerPass()206 DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } 207 setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath)208 void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { 209 OrigDIVerifyBugsReportFilePath = BugsReportFilePath; 210 } getOrigDIVerifyBugsReportFilePath()211 StringRef getOrigDIVerifyBugsReportFilePath() const { 212 return OrigDIVerifyBugsReportFilePath; 213 } 214 setDebugifyMode(enum DebugifyMode M)215 void setDebugifyMode(enum DebugifyMode M) { Mode = M; } 216 isSyntheticDebugInfo()217 bool isSyntheticDebugInfo() const { 218 return Mode == DebugifyMode::SyntheticDebugInfo; 219 } isOriginalDebugInfoMode()220 bool isOriginalDebugInfoMode() const { 221 return Mode == DebugifyMode::OriginalDebugInfo; 222 } 223 }; 224 225 /// DebugifyCustomPassManager wraps each pass with the debugify passes if 226 /// needed. 227 /// NOTE: We support legacy custom pass manager only. 228 /// TODO: Add New PM support for custom pass manager. 229 class DebugifyCustomPassManager : public legacy::PassManager { 230 StringRef OrigDIVerifyBugsReportFilePath; 231 DebugifyStatsMap *DIStatsMap = nullptr; 232 DebugInfoPerPass *DebugInfoBeforePass = nullptr; 233 enum DebugifyMode Mode = DebugifyMode::NoDebugify; 234 235 public: 236 using super = legacy::PassManager; 237 add(Pass * P)238 void add(Pass *P) override { 239 // Wrap each pass with (-check)-debugify passes if requested, making 240 // exceptions for passes which shouldn't see -debugify instrumentation. 241 bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify && 242 !P->getAsImmutablePass() && !isIRPrintingPass(P) && 243 !isBitcodeWriterPass(P); 244 if (!WrapWithDebugify) { 245 super::add(P); 246 return; 247 } 248 249 // Either apply -debugify/-check-debugify before/after each pass and collect 250 // debug info loss statistics, or collect and check original debug info in 251 // the optimizations. 252 PassKind Kind = P->getPassKind(); 253 StringRef Name = P->getPassName(); 254 255 // TODO: Implement Debugify for LoopPass. 256 switch (Kind) { 257 case PT_Function: 258 super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass)); 259 super::add(P); 260 super::add(createCheckDebugifyFunctionPass( 261 isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 262 OrigDIVerifyBugsReportFilePath)); 263 break; 264 case PT_Module: 265 super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass)); 266 super::add(P); 267 super::add(createCheckDebugifyModulePass( 268 isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 269 OrigDIVerifyBugsReportFilePath)); 270 break; 271 default: 272 super::add(P); 273 break; 274 } 275 } 276 277 // Used within DebugifyMode::SyntheticDebugInfo mode. setDIStatsMap(DebugifyStatsMap & StatMap)278 void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } 279 // Used within DebugifyMode::OriginalDebugInfo mode. setDebugInfoBeforePass(DebugInfoPerPass & PerPassDI)280 void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) { 281 DebugInfoBeforePass = &PerPassDI; 282 } setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath)283 void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { 284 OrigDIVerifyBugsReportFilePath = BugsReportFilePath; 285 } getOrigDIVerifyBugsReportFilePath()286 StringRef getOrigDIVerifyBugsReportFilePath() const { 287 return OrigDIVerifyBugsReportFilePath; 288 } 289 setDebugifyMode(enum DebugifyMode M)290 void setDebugifyMode(enum DebugifyMode M) { Mode = M; } 291 isSyntheticDebugInfo()292 bool isSyntheticDebugInfo() const { 293 return Mode == DebugifyMode::SyntheticDebugInfo; 294 } isOriginalDebugInfoMode()295 bool isOriginalDebugInfoMode() const { 296 return Mode == DebugifyMode::OriginalDebugInfo; 297 } 298 getDebugifyStatsMap()299 const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } getDebugInfoPerPass()300 DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } 301 }; 302 } // namespace llvm 303 304 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H 305