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 /// Polymorphic method to to let a pass optionally exempted from skipping by 53 /// PassInstrumentation. 54 /// To opt-in, pass should implement `static bool isRequired()`. It's no-op 55 /// to have `isRequired` always return false since that is the default. 56 virtual bool isRequired() const = 0; 57 }; 58 59 /// A template wrapper used to implement the polymorphic API. 60 /// 61 /// Can be instantiated for any object which provides a \c run method accepting 62 /// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to 63 /// be a copyable object. 64 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT, 65 typename AnalysisManagerT, typename... ExtraArgTs> 66 struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> { PassModelPassModel67 explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} 68 // We have to explicitly define all the special member functions because MSVC 69 // refuses to generate them. PassModelPassModel70 PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} PassModelPassModel71 PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} 72 swapPassModel73 friend void swap(PassModel &LHS, PassModel &RHS) { 74 using std::swap; 75 swap(LHS.Pass, RHS.Pass); 76 } 77 78 PassModel &operator=(PassModel RHS) { 79 swap(*this, RHS); 80 return *this; 81 } 82 runPassModel83 PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM, 84 ExtraArgTs... ExtraArgs) override { 85 return Pass.run(IR, AM, ExtraArgs...); 86 } 87 namePassModel88 StringRef name() const override { return PassT::name(); } 89 90 template <typename T> 91 using has_required_t = decltype(std::declval<T &>().isRequired()); 92 93 template <typename T> 94 static std::enable_if_t<is_detected<has_required_t, T>::value, bool> passIsRequiredImplPassModel95 passIsRequiredImpl() { 96 return T::isRequired(); 97 } 98 template <typename T> 99 static std::enable_if_t<!is_detected<has_required_t, T>::value, bool> passIsRequiredImplPassModel100 passIsRequiredImpl() { 101 return false; 102 } 103 isRequiredPassModel104 bool isRequired() const override { return passIsRequiredImpl<PassT>(); } 105 106 PassT Pass; 107 }; 108 109 /// Abstract concept of an analysis result. 110 /// 111 /// This concept is parameterized over the IR unit that this result pertains 112 /// to. 113 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT> 114 struct AnalysisResultConcept { 115 virtual ~AnalysisResultConcept() = default; 116 117 /// Method to try and mark a result as invalid. 118 /// 119 /// When the outer analysis manager detects a change in some underlying 120 /// unit of the IR, it will call this method on all of the results cached. 121 /// 122 /// \p PA is a set of preserved analyses which can be used to avoid 123 /// invalidation because the pass which changed the underlying IR took care 124 /// to update or preserve the analysis result in some way. 125 /// 126 /// \p Inv is typically a \c AnalysisManager::Invalidator object that can be 127 /// used by a particular analysis result to discover if other analyses 128 /// results are also invalidated in the event that this result depends on 129 /// them. See the documentation in the \c AnalysisManager for more details. 130 /// 131 /// \returns true if the result is indeed invalid (the default). 132 virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, 133 InvalidatorT &Inv) = 0; 134 }; 135 136 /// SFINAE metafunction for computing whether \c ResultT provides an 137 /// \c invalidate member function. 138 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod { 139 using EnabledType = char; 140 struct DisabledType { 141 char a, b; 142 }; 143 144 // Purely to help out MSVC which fails to disable the below specialization, 145 // explicitly enable using the result type's invalidate routine if we can 146 // successfully call that routine. 147 template <typename T> struct Nonce { using Type = EnabledType; }; 148 template <typename T> 149 static typename Nonce<decltype(std::declval<T>().invalidate( 150 std::declval<IRUnitT &>(), std::declval<PreservedAnalyses>()))>::Type 151 check(rank<2>); 152 153 // First we define an overload that can only be taken if there is no 154 // invalidate member. We do this by taking the address of an invalidate 155 // member in an adjacent base class of a derived class. This would be 156 // ambiguous if there were an invalidate member in the result type. 157 template <typename T, typename U> static DisabledType NonceFunction(T U::*); 158 struct CheckerBase { int invalidate; }; 159 template <typename T> struct Checker : CheckerBase, T {}; 160 template <typename T> 161 static decltype(NonceFunction(&Checker<T>::invalidate)) check(rank<1>); 162 163 // Now we have the fallback that will only be reached when there is an 164 // invalidate member, and enables the trait. 165 template <typename T> 166 static EnabledType check(rank<0>); 167 168 public: 169 enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) }; 170 }; 171 172 /// Wrapper to model the analysis result concept. 173 /// 174 /// By default, this will implement the invalidate method with a trivial 175 /// implementation so that the actual analysis result doesn't need to provide 176 /// an invalidation handler. It is only selected when the invalidation handler 177 /// is not part of the ResultT's interface. 178 template <typename IRUnitT, typename PassT, typename ResultT, 179 typename PreservedAnalysesT, typename InvalidatorT, 180 bool HasInvalidateHandler = 181 ResultHasInvalidateMethod<IRUnitT, ResultT>::Value> 182 struct AnalysisResultModel; 183 184 /// Specialization of \c AnalysisResultModel which provides the default 185 /// invalidate functionality. 186 template <typename IRUnitT, typename PassT, typename ResultT, 187 typename PreservedAnalysesT, typename InvalidatorT> 188 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, 189 InvalidatorT, false> 190 : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> { 191 explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} 192 // We have to explicitly define all the special member functions because MSVC 193 // refuses to generate them. 194 AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} 195 AnalysisResultModel(AnalysisResultModel &&Arg) 196 : Result(std::move(Arg.Result)) {} 197 198 friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { 199 using std::swap; 200 swap(LHS.Result, RHS.Result); 201 } 202 203 AnalysisResultModel &operator=(AnalysisResultModel RHS) { 204 swap(*this, RHS); 205 return *this; 206 } 207 208 /// The model bases invalidation solely on being in the preserved set. 209 // 210 // FIXME: We should actually use two different concepts for analysis results 211 // rather than two different models, and avoid the indirect function call for 212 // ones that use the trivial behavior. 213 bool invalidate(IRUnitT &, const PreservedAnalysesT &PA, 214 InvalidatorT &) override { 215 auto PAC = PA.template getChecker<PassT>(); 216 return !PAC.preserved() && 217 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>(); 218 } 219 220 ResultT Result; 221 }; 222 223 /// Specialization of \c AnalysisResultModel which delegates invalidate 224 /// handling to \c ResultT. 225 template <typename IRUnitT, typename PassT, typename ResultT, 226 typename PreservedAnalysesT, typename InvalidatorT> 227 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, 228 InvalidatorT, true> 229 : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> { 230 explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} 231 // We have to explicitly define all the special member functions because MSVC 232 // refuses to generate them. 233 AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} 234 AnalysisResultModel(AnalysisResultModel &&Arg) 235 : Result(std::move(Arg.Result)) {} 236 237 friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { 238 using std::swap; 239 swap(LHS.Result, RHS.Result); 240 } 241 242 AnalysisResultModel &operator=(AnalysisResultModel RHS) { 243 swap(*this, RHS); 244 return *this; 245 } 246 247 /// The model delegates to the \c ResultT method. 248 bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, 249 InvalidatorT &Inv) override { 250 return Result.invalidate(IR, PA, Inv); 251 } 252 253 ResultT Result; 254 }; 255 256 /// Abstract concept of an analysis pass. 257 /// 258 /// This concept is parameterized over the IR unit that it can run over and 259 /// produce an analysis result. 260 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT, 261 typename... ExtraArgTs> 262 struct AnalysisPassConcept { 263 virtual ~AnalysisPassConcept() = default; 264 265 /// Method to run this analysis over a unit of IR. 266 /// \returns A unique_ptr to the analysis result object to be queried by 267 /// users. 268 virtual std::unique_ptr< 269 AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> 270 run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, 271 ExtraArgTs... ExtraArgs) = 0; 272 273 /// Polymorphic method to access the name of a pass. 274 virtual StringRef name() const = 0; 275 }; 276 277 /// Wrapper to model the analysis pass concept. 278 /// 279 /// Can wrap any type which implements a suitable \c run method. The method 280 /// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments 281 /// and produce an object which can be wrapped in a \c AnalysisResultModel. 282 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT, 283 typename InvalidatorT, typename... ExtraArgTs> 284 struct AnalysisPassModel : AnalysisPassConcept<IRUnitT, PreservedAnalysesT, 285 InvalidatorT, ExtraArgTs...> { 286 explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} 287 // We have to explicitly define all the special member functions because MSVC 288 // refuses to generate them. 289 AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} 290 AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} 291 292 friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { 293 using std::swap; 294 swap(LHS.Pass, RHS.Pass); 295 } 296 297 AnalysisPassModel &operator=(AnalysisPassModel RHS) { 298 swap(*this, RHS); 299 return *this; 300 } 301 302 // FIXME: Replace PassT::Result with type traits when we use C++11. 303 using ResultModelT = 304 AnalysisResultModel<IRUnitT, PassT, typename PassT::Result, 305 PreservedAnalysesT, InvalidatorT>; 306 307 /// The model delegates to the \c PassT::run method. 308 /// 309 /// The return is wrapped in an \c AnalysisResultModel. 310 std::unique_ptr< 311 AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>> 312 run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM, 313 ExtraArgTs... ExtraArgs) override { 314 return std::make_unique<ResultModelT>( 315 Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)); 316 } 317 318 /// The model delegates to a static \c PassT::name method. 319 /// 320 /// The returned string ref must point to constant immutable data! 321 StringRef name() const override { return PassT::name(); } 322 323 PassT Pass; 324 }; 325 326 } // end namespace detail 327 328 } // end namespace llvm 329 330 #endif // LLVM_IR_PASSMANAGERINTERNAL_H 331