1fe6060f1SDimitry Andric //===- Debugify.h - Check debug info preservation in optimizations --------===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric /// 9fe6060f1SDimitry Andric /// \file Interface to the `debugify` synthetic/original debug info testing 10fe6060f1SDimitry Andric /// utility. 11480093f4SDimitry Andric /// 12480093f4SDimitry Andric //===----------------------------------------------------------------------===// 13480093f4SDimitry Andric 14fe6060f1SDimitry Andric #ifndef LLVM_TRANSFORMS_UTILS_DEBUGIFY_H 15fe6060f1SDimitry Andric #define LLVM_TRANSFORMS_UTILS_DEBUGIFY_H 16480093f4SDimitry Andric 17480093f4SDimitry Andric #include "llvm/ADT/MapVector.h" 18e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 19e8d8bef9SDimitry Andric #include "llvm/Bitcode/BitcodeWriterPass.h" 20e8d8bef9SDimitry Andric #include "llvm/IR/IRPrintingPasses.h" 21e8d8bef9SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 22*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 23*0fca6ea1SDimitry Andric #include "llvm/IR/PassInstrumentation.h" 24480093f4SDimitry Andric #include "llvm/IR/PassManager.h" 25fe6060f1SDimitry Andric #include "llvm/IR/ValueHandle.h" 261fd87a68SDimitry Andric #include "llvm/Pass.h" 27fe6060f1SDimitry Andric 2881ad6265SDimitry Andric using DebugFnMap = 2981ad6265SDimitry Andric llvm::MapVector<const llvm::Function *, const llvm::DISubprogram *>; 30fe6060f1SDimitry Andric using DebugInstMap = llvm::MapVector<const llvm::Instruction *, bool>; 31fe6060f1SDimitry Andric using DebugVarMap = llvm::MapVector<const llvm::DILocalVariable *, unsigned>; 32fe6060f1SDimitry Andric using WeakInstValueMap = 33fe6060f1SDimitry Andric llvm::MapVector<const llvm::Instruction *, llvm::WeakVH>; 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric /// Used to track the Debug Info Metadata information. 36fe6060f1SDimitry Andric struct DebugInfoPerPass { 37fe6060f1SDimitry Andric // This maps a function name to its associated DISubprogram. 38fe6060f1SDimitry Andric DebugFnMap DIFunctions; 39fe6060f1SDimitry Andric // This maps an instruction and the info about whether it has !dbg attached. 40fe6060f1SDimitry Andric DebugInstMap DILocations; 41fe6060f1SDimitry Andric // This tracks value (instruction) deletion. If an instruction gets deleted, 42fe6060f1SDimitry Andric // WeakVH nulls itself. 43fe6060f1SDimitry Andric WeakInstValueMap InstToDelete; 44fe6060f1SDimitry Andric // Maps variable into dbg users (#dbg values/declares for this variable). 45fe6060f1SDimitry Andric DebugVarMap DIVariables; 46fe6060f1SDimitry Andric }; 47fe6060f1SDimitry Andric 485ffd83dbSDimitry Andric namespace llvm { 495ffd83dbSDimitry Andric class DIBuilder; 505ffd83dbSDimitry Andric 515ffd83dbSDimitry Andric /// Add synthesized debug information to a module. 525ffd83dbSDimitry Andric /// 535ffd83dbSDimitry Andric /// \param M The module to add debug information to. 545ffd83dbSDimitry Andric /// \param Functions A range of functions to add debug information to. 555ffd83dbSDimitry Andric /// \param Banner A prefix string to add to debug/error messages. 565ffd83dbSDimitry Andric /// \param ApplyToMF A call back that will add debug information to the 575ffd83dbSDimitry Andric /// MachineFunction for a Function. If nullptr, then the 585ffd83dbSDimitry Andric /// MachineFunction (if any) will not be modified. 595ffd83dbSDimitry Andric bool applyDebugifyMetadata( 605ffd83dbSDimitry Andric Module &M, iterator_range<Module::iterator> Functions, StringRef Banner, 615ffd83dbSDimitry Andric std::function<bool(DIBuilder &, Function &)> ApplyToMF); 625ffd83dbSDimitry Andric 635ffd83dbSDimitry Andric /// Strip out all of the metadata and debug info inserted by debugify. If no 645ffd83dbSDimitry Andric /// llvm.debugify module-level named metadata is present, this is a no-op. 655ffd83dbSDimitry Andric /// Returns true if any change was made. 665ffd83dbSDimitry Andric bool stripDebugifyMetadata(Module &M); 675ffd83dbSDimitry Andric 68fe6060f1SDimitry Andric /// Collect original debug information before a pass. 69fe6060f1SDimitry Andric /// 70fe6060f1SDimitry Andric /// \param M The module to collect debug information from. 71fe6060f1SDimitry Andric /// \param Functions A range of functions to collect debug information from. 7281ad6265SDimitry Andric /// \param DebugInfoBeforePass DI metadata before a pass. 73fe6060f1SDimitry Andric /// \param Banner A prefix string to add to debug/error messages. 74fe6060f1SDimitry Andric /// \param NameOfWrappedPass A name of a pass to add to debug/error messages. 75fe6060f1SDimitry Andric bool collectDebugInfoMetadata(Module &M, 76fe6060f1SDimitry Andric iterator_range<Module::iterator> Functions, 7781ad6265SDimitry Andric DebugInfoPerPass &DebugInfoBeforePass, 78fe6060f1SDimitry Andric StringRef Banner, StringRef NameOfWrappedPass); 79fe6060f1SDimitry Andric 80fe6060f1SDimitry Andric /// Check original debug information after a pass. 81fe6060f1SDimitry Andric /// 82fe6060f1SDimitry Andric /// \param M The module to collect debug information from. 83fe6060f1SDimitry Andric /// \param Functions A range of functions to collect debug information from. 8481ad6265SDimitry Andric /// \param DebugInfoBeforePass DI metadata before a pass. 85fe6060f1SDimitry Andric /// \param Banner A prefix string to add to debug/error messages. 86fe6060f1SDimitry Andric /// \param NameOfWrappedPass A name of a pass to add to debug/error messages. 87fe6060f1SDimitry Andric bool checkDebugInfoMetadata(Module &M, 88fe6060f1SDimitry Andric iterator_range<Module::iterator> Functions, 8981ad6265SDimitry Andric DebugInfoPerPass &DebugInfoBeforePass, 90fe6060f1SDimitry Andric StringRef Banner, StringRef NameOfWrappedPass, 91fe6060f1SDimitry Andric StringRef OrigDIVerifyBugsReportFilePath); 92fe6060f1SDimitry Andric } // namespace llvm 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric /// Used to check whether we track synthetic or original debug info. 95fe6060f1SDimitry Andric enum class DebugifyMode { NoDebugify, SyntheticDebugInfo, OriginalDebugInfo }; 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric llvm::ModulePass *createDebugifyModulePass( 98fe6060f1SDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 99fe6060f1SDimitry Andric llvm::StringRef NameOfWrappedPass = "", 10081ad6265SDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr); 101fe6060f1SDimitry Andric llvm::FunctionPass *createDebugifyFunctionPass( 102fe6060f1SDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 103fe6060f1SDimitry Andric llvm::StringRef NameOfWrappedPass = "", 10481ad6265SDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr); 105480093f4SDimitry Andric 106753f127fSDimitry Andric class NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> { 107753f127fSDimitry Andric llvm::StringRef NameOfWrappedPass; 108753f127fSDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr; 109753f127fSDimitry Andric enum DebugifyMode Mode = DebugifyMode::NoDebugify; 110753f127fSDimitry Andric public: 111753f127fSDimitry Andric NewPMDebugifyPass( 112753f127fSDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 113753f127fSDimitry Andric llvm::StringRef NameOfWrappedPass = "", 114753f127fSDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr) 115753f127fSDimitry Andric : NameOfWrappedPass(NameOfWrappedPass), 116753f127fSDimitry Andric DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode) {} 117753f127fSDimitry Andric 118480093f4SDimitry Andric llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 119480093f4SDimitry Andric }; 120480093f4SDimitry Andric 121fe6060f1SDimitry Andric /// Track how much `debugify` information (in the `synthetic` mode only) 122fe6060f1SDimitry Andric /// has been lost. 123480093f4SDimitry Andric struct DebugifyStatistics { 124480093f4SDimitry Andric /// Number of missing dbg.values. 125480093f4SDimitry Andric unsigned NumDbgValuesMissing = 0; 126480093f4SDimitry Andric 127480093f4SDimitry Andric /// Number of dbg.values expected. 128480093f4SDimitry Andric unsigned NumDbgValuesExpected = 0; 129480093f4SDimitry Andric 130480093f4SDimitry Andric /// Number of instructions with empty debug locations. 131480093f4SDimitry Andric unsigned NumDbgLocsMissing = 0; 132480093f4SDimitry Andric 133480093f4SDimitry Andric /// Number of instructions expected to have debug locations. 134480093f4SDimitry Andric unsigned NumDbgLocsExpected = 0; 135480093f4SDimitry Andric 136480093f4SDimitry Andric /// Get the ratio of missing/expected dbg.values. 137480093f4SDimitry Andric float getMissingValueRatio() const { 138480093f4SDimitry Andric return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); 139480093f4SDimitry Andric } 140480093f4SDimitry Andric 141480093f4SDimitry Andric /// Get the ratio of missing/expected instructions with locations. 142480093f4SDimitry Andric float getEmptyLocationRatio() const { 143480093f4SDimitry Andric return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); 144480093f4SDimitry Andric } 145480093f4SDimitry Andric }; 146480093f4SDimitry Andric 147480093f4SDimitry Andric /// Map pass names to a per-pass DebugifyStatistics instance. 148480093f4SDimitry Andric using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>; 149480093f4SDimitry Andric 150fe6060f1SDimitry Andric llvm::ModulePass *createCheckDebugifyModulePass( 151fe6060f1SDimitry Andric bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 152fe6060f1SDimitry Andric DebugifyStatsMap *StatsMap = nullptr, 153fe6060f1SDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 15481ad6265SDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr, 155fe6060f1SDimitry Andric llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 156e8d8bef9SDimitry Andric 157fe6060f1SDimitry Andric llvm::FunctionPass *createCheckDebugifyFunctionPass( 158fe6060f1SDimitry Andric bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 159fe6060f1SDimitry Andric DebugifyStatsMap *StatsMap = nullptr, 160fe6060f1SDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 16181ad6265SDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr, 162fe6060f1SDimitry Andric llvm::StringRef OrigDIVerifyBugsReportFilePath = ""); 163480093f4SDimitry Andric 164753f127fSDimitry Andric class NewPMCheckDebugifyPass 165480093f4SDimitry Andric : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> { 166753f127fSDimitry Andric llvm::StringRef NameOfWrappedPass; 167753f127fSDimitry Andric llvm::StringRef OrigDIVerifyBugsReportFilePath; 168753f127fSDimitry Andric DebugifyStatsMap *StatsMap; 169753f127fSDimitry Andric DebugInfoPerPass *DebugInfoBeforePass; 170753f127fSDimitry Andric enum DebugifyMode Mode; 171753f127fSDimitry Andric bool Strip; 172753f127fSDimitry Andric public: 173753f127fSDimitry Andric NewPMCheckDebugifyPass( 174753f127fSDimitry Andric bool Strip = false, llvm::StringRef NameOfWrappedPass = "", 175753f127fSDimitry Andric DebugifyStatsMap *StatsMap = nullptr, 176753f127fSDimitry Andric enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 177753f127fSDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr, 178753f127fSDimitry Andric llvm::StringRef OrigDIVerifyBugsReportFilePath = "") 179753f127fSDimitry Andric : NameOfWrappedPass(NameOfWrappedPass), 180753f127fSDimitry Andric OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), 181753f127fSDimitry Andric StatsMap(StatsMap), DebugInfoBeforePass(DebugInfoBeforePass), Mode(Mode), 182753f127fSDimitry Andric Strip(Strip) {} 183753f127fSDimitry Andric 184480093f4SDimitry Andric llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); 185480093f4SDimitry Andric }; 186480093f4SDimitry Andric 187fe6060f1SDimitry Andric namespace llvm { 188fe6060f1SDimitry Andric void exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map); 189fe6060f1SDimitry Andric 190753f127fSDimitry Andric class DebugifyEachInstrumentation { 191753f127fSDimitry Andric llvm::StringRef OrigDIVerifyBugsReportFilePath = ""; 192753f127fSDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr; 193753f127fSDimitry Andric enum DebugifyMode Mode = DebugifyMode::NoDebugify; 194753f127fSDimitry Andric DebugifyStatsMap *DIStatsMap = nullptr; 195753f127fSDimitry Andric 196753f127fSDimitry Andric public: 19706c3fb27SDimitry Andric void registerCallbacks(PassInstrumentationCallbacks &PIC, 19806c3fb27SDimitry Andric ModuleAnalysisManager &MAM); 199753f127fSDimitry Andric // Used within DebugifyMode::SyntheticDebugInfo mode. 200753f127fSDimitry Andric void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } 201753f127fSDimitry Andric const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } 202753f127fSDimitry Andric // Used within DebugifyMode::OriginalDebugInfo mode. 203753f127fSDimitry Andric void setDebugInfoBeforePass(DebugInfoPerPass &PerPassMap) { 204753f127fSDimitry Andric DebugInfoBeforePass = &PerPassMap; 205753f127fSDimitry Andric } 206753f127fSDimitry Andric DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } 207753f127fSDimitry Andric 208753f127fSDimitry Andric void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { 209753f127fSDimitry Andric OrigDIVerifyBugsReportFilePath = BugsReportFilePath; 210753f127fSDimitry Andric } 211753f127fSDimitry Andric StringRef getOrigDIVerifyBugsReportFilePath() const { 212753f127fSDimitry Andric return OrigDIVerifyBugsReportFilePath; 213753f127fSDimitry Andric } 214753f127fSDimitry Andric 215753f127fSDimitry Andric void setDebugifyMode(enum DebugifyMode M) { Mode = M; } 216753f127fSDimitry Andric 217753f127fSDimitry Andric bool isSyntheticDebugInfo() const { 218753f127fSDimitry Andric return Mode == DebugifyMode::SyntheticDebugInfo; 219753f127fSDimitry Andric } 220753f127fSDimitry Andric bool isOriginalDebugInfoMode() const { 221753f127fSDimitry Andric return Mode == DebugifyMode::OriginalDebugInfo; 222753f127fSDimitry Andric } 223e8d8bef9SDimitry Andric }; 224e8d8bef9SDimitry Andric 225e8d8bef9SDimitry Andric /// DebugifyCustomPassManager wraps each pass with the debugify passes if 226e8d8bef9SDimitry Andric /// needed. 227e8d8bef9SDimitry Andric /// NOTE: We support legacy custom pass manager only. 228e8d8bef9SDimitry Andric /// TODO: Add New PM support for custom pass manager. 229e8d8bef9SDimitry Andric class DebugifyCustomPassManager : public legacy::PassManager { 230fe6060f1SDimitry Andric StringRef OrigDIVerifyBugsReportFilePath; 231fe6060f1SDimitry Andric DebugifyStatsMap *DIStatsMap = nullptr; 23281ad6265SDimitry Andric DebugInfoPerPass *DebugInfoBeforePass = nullptr; 233fe6060f1SDimitry Andric enum DebugifyMode Mode = DebugifyMode::NoDebugify; 234e8d8bef9SDimitry Andric 235e8d8bef9SDimitry Andric public: 236e8d8bef9SDimitry Andric using super = legacy::PassManager; 237e8d8bef9SDimitry Andric 238e8d8bef9SDimitry Andric void add(Pass *P) override { 239e8d8bef9SDimitry Andric // Wrap each pass with (-check)-debugify passes if requested, making 240e8d8bef9SDimitry Andric // exceptions for passes which shouldn't see -debugify instrumentation. 241fe6060f1SDimitry Andric bool WrapWithDebugify = Mode != DebugifyMode::NoDebugify && 242fe6060f1SDimitry Andric !P->getAsImmutablePass() && !isIRPrintingPass(P) && 243fe6060f1SDimitry Andric !isBitcodeWriterPass(P); 244e8d8bef9SDimitry Andric if (!WrapWithDebugify) { 245e8d8bef9SDimitry Andric super::add(P); 246e8d8bef9SDimitry Andric return; 247e8d8bef9SDimitry Andric } 248e8d8bef9SDimitry Andric 249fe6060f1SDimitry Andric // Either apply -debugify/-check-debugify before/after each pass and collect 250fe6060f1SDimitry Andric // debug info loss statistics, or collect and check original debug info in 251fe6060f1SDimitry Andric // the optimizations. 252e8d8bef9SDimitry Andric PassKind Kind = P->getPassKind(); 253e8d8bef9SDimitry Andric StringRef Name = P->getPassName(); 254e8d8bef9SDimitry Andric 255e8d8bef9SDimitry Andric // TODO: Implement Debugify for LoopPass. 256e8d8bef9SDimitry Andric switch (Kind) { 257e8d8bef9SDimitry Andric case PT_Function: 25881ad6265SDimitry Andric super::add(createDebugifyFunctionPass(Mode, Name, DebugInfoBeforePass)); 259e8d8bef9SDimitry Andric super::add(P); 260fe6060f1SDimitry Andric super::add(createCheckDebugifyFunctionPass( 26181ad6265SDimitry Andric isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 262fe6060f1SDimitry Andric OrigDIVerifyBugsReportFilePath)); 263e8d8bef9SDimitry Andric break; 264e8d8bef9SDimitry Andric case PT_Module: 26581ad6265SDimitry Andric super::add(createDebugifyModulePass(Mode, Name, DebugInfoBeforePass)); 266e8d8bef9SDimitry Andric super::add(P); 267fe6060f1SDimitry Andric super::add(createCheckDebugifyModulePass( 26881ad6265SDimitry Andric isSyntheticDebugInfo(), Name, DIStatsMap, Mode, DebugInfoBeforePass, 269fe6060f1SDimitry Andric OrigDIVerifyBugsReportFilePath)); 270e8d8bef9SDimitry Andric break; 271e8d8bef9SDimitry Andric default: 272e8d8bef9SDimitry Andric super::add(P); 273e8d8bef9SDimitry Andric break; 274e8d8bef9SDimitry Andric } 275e8d8bef9SDimitry Andric } 276e8d8bef9SDimitry Andric 277fe6060f1SDimitry Andric // Used within DebugifyMode::SyntheticDebugInfo mode. 278fe6060f1SDimitry Andric void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; } 279fe6060f1SDimitry Andric // Used within DebugifyMode::OriginalDebugInfo mode. 28081ad6265SDimitry Andric void setDebugInfoBeforePass(DebugInfoPerPass &PerPassDI) { 28181ad6265SDimitry Andric DebugInfoBeforePass = &PerPassDI; 282fe6060f1SDimitry Andric } 283fe6060f1SDimitry Andric void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) { 284fe6060f1SDimitry Andric OrigDIVerifyBugsReportFilePath = BugsReportFilePath; 285fe6060f1SDimitry Andric } 286fe6060f1SDimitry Andric StringRef getOrigDIVerifyBugsReportFilePath() const { 287fe6060f1SDimitry Andric return OrigDIVerifyBugsReportFilePath; 288fe6060f1SDimitry Andric } 289e8d8bef9SDimitry Andric 290fe6060f1SDimitry Andric void setDebugifyMode(enum DebugifyMode M) { Mode = M; } 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric bool isSyntheticDebugInfo() const { 293fe6060f1SDimitry Andric return Mode == DebugifyMode::SyntheticDebugInfo; 294fe6060f1SDimitry Andric } 295fe6060f1SDimitry Andric bool isOriginalDebugInfoMode() const { 296fe6060f1SDimitry Andric return Mode == DebugifyMode::OriginalDebugInfo; 297fe6060f1SDimitry Andric } 298fe6060f1SDimitry Andric 299fe6060f1SDimitry Andric const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } 30081ad6265SDimitry Andric DebugInfoPerPass &getDebugInfoPerPass() { return *DebugInfoBeforePass; } 301e8d8bef9SDimitry Andric }; 302e8d8bef9SDimitry Andric } // namespace llvm 303e8d8bef9SDimitry Andric 304fe6060f1SDimitry Andric #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H 305