Index: llvm/include/llvm/IR/PassManager.h =================================================================== --- llvm/include/llvm/IR/PassManager.h +++ llvm/include/llvm/IR/PassManager.h @@ -879,18 +879,20 @@ /// \brief Convenience typedef for the Function analysis manager. typedef AnalysisManager FunctionAnalysisManager; -/// \brief A module analysis which acts as a proxy for a function analysis -/// manager. +/// \brief An analysis over a "larger" IR unit that provides access to an +/// analysis manager over a "smaller" IR unit. /// -/// This primarily proxies invalidation information from the module analysis -/// manager and module pass manager to a function analysis manager. You should -/// never use a function analysis manager from within (transitively) a module -/// pass manager unless your parent module pass has received a proxy result -/// object for it. +/// For example, you might have an +/// InnerAnalysisManagerProxy. This is an +/// analysis over Modules that provides access to a Function analysis manager. +/// (The FunctionAnalysisManager is the "inner" manager being proxied.) /// -/// Note that the proxy's result is a move-only object and represents ownership -/// of the validity of the analyses in the \c FunctionAnalysisManager it -/// provides. +/// You should never use a "smaller" analysis manager from within (transitively) +/// a "larger" pass manager unless you have received a proxy result object for +/// the smaller analysis manager. +/// +/// Note that the proxy's result is a move-only RAII object. The validity of +/// the analyses in the "smaller" analysis manager is tied to its lifetime. template class InnerAnalysisManagerProxy : public AnalysisInfoMixin< @@ -898,57 +900,39 @@ public: class Result { public: - explicit Result(AnalysisManagerT &InnerAM) : InnerAM(&InnerAM) {} - Result(Result &&Arg) : InnerAM(std::move(Arg.InnerAM)) { - // We have to null out the analysis manager in the moved-from state - // because we are taking ownership of the responsibilty to clear the - // analysis state. - Arg.InnerAM = nullptr; - } + explicit Result(AnalysisManagerT &AM) : AM(&AM) {} + Result(Result &&RHS) : AM(std::move(RHS.AM)) { RHS.AM = nullptr; } Result &operator=(Result &&RHS) { - InnerAM = RHS.InnerAM; - // We have to null out the analysis manager in the moved-from state - // because we are taking ownership of the responsibilty to clear the - // analysis state. - RHS.InnerAM = nullptr; + AM = RHS.AM; + RHS.AM = nullptr; return *this; } ~Result() { - // InnerAM is cleared in a moved from state where there is nothing to do. - if (!InnerAM) - return; - // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. - InnerAM->clear(); + if (AM) + AM->clear(); } /// \brief Accessor for the analysis manager. - AnalysisManagerT &getManager() { return *InnerAM; } + AnalysisManagerT &getManager() { return *AM; } - /// \brief Handler for invalidation of the outer IR unit. + /// \brief Handler for invalidation of the "larger" IR unit, \c IRUnitT. /// - /// If this analysis itself is preserved, then we assume that the set of \c - /// IR units that the inner analysis manager controls hasn't changed and - /// thus we don't need to invalidate *all* cached data associated with any - /// \c IRUnitT* in the \c AnalysisManagerT. + /// If the proxy analysis itself is not preserved, we assume that the set of + /// "smaller" objects contained in IRUnit may have changed. In this case, + /// we have to call \c clear() on the inner analysis manager, as it may now + /// have stale pointers to its "smaller" objects. /// - /// Regardless of whether this analysis is marked as preserved, all of the - /// analyses in the \c AnalysisManagerT are potentially invalidated (for - /// the relevant inner set of their IR units) based on the set of preserved - /// analyses. - /// - /// Because this needs to understand the mapping from one IR unit to an - /// inner IR unit, this method isn't defined in the primary template. - /// Instead, each specialization of this template will need to provide an - /// explicit specialization of this method to handle that particular pair - /// of IR unit and inner AnalysisManagerT. + /// Regardless of whether the proxy analysis is marked as preserved, all of + /// the analyses in the inner analysis manager are potentially invalidated + /// based on the set of preserved analyses. bool invalidate( IRUnitT &IR, const PreservedAnalyses &PA, typename AnalysisManager::Invalidator &Inv); private: - AnalysisManagerT *InnerAM; + AnalysisManagerT *AM; }; explicit InnerAnalysisManagerProxy(AnalysisManagerT &InnerAM) @@ -956,13 +940,9 @@ /// \brief Run the analysis pass and create our proxy result object. /// - /// This doesn't do any interesting work, it is primarily used to insert our - /// proxy result object into the module analysis cache so that we can proxy - /// invalidation to the function analysis manager. - /// - /// In debug builds, it will also assert that the analysis manager is empty - /// as no queries should arrive at the function analysis manager prior to - /// this analysis being requested. + /// This doesn't do any interesting work; it is primarily used to insert our + /// proxy result object into the "larger" analysis cache so that we can proxy + /// invalidation to the "smaller" analysis manager. Result run(IRUnitT &IR, AnalysisManager &AM, ExtraArgTs...) { return Result(*InnerAM); @@ -996,22 +976,23 @@ extern template class InnerAnalysisManagerProxy; -/// \brief A function analysis which acts as a proxy for a module analysis -/// manager. +/// \brief An analysis over a "smaller" IR unit that provides access to an +/// analysis manager over a "larger" IR unit. /// -/// This primarily provides an accessor to a parent module analysis manager to -/// function passes. Only the const interface of the module analysis manager is -/// provided to indicate that once inside of a function analysis pass you -/// cannot request a module analysis to actually run. Instead, the user must -/// rely on the \c getCachedResult API. +/// For example, you might have an +/// OuterAnalysisManagerProxy. This is an +/// analysis over Functions which provides access to a Module analysis manager. +/// (The ModuleAnalysisManager is the "outer" manager being proxied.) /// -/// The invalidation provided by this proxy involves tracking when an -/// invalidation event in the outer analysis manager needs to trigger an -/// invalidation of a particular analysis on this IR unit. +/// Only the const interface of the proxied analysis manager is provided to +/// indicate that once inside of a "smaller" analysis pass you cannot request a +/// module analysis to actually run. Instead, the user must rely on the \c +/// getCachedResult API. /// -/// Because outer analyses aren't invalidated while these IR units are being -/// precessed, we have to register and handle these as deferred invalidation -/// events. +/// This proxy doesn't manage invalidation in any way -- that is handled by the +/// recursive return path of each layer of the pass manager. A consequence of +/// this is, the "larger" analyses may be stale. We update the "larger" +/// analyses only when we're done running passes over the "smaller" IR units. template class OuterAnalysisManagerProxy : public AnalysisInfoMixin< @@ -1024,7 +1005,7 @@ const AnalysisManagerT &getManager() const { return *AM; } - /// \brief Handle invalidation by ignoring it, this pass is immutable. + /// \brief Handle invalidation by ignoring it; this pass is immutable. bool invalidate( IRUnitT &, const PreservedAnalyses &, typename AnalysisManager::Invalidator &) { @@ -1089,18 +1070,15 @@ extern template class OuterAnalysisManagerProxy; -/// Provide the \c ModuleAnalysisManager to \c Fucntion proxy. +/// Provide the \c ModuleAnalysisManager to \c Function proxy. typedef OuterAnalysisManagerProxy ModuleAnalysisManagerFunctionProxy; /// \brief Trivial adaptor that maps from a module to its functions. /// /// Designed to allow composition of a FunctionPass(Manager) and -/// a ModulePassManager. Note that if this pass is constructed with a pointer -/// to a \c ModuleAnalysisManager it will run the -/// \c FunctionAnalysisManagerModuleProxy analysis prior to running the function -/// pass over the module to enable a \c FunctionAnalysisManager to be used -/// within this run safely. +/// a ModulePassManager, by running the FunctionPass(Manager) over every +/// function in the module. /// /// Function passes run within this adaptor can rely on having exclusive access /// to the function they are run over. They should not read or modify any other @@ -1115,6 +1093,10 @@ /// module. /// FIXME: Make the above true for all of LLVM's actual passes, some still /// violate this principle. +/// +/// Note that although function passes can access module analyses, module +/// analyses are not invalidated while the function passes are running, so they +/// may be stale. Function analyses will not be stale. template class ModuleToFunctionPassAdaptor : public PassInfoMixin> { @@ -1124,7 +1106,6 @@ /// \brief Runs the function pass across every function in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { - // Setup the function analysis manager from its proxy. FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); @@ -1145,10 +1126,11 @@ PA.intersect(std::move(PassPA)); } - // By definition we preserve the proxy. We also preserve all analyses on - // Function units. This precludes *any* invalidation of function analyses - // by the proxy, but that's OK because we've taken care to invalidate - // analyses in the function analysis manager incrementally above. + // The FunctionAnalysisManagerModuleProxy is preserved because (we assume) + // the function passes we ran didn't add or remove any functions. + // + // We also preserve all analyses on Function units, because we did all the + // invalidation we needed to do above. PA.preserveSet>(); PA.preserve(); return PA; @@ -1166,7 +1148,7 @@ return ModuleToFunctionPassAdaptor(std::move(Pass)); } -/// \brief A template utility pass to force an analysis result to be available. +/// \brief A utility pass template to force an analysis result to be available. /// /// If there are extra arguments at the pass's run level there may also be /// extra arguments to the analysis manager's \c getResult routine. We can't @@ -1196,17 +1178,14 @@ } }; -/// \brief A template utility pass to force an analysis result to be -/// invalidated. -/// -/// This is a no-op pass which simply forces a specific analysis result to be -/// invalidated when it is run. +/// \brief A no-op pass template which simply forces a specific analysis result +/// to be invalidated. template struct InvalidateAnalysisPass : PassInfoMixin> { /// \brief Run this pass over some unit of IR. /// - /// This pass can be run over any unit of IR and use any analysis manager + /// This pass can be run over any unit of IR and use any analysis manager, /// provided they satisfy the basic API requirements. When this pass is /// created, these methods can be instantiated to satisfy whatever the /// context requires. @@ -1218,10 +1197,10 @@ } }; -/// \brief A utility pass that does nothing but preserves no analyses. +/// \brief A utility pass that does nothing, but preserves no analyses. /// -/// As a consequence fo not preserving any analyses, this pass will force all -/// analysis passes to be re-run to produce fresh results if any are needed. +/// Because this preserves no analyses, any analysis passes queried after this +/// pass runs will recompute fresh results. struct InvalidateAllAnalysesPass : PassInfoMixin { /// \brief Run this pass over some unit of IR. template @@ -1257,6 +1236,6 @@ return RepeatedPass(Count, std::move(P)); } -} +} // namespace llvm #endif Index: llvm/lib/Analysis/LoopPassManager.cpp =================================================================== --- llvm/lib/Analysis/LoopPassManager.cpp +++ llvm/lib/Analysis/LoopPassManager.cpp @@ -29,13 +29,12 @@ bool LoopAnalysisManagerFunctionProxy::Result::invalidate( Function &F, const PreservedAnalyses &PA, FunctionAnalysisManager::Invalidator &Inv) { - // If this proxy isn't marked as preserved, the set of Function objects in - // the module may have changed. We therefore can't call - // InnerAM->invalidate(), because any pointers to Functions it has may be - // stale. + // If this proxy isn't marked as preserved, the set of Function objects in the + // module may have changed. We therefore can't call AM->invalidate(), because + // any pointers to Functions it has may be stale. auto PAC = PA.getChecker(); if (!PAC.preserved() && !PAC.preservedSet>()) - InnerAM->clear(); + AM->clear(); // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM. Index: llvm/lib/IR/PassManager.cpp =================================================================== --- llvm/lib/IR/PassManager.cpp +++ llvm/lib/IR/PassManager.cpp @@ -43,7 +43,7 @@ // cached on functions *still in the module* at the end of the module pass. auto PAC = PA.getChecker(); if (!PAC.preserved() && !PAC.preservedSet>()) { - InnerAM->clear(); + AM->clear(); return true; } @@ -60,7 +60,7 @@ // module-level analysis invalidation that triggers deferred invalidation // registered with the outer analysis manager proxy for this function. if (auto *OuterProxy = - InnerAM->getCachedResult(F)) + AM->getCachedResult(F)) for (const auto &OuterInvalidationPair : OuterProxy->getOuterInvalidations()) { AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first; @@ -76,14 +76,14 @@ // Check if we needed a custom PA set, and if so we'll need to run the // inner invalidation. if (FunctionPA) { - InnerAM->invalidate(F, *FunctionPA); + AM->invalidate(F, *FunctionPA); continue; } // Otherwise we only need to do invalidation if the original PA set didn't // preserve all function analyses. if (!AreFunctionAnalysesPreserved) - InnerAM->invalidate(F, PA); + AM->invalidate(F, PA); } // Return false to indicate that this result is still a valid proxy.