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