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