Home | History | Annotate | Line # | Download | only in Utils
      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.
    125   float getMissingValueRatio() const {
    126     return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
    127   }
    128 
    129   /// Get the ratio of missing/expected instructions with locations.
    130   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 
    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.
    219   void setDIStatsMap(DebugifyStatsMap &StatMap) { DIStatsMap = &StatMap; }
    220   // Used within DebugifyMode::OriginalDebugInfo mode.
    221   void setDIPreservationMap(DebugInfoPerPassMap &PerPassMap) {
    222     DIPreservationMap = &PerPassMap;
    223   }
    224   void setOrigDIVerifyBugsReportFilePath(StringRef BugsReportFilePath) {
    225     OrigDIVerifyBugsReportFilePath = BugsReportFilePath;
    226   }
    227   StringRef getOrigDIVerifyBugsReportFilePath() const {
    228     return OrigDIVerifyBugsReportFilePath;
    229   }
    230 
    231   void setDebugifyMode(enum DebugifyMode M) { Mode = M; }
    232 
    233   bool isSyntheticDebugInfo() const {
    234     return Mode == DebugifyMode::SyntheticDebugInfo;
    235   }
    236   bool isOriginalDebugInfoMode() const {
    237     return Mode == DebugifyMode::OriginalDebugInfo;
    238   }
    239 
    240   const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; }
    241   DebugInfoPerPassMap &getDebugInfoPerPassMap() { return *DIPreservationMap; }
    242 };
    243 } // namespace llvm
    244 
    245 #endif // LLVM_TRANSFORMS_UTILS_DEBUGIFY_H
    246