Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //===- PassManager internal APIs and implementation details -----*- 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 header provides internal APIs and implementation details used by the
0011 /// pass management interfaces exposed in PassManager.h. To understand more
0012 /// context of why these particular interfaces are needed, see that header
0013 /// file. None of these APIs should be used elsewhere.
0014 ///
0015 //===----------------------------------------------------------------------===//
0016 
0017 #ifndef LLVM_IR_PASSMANAGERINTERNAL_H
0018 #define LLVM_IR_PASSMANAGERINTERNAL_H
0019 
0020 #include "llvm/ADT/STLExtras.h"
0021 #include "llvm/ADT/StringRef.h"
0022 #include "llvm/IR/Analysis.h"
0023 #include "llvm/Support/raw_ostream.h"
0024 #include <memory>
0025 #include <type_traits>
0026 #include <utility>
0027 
0028 namespace llvm {
0029 
0030 template <typename IRUnitT> class AllAnalysesOn;
0031 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
0032 class PreservedAnalyses;
0033 
0034 // Implementation details of the pass manager interfaces.
0035 namespace detail {
0036 
0037 /// Template for the abstract base class used to dispatch
0038 /// polymorphically over pass objects.
0039 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
0040 struct PassConcept {
0041   // Boiler plate necessary for the container of derived classes.
0042   virtual ~PassConcept() = default;
0043 
0044   /// The polymorphic API which runs the pass over a given IR entity.
0045   ///
0046   /// Note that actual pass object can omit the analysis manager argument if
0047   /// desired. Also that the analysis manager may be null if there is no
0048   /// analysis manager in the pass pipeline.
0049   virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
0050                                 ExtraArgTs... ExtraArgs) = 0;
0051 
0052   virtual void
0053   printPipeline(raw_ostream &OS,
0054                 function_ref<StringRef(StringRef)> MapClassName2PassName) = 0;
0055   /// Polymorphic method to access the name of a pass.
0056   virtual StringRef name() const = 0;
0057 
0058   /// Polymorphic method to let a pass optionally exempted from skipping by
0059   /// PassInstrumentation.
0060   /// To opt-in, pass should implement `static bool isRequired()`. It's no-op
0061   /// to have `isRequired` always return false since that is the default.
0062   virtual bool isRequired() const = 0;
0063 };
0064 
0065 /// A template wrapper used to implement the polymorphic API.
0066 ///
0067 /// Can be instantiated for any object which provides a \c run method accepting
0068 /// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to
0069 /// be a copyable object.
0070 template <typename IRUnitT, typename PassT, typename AnalysisManagerT,
0071           typename... ExtraArgTs>
0072 struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
0073   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
0074   // We have to explicitly define all the special member functions because MSVC
0075   // refuses to generate them.
0076   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
0077   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
0078 
0079   friend void swap(PassModel &LHS, PassModel &RHS) {
0080     using std::swap;
0081     swap(LHS.Pass, RHS.Pass);
0082   }
0083 
0084   PassModel &operator=(PassModel RHS) {
0085     swap(*this, RHS);
0086     return *this;
0087   }
0088 
0089   PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
0090                         ExtraArgTs... ExtraArgs) override {
0091     return Pass.run(IR, AM, ExtraArgs...);
0092   }
0093 
0094   void printPipeline(
0095       raw_ostream &OS,
0096       function_ref<StringRef(StringRef)> MapClassName2PassName) override {
0097     Pass.printPipeline(OS, MapClassName2PassName);
0098   }
0099 
0100   StringRef name() const override { return PassT::name(); }
0101 
0102   template <typename T>
0103   using has_required_t = decltype(std::declval<T &>().isRequired());
0104 
0105   template <typename T>
0106   static std::enable_if_t<is_detected<has_required_t, T>::value, bool>
0107   passIsRequiredImpl() {
0108     return T::isRequired();
0109   }
0110   template <typename T>
0111   static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
0112   passIsRequiredImpl() {
0113     return false;
0114   }
0115 
0116   bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
0117 
0118   PassT Pass;
0119 };
0120 
0121 /// Abstract concept of an analysis result.
0122 ///
0123 /// This concept is parameterized over the IR unit that this result pertains
0124 /// to.
0125 template <typename IRUnitT, typename InvalidatorT>
0126 struct AnalysisResultConcept {
0127   virtual ~AnalysisResultConcept() = default;
0128 
0129   /// Method to try and mark a result as invalid.
0130   ///
0131   /// When the outer analysis manager detects a change in some underlying
0132   /// unit of the IR, it will call this method on all of the results cached.
0133   ///
0134   /// \p PA is a set of preserved analyses which can be used to avoid
0135   /// invalidation because the pass which changed the underlying IR took care
0136   /// to update or preserve the analysis result in some way.
0137   ///
0138   /// \p Inv is typically a \c AnalysisManager::Invalidator object that can be
0139   /// used by a particular analysis result to discover if other analyses
0140   /// results are also invalidated in the event that this result depends on
0141   /// them. See the documentation in the \c AnalysisManager for more details.
0142   ///
0143   /// \returns true if the result is indeed invalid (the default).
0144   virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
0145                           InvalidatorT &Inv) = 0;
0146 };
0147 
0148 /// SFINAE metafunction for computing whether \c ResultT provides an
0149 /// \c invalidate member function.
0150 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
0151   using EnabledType = char;
0152   struct DisabledType {
0153     char a, b;
0154   };
0155 
0156   // Purely to help out MSVC which fails to disable the below specialization,
0157   // explicitly enable using the result type's invalidate routine if we can
0158   // successfully call that routine.
0159   template <typename T> struct Nonce { using Type = EnabledType; };
0160   template <typename T>
0161   static typename Nonce<decltype(std::declval<T>().invalidate(
0162       std::declval<IRUnitT &>(), std::declval<PreservedAnalyses>()))>::Type
0163       check(rank<2>);
0164 
0165   // First we define an overload that can only be taken if there is no
0166   // invalidate member. We do this by taking the address of an invalidate
0167   // member in an adjacent base class of a derived class. This would be
0168   // ambiguous if there were an invalidate member in the result type.
0169   template <typename T, typename U> static DisabledType NonceFunction(T U::*);
0170   struct CheckerBase { int invalidate; };
0171   template <typename T> struct Checker : CheckerBase, std::remove_cv_t<T> {};
0172   template <typename T>
0173   static decltype(NonceFunction(&Checker<T>::invalidate)) check(rank<1>);
0174 
0175   // Now we have the fallback that will only be reached when there is an
0176   // invalidate member, and enables the trait.
0177   template <typename T>
0178   static EnabledType check(rank<0>);
0179 
0180 public:
0181   enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) };
0182 };
0183 
0184 /// Wrapper to model the analysis result concept.
0185 ///
0186 /// By default, this will implement the invalidate method with a trivial
0187 /// implementation so that the actual analysis result doesn't need to provide
0188 /// an invalidation handler. It is only selected when the invalidation handler
0189 /// is not part of the ResultT's interface.
0190 template <typename IRUnitT, typename PassT, typename ResultT,
0191           typename InvalidatorT,
0192           bool HasInvalidateHandler =
0193               ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
0194 struct AnalysisResultModel;
0195 
0196 /// Specialization of \c AnalysisResultModel which provides the default
0197 /// invalidate functionality.
0198 template <typename IRUnitT, typename PassT, typename ResultT,
0199           typename InvalidatorT>
0200 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, false>
0201     : AnalysisResultConcept<IRUnitT, InvalidatorT> {
0202   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
0203   // We have to explicitly define all the special member functions because MSVC
0204   // refuses to generate them.
0205   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
0206   AnalysisResultModel(AnalysisResultModel &&Arg)
0207       : Result(std::move(Arg.Result)) {}
0208 
0209   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
0210     using std::swap;
0211     swap(LHS.Result, RHS.Result);
0212   }
0213 
0214   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
0215     swap(*this, RHS);
0216     return *this;
0217   }
0218 
0219   /// The model bases invalidation solely on being in the preserved set.
0220   //
0221   // FIXME: We should actually use two different concepts for analysis results
0222   // rather than two different models, and avoid the indirect function call for
0223   // ones that use the trivial behavior.
0224   bool invalidate(IRUnitT &, const PreservedAnalyses &PA,
0225                   InvalidatorT &) override {
0226     auto PAC = PA.template getChecker<PassT>();
0227     return !PAC.preserved() &&
0228            !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
0229   }
0230 
0231   ResultT Result;
0232 };
0233 
0234 /// Specialization of \c AnalysisResultModel which delegates invalidate
0235 /// handling to \c ResultT.
0236 template <typename IRUnitT, typename PassT, typename ResultT,
0237           typename InvalidatorT>
0238 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, true>
0239     : AnalysisResultConcept<IRUnitT, InvalidatorT> {
0240   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
0241   // We have to explicitly define all the special member functions because MSVC
0242   // refuses to generate them.
0243   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
0244   AnalysisResultModel(AnalysisResultModel &&Arg)
0245       : Result(std::move(Arg.Result)) {}
0246 
0247   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
0248     using std::swap;
0249     swap(LHS.Result, RHS.Result);
0250   }
0251 
0252   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
0253     swap(*this, RHS);
0254     return *this;
0255   }
0256 
0257   /// The model delegates to the \c ResultT method.
0258   bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
0259                   InvalidatorT &Inv) override {
0260     return Result.invalidate(IR, PA, Inv);
0261   }
0262 
0263   ResultT Result;
0264 };
0265 
0266 /// Abstract concept of an analysis pass.
0267 ///
0268 /// This concept is parameterized over the IR unit that it can run over and
0269 /// produce an analysis result.
0270 template <typename IRUnitT, typename InvalidatorT, typename... ExtraArgTs>
0271 struct AnalysisPassConcept {
0272   virtual ~AnalysisPassConcept() = default;
0273 
0274   /// Method to run this analysis over a unit of IR.
0275   /// \returns A unique_ptr to the analysis result object to be queried by
0276   /// users.
0277   virtual std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
0278   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
0279       ExtraArgTs... ExtraArgs) = 0;
0280 
0281   /// Polymorphic method to access the name of a pass.
0282   virtual StringRef name() const = 0;
0283 };
0284 
0285 /// Wrapper to model the analysis pass concept.
0286 ///
0287 /// Can wrap any type which implements a suitable \c run method. The method
0288 /// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments
0289 /// and produce an object which can be wrapped in a \c AnalysisResultModel.
0290 template <typename IRUnitT, typename PassT, typename InvalidatorT,
0291           typename... ExtraArgTs>
0292 struct AnalysisPassModel
0293     : AnalysisPassConcept<IRUnitT, InvalidatorT, ExtraArgTs...> {
0294   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
0295   // We have to explicitly define all the special member functions because MSVC
0296   // refuses to generate them.
0297   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
0298   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
0299 
0300   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
0301     using std::swap;
0302     swap(LHS.Pass, RHS.Pass);
0303   }
0304 
0305   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
0306     swap(*this, RHS);
0307     return *this;
0308   }
0309 
0310   // FIXME: Replace PassT::Result with type traits when we use C++11.
0311   using ResultModelT =
0312       AnalysisResultModel<IRUnitT, PassT, typename PassT::Result, InvalidatorT>;
0313 
0314   /// The model delegates to the \c PassT::run method.
0315   ///
0316   /// The return is wrapped in an \c AnalysisResultModel.
0317   std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
0318   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
0319       ExtraArgTs... ExtraArgs) override {
0320     return std::make_unique<ResultModelT>(
0321         Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...));
0322   }
0323 
0324   /// The model delegates to a static \c PassT::name method.
0325   ///
0326   /// The returned string ref must point to constant immutable data!
0327   StringRef name() const override { return PassT::name(); }
0328 
0329   PassT Pass;
0330 };
0331 
0332 } // end namespace detail
0333 
0334 } // end namespace llvm
0335 
0336 #endif // LLVM_IR_PASSMANAGERINTERNAL_H