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