Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:09

0001 //===- llvm/IR/PassInstrumentation.h ----------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 ///
0010 /// This file defines the Pass Instrumentation classes that provide
0011 /// instrumentation points into the pass execution by PassManager.
0012 ///
0013 /// There are two main classes:
0014 ///   - PassInstrumentation provides a set of instrumentation points for
0015 ///     pass managers to call on.
0016 ///
0017 ///   - PassInstrumentationCallbacks registers callbacks and provides access
0018 ///     to them for PassInstrumentation.
0019 ///
0020 /// PassInstrumentation object is being used as a result of
0021 /// PassInstrumentationAnalysis (so it is intended to be easily copyable).
0022 ///
0023 /// Intended scheme of use for Pass Instrumentation is as follows:
0024 ///    - register instrumentation callbacks in PassInstrumentationCallbacks
0025 ///      instance. PassBuilder provides helper for that.
0026 ///
0027 ///    - register PassInstrumentationAnalysis with all the PassManagers.
0028 ///      PassBuilder handles that automatically when registering analyses.
0029 ///
0030 ///    - Pass Manager requests PassInstrumentationAnalysis from analysis manager
0031 ///      and gets PassInstrumentation as its result.
0032 ///
0033 ///    - Pass Manager invokes PassInstrumentation entry points appropriately,
0034 ///      passing StringRef identification ("name") of the pass currently being
0035 ///      executed and IRUnit it works on. There can be different schemes of
0036 ///      providing names in future, currently it is just a name() of the pass.
0037 ///
0038 ///    - PassInstrumentation wraps address of IRUnit into llvm::Any and passes
0039 ///      control to all the registered callbacks. Note that we specifically wrap
0040 ///      'const IRUnitT*' so as to avoid any accidental changes to IR in
0041 ///      instrumenting callbacks.
0042 ///
0043 ///    - Some instrumentation points (BeforePass) allow to control execution
0044 ///      of a pass. For those callbacks returning false means pass will not be
0045 ///      executed.
0046 ///
0047 //===----------------------------------------------------------------------===//
0048 
0049 #ifndef LLVM_IR_PASSINSTRUMENTATION_H
0050 #define LLVM_IR_PASSINSTRUMENTATION_H
0051 
0052 #include "llvm/ADT/Any.h"
0053 #include "llvm/ADT/DenseMap.h"
0054 #include "llvm/ADT/FunctionExtras.h"
0055 #include "llvm/ADT/SmallVector.h"
0056 #include "llvm/IR/PassManager.h"
0057 #include "llvm/Support/Compiler.h"
0058 #include <type_traits>
0059 #include <vector>
0060 
0061 namespace llvm {
0062 
0063 class PreservedAnalyses;
0064 class StringRef;
0065 class Module;
0066 class Loop;
0067 class Function;
0068 
0069 extern template struct LLVM_TEMPLATE_ABI Any::TypeId<const Module *>;
0070 extern template struct LLVM_TEMPLATE_ABI Any::TypeId<const Function *>;
0071 extern template struct LLVM_TEMPLATE_ABI Any::TypeId<const Loop *>;
0072 
0073 /// This class manages callbacks registration, as well as provides a way for
0074 /// PassInstrumentation to pass control to the registered callbacks.
0075 class PassInstrumentationCallbacks {
0076 public:
0077   // Before/After callbacks accept IRUnits whenever appropriate, so they need
0078   // to take them as constant pointers, wrapped with llvm::Any.
0079   // For the case when IRUnit has been invalidated there is a different
0080   // callback to use - AfterPassInvalidated.
0081   // We call all BeforePassFuncs to determine if a pass should run or not.
0082   // BeforeNonSkippedPassFuncs are called only if the pass should run.
0083   // TODO: currently AfterPassInvalidated does not accept IRUnit, since passing
0084   // already invalidated IRUnit is unsafe. There are ways to handle invalidated
0085   // IRUnits in a safe way, and we might pursue that as soon as there is a
0086   // useful instrumentation that needs it.
0087   using BeforePassFunc = bool(StringRef, Any);
0088   using BeforeSkippedPassFunc = void(StringRef, Any);
0089   using BeforeNonSkippedPassFunc = void(StringRef, Any);
0090   using AfterPassFunc = void(StringRef, Any, const PreservedAnalyses &);
0091   using AfterPassInvalidatedFunc = void(StringRef, const PreservedAnalyses &);
0092   using BeforeAnalysisFunc = void(StringRef, Any);
0093   using AfterAnalysisFunc = void(StringRef, Any);
0094   using AnalysisInvalidatedFunc = void(StringRef, Any);
0095   using AnalysesClearedFunc = void(StringRef);
0096 
0097 public:
0098   PassInstrumentationCallbacks() = default;
0099 
0100   /// Copying PassInstrumentationCallbacks is not intended.
0101   PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete;
0102   void operator=(const PassInstrumentationCallbacks &) = delete;
0103 
0104   template <typename CallableT>
0105   void registerShouldRunOptionalPassCallback(CallableT C) {
0106     ShouldRunOptionalPassCallbacks.emplace_back(std::move(C));
0107   }
0108 
0109   template <typename CallableT>
0110   void registerBeforeSkippedPassCallback(CallableT C) {
0111     BeforeSkippedPassCallbacks.emplace_back(std::move(C));
0112   }
0113 
0114   template <typename CallableT>
0115   void registerBeforeNonSkippedPassCallback(CallableT C) {
0116     BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
0117   }
0118 
0119   template <typename CallableT>
0120   void registerAfterPassCallback(CallableT C, bool ToFront = false) {
0121     if (ToFront)
0122       AfterPassCallbacks.insert(AfterPassCallbacks.begin(), std::move(C));
0123     else
0124       AfterPassCallbacks.emplace_back(std::move(C));
0125   }
0126 
0127   template <typename CallableT>
0128   void registerAfterPassInvalidatedCallback(CallableT C, bool ToFront = false) {
0129     if (ToFront)
0130       AfterPassInvalidatedCallbacks.insert(
0131           AfterPassInvalidatedCallbacks.begin(), std::move(C));
0132     else
0133       AfterPassInvalidatedCallbacks.emplace_back(std::move(C));
0134   }
0135 
0136   template <typename CallableT>
0137   void registerBeforeAnalysisCallback(CallableT C) {
0138     BeforeAnalysisCallbacks.emplace_back(std::move(C));
0139   }
0140 
0141   template <typename CallableT>
0142   void registerAfterAnalysisCallback(CallableT C, bool ToFront = false) {
0143     if (ToFront)
0144       AfterAnalysisCallbacks.insert(AfterAnalysisCallbacks.begin(),
0145                                     std::move(C));
0146     else
0147       AfterAnalysisCallbacks.emplace_back(std::move(C));
0148   }
0149 
0150   template <typename CallableT>
0151   void registerAnalysisInvalidatedCallback(CallableT C) {
0152     AnalysisInvalidatedCallbacks.emplace_back(std::move(C));
0153   }
0154 
0155   template <typename CallableT>
0156   void registerAnalysesClearedCallback(CallableT C) {
0157     AnalysesClearedCallbacks.emplace_back(std::move(C));
0158   }
0159 
0160   template <typename CallableT>
0161   void registerClassToPassNameCallback(CallableT C) {
0162     ClassToPassNameCallbacks.emplace_back(std::move(C));
0163   }
0164 
0165   /// Add a class name to pass name mapping for use by pass instrumentation.
0166   void addClassToPassName(StringRef ClassName, StringRef PassName);
0167   /// Get the pass name for a given pass class name.
0168   StringRef getPassNameForClassName(StringRef ClassName);
0169 
0170 private:
0171   friend class PassInstrumentation;
0172 
0173   /// These are only run on passes that are not required. They return false when
0174   /// an optional pass should be skipped.
0175   SmallVector<llvm::unique_function<BeforePassFunc>, 4>
0176       ShouldRunOptionalPassCallbacks;
0177   /// These are run on passes that are skipped.
0178   SmallVector<llvm::unique_function<BeforeSkippedPassFunc>, 4>
0179       BeforeSkippedPassCallbacks;
0180   /// These are run on passes that are about to be run.
0181   SmallVector<llvm::unique_function<BeforeNonSkippedPassFunc>, 4>
0182       BeforeNonSkippedPassCallbacks;
0183   /// These are run on passes that have just run.
0184   SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
0185   /// These are run on passes that have just run on invalidated IR.
0186   SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4>
0187       AfterPassInvalidatedCallbacks;
0188   /// These are run on analyses that are about to be run.
0189   SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4>
0190       BeforeAnalysisCallbacks;
0191   /// These are run on analyses that have been run.
0192   SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4>
0193       AfterAnalysisCallbacks;
0194   /// These are run on analyses that have been invalidated.
0195   SmallVector<llvm::unique_function<AnalysisInvalidatedFunc>, 4>
0196       AnalysisInvalidatedCallbacks;
0197   /// These are run on analyses that have been cleared.
0198   SmallVector<llvm::unique_function<AnalysesClearedFunc>, 4>
0199       AnalysesClearedCallbacks;
0200 
0201   SmallVector<llvm::unique_function<void ()>, 4> ClassToPassNameCallbacks;
0202   DenseMap<StringRef, std::string> ClassToPassName;
0203 };
0204 
0205 /// This class provides instrumentation entry points for the Pass Manager,
0206 /// doing calls to callbacks registered in PassInstrumentationCallbacks.
0207 class PassInstrumentation {
0208   PassInstrumentationCallbacks *Callbacks;
0209 
0210   // Template argument PassT of PassInstrumentation::runBeforePass could be two
0211   // kinds: (1) a regular pass inherited from PassInfoMixin (happen when
0212   // creating a adaptor pass for a regular pass); (2) a type-erased PassConcept
0213   // created from (1). Here we want to make case (1) skippable unconditionally
0214   // since they are regular passes. We call PassConcept::isRequired to decide
0215   // for case (2).
0216   template <typename PassT>
0217   using has_required_t = decltype(std::declval<PassT &>().isRequired());
0218 
0219   template <typename PassT>
0220   static std::enable_if_t<is_detected<has_required_t, PassT>::value, bool>
0221   isRequired(const PassT &Pass) {
0222     return Pass.isRequired();
0223   }
0224   template <typename PassT>
0225   static std::enable_if_t<!is_detected<has_required_t, PassT>::value, bool>
0226   isRequired(const PassT &Pass) {
0227     return false;
0228   }
0229 
0230 public:
0231   /// Callbacks object is not owned by PassInstrumentation, its life-time
0232   /// should at least match the life-time of corresponding
0233   /// PassInstrumentationAnalysis (which usually is till the end of current
0234   /// compilation).
0235   PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr)
0236       : Callbacks(CB) {}
0237 
0238   /// BeforePass instrumentation point - takes \p Pass instance to be executed
0239   /// and constant reference to IR it operates on. \Returns true if pass is
0240   /// allowed to be executed. These are only run on optional pass since required
0241   /// passes must always be run. This allows these callbacks to print info when
0242   /// they want to skip a pass.
0243   template <typename IRUnitT, typename PassT>
0244   bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const {
0245     if (!Callbacks)
0246       return true;
0247 
0248     bool ShouldRun = true;
0249     if (!isRequired(Pass)) {
0250       for (auto &C : Callbacks->ShouldRunOptionalPassCallbacks)
0251         ShouldRun &= C(Pass.name(), llvm::Any(&IR));
0252     }
0253 
0254     if (ShouldRun) {
0255       for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks)
0256         C(Pass.name(), llvm::Any(&IR));
0257     } else {
0258       for (auto &C : Callbacks->BeforeSkippedPassCallbacks)
0259         C(Pass.name(), llvm::Any(&IR));
0260     }
0261 
0262     return ShouldRun;
0263   }
0264 
0265   /// AfterPass instrumentation point - takes \p Pass instance that has
0266   /// just been executed and constant reference to \p IR it operates on.
0267   /// \p IR is guaranteed to be valid at this point.
0268   template <typename IRUnitT, typename PassT>
0269   void runAfterPass(const PassT &Pass, const IRUnitT &IR,
0270                     const PreservedAnalyses &PA) const {
0271     if (Callbacks)
0272       for (auto &C : Callbacks->AfterPassCallbacks)
0273         C(Pass.name(), llvm::Any(&IR), PA);
0274   }
0275 
0276   /// AfterPassInvalidated instrumentation point - takes \p Pass instance
0277   /// that has just been executed. For use when IR has been invalidated
0278   /// by \p Pass execution.
0279   template <typename IRUnitT, typename PassT>
0280   void runAfterPassInvalidated(const PassT &Pass,
0281                                const PreservedAnalyses &PA) const {
0282     if (Callbacks)
0283       for (auto &C : Callbacks->AfterPassInvalidatedCallbacks)
0284         C(Pass.name(), PA);
0285   }
0286 
0287   /// BeforeAnalysis instrumentation point - takes \p Analysis instance
0288   /// to be executed and constant reference to IR it operates on.
0289   template <typename IRUnitT, typename PassT>
0290   void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
0291     if (Callbacks)
0292       for (auto &C : Callbacks->BeforeAnalysisCallbacks)
0293         C(Analysis.name(), llvm::Any(&IR));
0294   }
0295 
0296   /// AfterAnalysis instrumentation point - takes \p Analysis instance
0297   /// that has just been executed and constant reference to IR it operated on.
0298   template <typename IRUnitT, typename PassT>
0299   void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
0300     if (Callbacks)
0301       for (auto &C : Callbacks->AfterAnalysisCallbacks)
0302         C(Analysis.name(), llvm::Any(&IR));
0303   }
0304 
0305   /// AnalysisInvalidated instrumentation point - takes \p Analysis instance
0306   /// that has just been invalidated and constant reference to IR it operated
0307   /// on.
0308   template <typename IRUnitT, typename PassT>
0309   void runAnalysisInvalidated(const PassT &Analysis, const IRUnitT &IR) const {
0310     if (Callbacks)
0311       for (auto &C : Callbacks->AnalysisInvalidatedCallbacks)
0312         C(Analysis.name(), llvm::Any(&IR));
0313   }
0314 
0315   /// AnalysesCleared instrumentation point - takes name of IR that analyses
0316   /// operated on.
0317   void runAnalysesCleared(StringRef Name) const {
0318     if (Callbacks)
0319       for (auto &C : Callbacks->AnalysesClearedCallbacks)
0320         C(Name);
0321   }
0322 
0323   /// Handle invalidation from the pass manager when PassInstrumentation
0324   /// is used as the result of PassInstrumentationAnalysis.
0325   ///
0326   /// On attempt to invalidate just return false. There is nothing to become
0327   /// invalid here.
0328   template <typename IRUnitT, typename... ExtraArgsT>
0329   bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &,
0330                   ExtraArgsT...) {
0331     return false;
0332   }
0333 
0334   template <typename CallableT>
0335   void pushBeforeNonSkippedPassCallback(CallableT C) {
0336     if (Callbacks)
0337       Callbacks->BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
0338   }
0339   void popBeforeNonSkippedPassCallback() {
0340     if (Callbacks)
0341       Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
0342   }
0343 
0344   /// Get the pass name for a given pass class name.
0345   StringRef getPassNameForClassName(StringRef ClassName) const {
0346     if (Callbacks)
0347       return Callbacks->getPassNameForClassName(ClassName);
0348     return {};
0349   }
0350 };
0351 
0352 bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials);
0353 
0354 /// Pseudo-analysis pass that exposes the \c PassInstrumentation to pass
0355 /// managers.
0356 class PassInstrumentationAnalysis
0357     : public AnalysisInfoMixin<PassInstrumentationAnalysis> {
0358   friend AnalysisInfoMixin<PassInstrumentationAnalysis>;
0359   static AnalysisKey Key;
0360 
0361   PassInstrumentationCallbacks *Callbacks;
0362 
0363 public:
0364   /// PassInstrumentationCallbacks object is shared, owned by something else,
0365   /// not this analysis.
0366   PassInstrumentationAnalysis(PassInstrumentationCallbacks *Callbacks = nullptr)
0367       : Callbacks(Callbacks) {}
0368 
0369   using Result = PassInstrumentation;
0370 
0371   template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
0372   Result run(IRUnitT &, AnalysisManagerT &, ExtraArgTs &&...) {
0373     return PassInstrumentation(Callbacks);
0374   }
0375 };
0376 
0377 
0378 } // namespace llvm
0379 
0380 #endif