Home | History | Annotate | Line # | Download | only in IR
      1 //===- llvm/IR/PassInstrumentation.h ----------------------*- C++ -*-===//
      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 /// \file
      9 ///
     10 /// This file defines the Pass Instrumentation classes that provide
     11 /// instrumentation points into the pass execution by PassManager.
     12 ///
     13 /// There are two main classes:
     14 ///   - PassInstrumentation provides a set of instrumentation points for
     15 ///     pass managers to call on.
     16 ///
     17 ///   - PassInstrumentationCallbacks registers callbacks and provides access
     18 ///     to them for PassInstrumentation.
     19 ///
     20 /// PassInstrumentation object is being used as a result of
     21 /// PassInstrumentationAnalysis (so it is intended to be easily copyable).
     22 ///
     23 /// Intended scheme of use for Pass Instrumentation is as follows:
     24 ///    - register instrumentation callbacks in PassInstrumentationCallbacks
     25 ///      instance. PassBuilder provides helper for that.
     26 ///
     27 ///    - register PassInstrumentationAnalysis with all the PassManagers.
     28 ///      PassBuilder handles that automatically when registering analyses.
     29 ///
     30 ///    - Pass Manager requests PassInstrumentationAnalysis from analysis manager
     31 ///      and gets PassInstrumentation as its result.
     32 ///
     33 ///    - Pass Manager invokes PassInstrumentation entry points appropriately,
     34 ///      passing StringRef identification ("name") of the pass currently being
     35 ///      executed and IRUnit it works on. There can be different schemes of
     36 ///      providing names in future, currently it is just a name() of the pass.
     37 ///
     38 ///    - PassInstrumentation wraps address of IRUnit into llvm::Any and passes
     39 ///      control to all the registered callbacks. Note that we specifically wrap
     40 ///      'const IRUnitT*' so as to avoid any accidental changes to IR in
     41 ///      instrumenting callbacks.
     42 ///
     43 ///    - Some instrumentation points (BeforePass) allow to control execution
     44 ///      of a pass. For those callbacks returning false means pass will not be
     45 ///      executed.
     46 ///
     47 //===----------------------------------------------------------------------===//
     48 
     49 #ifndef LLVM_IR_PASSINSTRUMENTATION_H
     50 #define LLVM_IR_PASSINSTRUMENTATION_H
     51 
     52 #include "llvm/ADT/Any.h"
     53 #include "llvm/ADT/FunctionExtras.h"
     54 #include "llvm/ADT/SmallVector.h"
     55 #include "llvm/ADT/StringMap.h"
     56 #include <type_traits>
     57 
     58 namespace llvm {
     59 
     60 class PreservedAnalyses;
     61 class StringRef;
     62 
     63 /// This class manages callbacks registration, as well as provides a way for
     64 /// PassInstrumentation to pass control to the registered callbacks.
     65 class PassInstrumentationCallbacks {
     66 public:
     67   // Before/After callbacks accept IRUnits whenever appropriate, so they need
     68   // to take them as constant pointers, wrapped with llvm::Any.
     69   // For the case when IRUnit has been invalidated there is a different
     70   // callback to use - AfterPassInvalidated.
     71   // We call all BeforePassFuncs to determine if a pass should run or not.
     72   // BeforeNonSkippedPassFuncs are called only if the pass should run.
     73   // TODO: currently AfterPassInvalidated does not accept IRUnit, since passing
     74   // already invalidated IRUnit is unsafe. There are ways to handle invalidated
     75   // IRUnits in a safe way, and we might pursue that as soon as there is a
     76   // useful instrumentation that needs it.
     77   using BeforePassFunc = bool(StringRef, Any);
     78   using BeforeSkippedPassFunc = void(StringRef, Any);
     79   using BeforeNonSkippedPassFunc = void(StringRef, Any);
     80   using AfterPassFunc = void(StringRef, Any, const PreservedAnalyses &);
     81   using AfterPassInvalidatedFunc = void(StringRef, const PreservedAnalyses &);
     82   using BeforeAnalysisFunc = void(StringRef, Any);
     83   using AfterAnalysisFunc = void(StringRef, Any);
     84   using AnalysisInvalidatedFunc = void(StringRef, Any);
     85   using AnalysesClearedFunc = void(StringRef);
     86 
     87 public:
     88   PassInstrumentationCallbacks() {}
     89 
     90   /// Copying PassInstrumentationCallbacks is not intended.
     91   PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete;
     92   void operator=(const PassInstrumentationCallbacks &) = delete;
     93 
     94   template <typename CallableT>
     95   void registerShouldRunOptionalPassCallback(CallableT C) {
     96     ShouldRunOptionalPassCallbacks.emplace_back(std::move(C));
     97   }
     98 
     99   template <typename CallableT>
    100   void registerBeforeSkippedPassCallback(CallableT C) {
    101     BeforeSkippedPassCallbacks.emplace_back(std::move(C));
    102   }
    103 
    104   template <typename CallableT>
    105   void registerBeforeNonSkippedPassCallback(CallableT C) {
    106     BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
    107   }
    108 
    109   template <typename CallableT> void registerAfterPassCallback(CallableT C) {
    110     AfterPassCallbacks.emplace_back(std::move(C));
    111   }
    112 
    113   template <typename CallableT>
    114   void registerAfterPassInvalidatedCallback(CallableT C) {
    115     AfterPassInvalidatedCallbacks.emplace_back(std::move(C));
    116   }
    117 
    118   template <typename CallableT>
    119   void registerBeforeAnalysisCallback(CallableT C) {
    120     BeforeAnalysisCallbacks.emplace_back(std::move(C));
    121   }
    122 
    123   template <typename CallableT>
    124   void registerAfterAnalysisCallback(CallableT C) {
    125     AfterAnalysisCallbacks.emplace_back(std::move(C));
    126   }
    127 
    128   template <typename CallableT>
    129   void registerAnalysisInvalidatedCallback(CallableT C) {
    130     AnalysisInvalidatedCallbacks.emplace_back(std::move(C));
    131   }
    132 
    133   template <typename CallableT>
    134   void registerAnalysesClearedCallback(CallableT C) {
    135     AnalysesClearedCallbacks.emplace_back(std::move(C));
    136   }
    137 
    138   /// Add a class name to pass name mapping for use by pass instrumentation.
    139   void addClassToPassName(StringRef ClassName, StringRef PassName);
    140   /// Get the pass name for a given pass class name.
    141   StringRef getPassNameForClassName(StringRef ClassName);
    142 
    143 private:
    144   friend class PassInstrumentation;
    145 
    146   /// These are only run on passes that are not required. They return false when
    147   /// an optional pass should be skipped.
    148   SmallVector<llvm::unique_function<BeforePassFunc>, 4>
    149       ShouldRunOptionalPassCallbacks;
    150   /// These are run on passes that are skipped.
    151   SmallVector<llvm::unique_function<BeforeSkippedPassFunc>, 4>
    152       BeforeSkippedPassCallbacks;
    153   /// These are run on passes that are about to be run.
    154   SmallVector<llvm::unique_function<BeforeNonSkippedPassFunc>, 4>
    155       BeforeNonSkippedPassCallbacks;
    156   /// These are run on passes that have just run.
    157   SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
    158   /// These are run passes that have just run on invalidated IR.
    159   SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4>
    160       AfterPassInvalidatedCallbacks;
    161   /// These are run on analyses that are about to be run.
    162   SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4>
    163       BeforeAnalysisCallbacks;
    164   /// These are run on analyses that have been run.
    165   SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4>
    166       AfterAnalysisCallbacks;
    167   /// These are run on analyses that have been invalidated.
    168   SmallVector<llvm::unique_function<AnalysisInvalidatedFunc>, 4>
    169       AnalysisInvalidatedCallbacks;
    170   /// These are run on analyses that have been cleared.
    171   SmallVector<llvm::unique_function<AnalysesClearedFunc>, 4>
    172       AnalysesClearedCallbacks;
    173 
    174   StringMap<std::string> ClassToPassName;
    175 };
    176 
    177 /// This class provides instrumentation entry points for the Pass Manager,
    178 /// doing calls to callbacks registered in PassInstrumentationCallbacks.
    179 class PassInstrumentation {
    180   PassInstrumentationCallbacks *Callbacks;
    181 
    182   // Template argument PassT of PassInstrumentation::runBeforePass could be two
    183   // kinds: (1) a regular pass inherited from PassInfoMixin (happen when
    184   // creating a adaptor pass for a regular pass); (2) a type-erased PassConcept
    185   // created from (1). Here we want to make case (1) skippable unconditionally
    186   // since they are regular passes. We call PassConcept::isRequired to decide
    187   // for case (2).
    188   template <typename PassT>
    189   using has_required_t = decltype(std::declval<PassT &>().isRequired());
    190 
    191   template <typename PassT>
    192   static std::enable_if_t<is_detected<has_required_t, PassT>::value, bool>
    193   isRequired(const PassT &Pass) {
    194     return Pass.isRequired();
    195   }
    196   template <typename PassT>
    197   static std::enable_if_t<!is_detected<has_required_t, PassT>::value, bool>
    198   isRequired(const PassT &Pass) {
    199     return false;
    200   }
    201 
    202 public:
    203   /// Callbacks object is not owned by PassInstrumentation, its life-time
    204   /// should at least match the life-time of corresponding
    205   /// PassInstrumentationAnalysis (which usually is till the end of current
    206   /// compilation).
    207   PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr)
    208       : Callbacks(CB) {}
    209 
    210   /// BeforePass instrumentation point - takes \p Pass instance to be executed
    211   /// and constant reference to IR it operates on. \Returns true if pass is
    212   /// allowed to be executed. These are only run on optional pass since required
    213   /// passes must always be run. This allows these callbacks to print info when
    214   /// they want to skip a pass.
    215   template <typename IRUnitT, typename PassT>
    216   bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const {
    217     if (!Callbacks)
    218       return true;
    219 
    220     bool ShouldRun = true;
    221     if (!isRequired(Pass)) {
    222       for (auto &C : Callbacks->ShouldRunOptionalPassCallbacks)
    223         ShouldRun &= C(Pass.name(), llvm::Any(&IR));
    224     }
    225 
    226     if (ShouldRun) {
    227       for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks)
    228         C(Pass.name(), llvm::Any(&IR));
    229     } else {
    230       for (auto &C : Callbacks->BeforeSkippedPassCallbacks)
    231         C(Pass.name(), llvm::Any(&IR));
    232     }
    233 
    234     return ShouldRun;
    235   }
    236 
    237   /// AfterPass instrumentation point - takes \p Pass instance that has
    238   /// just been executed and constant reference to \p IR it operates on.
    239   /// \p IR is guaranteed to be valid at this point.
    240   template <typename IRUnitT, typename PassT>
    241   void runAfterPass(const PassT &Pass, const IRUnitT &IR,
    242                     const PreservedAnalyses &PA) const {
    243     if (Callbacks)
    244       for (auto &C : Callbacks->AfterPassCallbacks)
    245         C(Pass.name(), llvm::Any(&IR), PA);
    246   }
    247 
    248   /// AfterPassInvalidated instrumentation point - takes \p Pass instance
    249   /// that has just been executed. For use when IR has been invalidated
    250   /// by \p Pass execution.
    251   template <typename IRUnitT, typename PassT>
    252   void runAfterPassInvalidated(const PassT &Pass,
    253                                const PreservedAnalyses &PA) const {
    254     if (Callbacks)
    255       for (auto &C : Callbacks->AfterPassInvalidatedCallbacks)
    256         C(Pass.name(), PA);
    257   }
    258 
    259   /// BeforeAnalysis instrumentation point - takes \p Analysis instance
    260   /// to be executed and constant reference to IR it operates on.
    261   template <typename IRUnitT, typename PassT>
    262   void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
    263     if (Callbacks)
    264       for (auto &C : Callbacks->BeforeAnalysisCallbacks)
    265         C(Analysis.name(), llvm::Any(&IR));
    266   }
    267 
    268   /// AfterAnalysis instrumentation point - takes \p Analysis instance
    269   /// that has just been executed and constant reference to IR it operated on.
    270   template <typename IRUnitT, typename PassT>
    271   void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
    272     if (Callbacks)
    273       for (auto &C : Callbacks->AfterAnalysisCallbacks)
    274         C(Analysis.name(), llvm::Any(&IR));
    275   }
    276 
    277   /// AnalysisInvalidated instrumentation point - takes \p Analysis instance
    278   /// that has just been invalidated and constant reference to IR it operated
    279   /// on.
    280   template <typename IRUnitT, typename PassT>
    281   void runAnalysisInvalidated(const PassT &Analysis, const IRUnitT &IR) const {
    282     if (Callbacks)
    283       for (auto &C : Callbacks->AnalysisInvalidatedCallbacks)
    284         C(Analysis.name(), llvm::Any(&IR));
    285   }
    286 
    287   /// AnalysesCleared instrumentation point - takes name of IR that analyses
    288   /// operated on.
    289   void runAnalysesCleared(StringRef Name) const {
    290     if (Callbacks)
    291       for (auto &C : Callbacks->AnalysesClearedCallbacks)
    292         C(Name);
    293   }
    294 
    295   /// Handle invalidation from the pass manager when PassInstrumentation
    296   /// is used as the result of PassInstrumentationAnalysis.
    297   ///
    298   /// On attempt to invalidate just return false. There is nothing to become
    299   /// invalid here.
    300   template <typename IRUnitT, typename... ExtraArgsT>
    301   bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &,
    302                   ExtraArgsT...) {
    303     return false;
    304   }
    305 
    306   template <typename CallableT>
    307   void pushBeforeNonSkippedPassCallback(CallableT C) {
    308     if (Callbacks)
    309       Callbacks->BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
    310   }
    311   void popBeforeNonSkippedPassCallback() {
    312     if (Callbacks)
    313       Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
    314   }
    315 };
    316 
    317 bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials);
    318 
    319 } // namespace llvm
    320 
    321 #endif
    322