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