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