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