1 //===- PassManager internal APIs and implementation details -----*- 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 header provides internal APIs and implementation details used by the 11 /// pass management interfaces exposed in PassManager.h. To understand more 12 /// context of why these particular interfaces are needed, see that header 13 /// file. None of these APIs should be used elsewhere. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #ifndef LLVM_IR_PASSMANAGERINTERNAL_H 18 #define LLVM_IR_PASSMANAGERINTERNAL_H 19 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/StringRef.h" 22 #include <memory> 23 #include <utility> 24 25 namespace llvm { 26 27 template <typename IRUnitT> class AllAnalysesOn; 28 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager; 29 class PreservedAnalyses; 30 31 /// Implementation details of the pass manager interfaces. 32 namespace detail { 33 34 /// Template for the abstract base class used to dispatch 35 /// polymorphically over pass objects. 36 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs> 37 struct PassConcept { 38 // Boiler plate necessary for the container of derived classes. 39 virtual ~PassConcept() = default; 40 41 /// The polymorphic API which runs the pass over a given IR entity. 42 /// 43 /// Note that actual pass object can omit the analysis manager argument if 44 /// desired. Also that the analysis manager may be null if there is no 45 /// analysis manager in the pass pipeline. 46 virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, 47 ExtraArgTs... ExtraArgs) = 0; 48 49 /// Polymorphic method to access the name of a pass. 50 virtual StringRef name() const = 0; 51 }; 52 53 /// A template wrapper used to implement the polymorphic API. 54 /// 55 /// Can be instantiated for any object which provides a \c run method accepting 56 /// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to 57 /// be a copyable object. 58 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT, 59 typename AnalysisManagerT, typename... ExtraArgTs> 60 struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> { PassModelPassModel61 explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} 62 // We have to explicitly define all the special member functions because MSVC 63 // refuses to generate them. PassModelPassModel64 PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} PassModelPassModel65 PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} 66 swapPassModel67 friend void swap(PassModel &LHS, PassModel &RHS) { 68 using std::swap; 69 swap(LHS.Pass, RHS.Pass); 70 } 71 72 PassModel &operator=(PassModel RHS) { 73 swap(*this, RHS); 74 return *this; 75 } 76 runPassModel77 PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM, 78 ExtraArgTs... ExtraArgs) override { 79 return Pass.run(IR, AM, ExtraArgs...); 80 } 81 namePassModel82 StringRef name() const override { return PassT::name(); } 83 84 PassT Pass; 85 }; 86 87 /// Abstract concept of an analysis result. 88 /// 89 /// This concept is parameterized over the IR unit that this result pertains 90 /// to. 91 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT> 92 struct AnalysisResultConcept { 93 virtual ~AnalysisResultConcept() = default; 94 95 /// Method to try and mark a result as invalid. 96 /// 97 /// When the outer analysis manager detects a change in some underlying 98 /// unit of the IR, it will call this method on all of the results cached. 99 /// 100 /// \p PA is a set of preserved analyses which can be used to avoid 101 /// invalidation because the pass which changed the underlying IR took care 102 /// to update or preserve the analysis result in some way. 103 /// 104 /// \p Inv is typically a \c AnalysisManager::Invalidator object that can be 105 /// used by a particular analysis result to discover if other analyses 106 /// results are also invalidated in the event that this result depends on 107 /// them. See the documentation in the \c AnalysisManager for more details. 108 /// 109 /// \returns true if the result is indeed invalid (the default). 110 virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, 111 InvalidatorT &Inv) = 0; 112 }; 113 114 /// SFINAE metafunction for computing whether \c ResultT provides an 115 /// \c invalidate member function. 116 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod { 117 using EnabledType = char; 118 struct DisabledType { 119 char a, b; 120 }; 121 122 // Purely to help out MSVC which fails to disable the below specialization, 123 // explicitly enable using the result type's invalidate routine if we can 124 // successfully call that routine. 125 template <typename T> struct Nonce { using Type = EnabledType; }; 126 template <typename T> 127 static typename Nonce<decltype(std::declval<T>().invalidate( 128 std::declval<IRUnitT &>(), std::declval<PreservedAnalyses>()))>::Type 129 check(rank<2>); 130 131 // First we define an overload that can only be taken if there is no 132 // invalidate member. We do this by taking the address of an invalidate 133 // member in an adjacent base class of a derived class. This would be 134 // ambiguous if there were an invalidate member in the result type. 135 template <typename T, typename U> static DisabledType NonceFunction(T U::*); 136 struct CheckerBase { int invalidate; }; 137 template <typename T> struct Checker : CheckerBase, T {}; 138 template <typename T> 139 static decltype(NonceFunction(&Checker<T>::invalidate)) check(rank<1>); 140 141 // Now we have the fallback that will only be reached when there is an 142 // invalidate member, and enables the trait. 143 template <typename T> 144 static EnabledType check(rank<0>); 145 146 public: 147 enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) }; 148 }; 149 150 /// Wrapper to model the analysis result concept. 151 /// 152 /// By default, this will implement the invalidate method with a trivial 153 /// implementation so that the actual analysis result doesn't need to provide 154 /// an invalidation handler. It is only selected when the invalidation handler 155 /// is not part of the ResultT's interface. 156 template <typename IRUnitT, typename PassT, typename ResultT, 157 typename PreservedAnalysesT, typename InvalidatorT, 158 bool HasInvalidateHandler = 159 ResultHasInvalidateMethod<IRUnitT, ResultT>::Value> 160 struct AnalysisResultModel; 161 162 /// Specialization of \c AnalysisResultModel which provides the default 163 /// invalidate functionality. 164 template <typename IRUnitT, typename PassT, typename ResultT, 165 typename PreservedAnalysesT, typename InvalidatorT> 166 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, 167 InvalidatorT, false> 168 : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> { 169 explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} 170 // We have to explicitly define all the special member functions because MSVC 171 // refuses to generate them. 172 AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} 173 AnalysisResultModel(AnalysisResultModel &&Arg) 174 : Result(std::move(Arg.Result)) {} 175 176 friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { 177 using std::swap; 178 swap(LHS.Result, RHS.Result); 179 } 180 181 AnalysisResultModel &operator=(AnalysisResultModel RHS) { 182 swap(*this, RHS); 183 return *this; 184 } 185 186 /// The model bases invalidation solely on being in the preserved set. 187 // 188 // FIXME: We should actually use two different concepts for analysis results 189 // rather than two different models, and avoid the indirect function call for 190 // ones that use the trivial behavior. 191 bool invalidate(IRUnitT &, const PreservedAnalysesT &PA, 192 InvalidatorT &) override { 193 auto PAC = PA.template getChecker<PassT>(); 194 return !PAC.preserved() && 195 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>(); 196 } 197 198 ResultT Result; 199 }; 200 201 /// Specialization of \c AnalysisResultModel which delegates invalidate 202 /// handling to \c ResultT. 203 template <typename IRUnitT, typename PassT, typename ResultT, 204 typename PreservedAnalysesT, typename InvalidatorT> 205 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, 206 InvalidatorT, true> 207 : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> { 208 explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} 209 // We have to explicitly define all the special member functions because MSVC 210 // refuses to generate them. 211 AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} 212 AnalysisResultModel(AnalysisResultModel &&Arg) 213 : Result(std::move(Arg.Result)) {} 214 215 friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { 216 using std::swap; 217 swap(LHS.Result, RHS.Result); 218 } 219 220 AnalysisResultModel &operator=(AnalysisResultModel RHS) { 221 swap(*this, RHS); 222 return *this; 223 } 224 225 /// The model delegates to the \c ResultT method. 226 bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, 227 InvalidatorT &Inv) override { 228 return Result.invalidate(IR, PA, Inv); 229 } 230 231 ResultT Result; 232 }; 233 234 /// Abstract concept of an analysis pass. 235 /// 236 /// This concept is parameterized over the IR unit that it can run over and 237 /// produce an analysis result. 238 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT, 239 typename... ExtraArgTs> 240 struct AnalysisPassConcept { 241 virtual ~AnalysisPassConcept() = default; 242 243 /// Method to run this analysis over a unit of IR. 244 /// \returns A unique_ptr to the analysis result object to be queried by 245 /// users. 246 virtual std::unique_ptr< 247 AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> 248 run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, 249 ExtraArgTs... ExtraArgs) = 0; 250 251 /// Polymorphic method to access the name of a pass. 252 virtual StringRef name() const = 0; 253 }; 254 255 /// Wrapper to model the analysis pass concept. 256 /// 257 /// Can wrap any type which implements a suitable \c run method. The method 258 /// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments 259 /// and produce an object which can be wrapped in a \c AnalysisResultModel. 260 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT, 261 typename InvalidatorT, typename... ExtraArgTs> 262 struct AnalysisPassModel : AnalysisPassConcept<IRUnitT, PreservedAnalysesT, 263 InvalidatorT, ExtraArgTs...> { 264 explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} 265 // We have to explicitly define all the special member functions because MSVC 266 // refuses to generate them. 267 AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} 268 AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} 269 270 friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { 271 using std::swap; 272 swap(LHS.Pass, RHS.Pass); 273 } 274 275 AnalysisPassModel &operator=(AnalysisPassModel RHS) { 276 swap(*this, RHS); 277 return *this; 278 } 279 280 // FIXME: Replace PassT::Result with type traits when we use C++11. 281 using ResultModelT = 282 AnalysisResultModel<IRUnitT, PassT, typename PassT::Result, 283 PreservedAnalysesT, InvalidatorT>; 284 285 /// The model delegates to the \c PassT::run method. 286 /// 287 /// The return is wrapped in an \c AnalysisResultModel. 288 std::unique_ptr< 289 AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> 290 run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, 291 ExtraArgTs... ExtraArgs) override { 292 return std::make_unique<ResultModelT>( 293 Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)); 294 } 295 296 /// The model delegates to a static \c PassT::name method. 297 /// 298 /// The returned string ref must point to constant immutable data! 299 StringRef name() const override { return PassT::name(); } 300 301 PassT Pass; 302 }; 303 304 } // end namespace detail 305 306 } // end namespace llvm 307 308 #endif // LLVM_IR_PASSMANAGERINTERNAL_H 309