Index: llvm/include/llvm/IR/PassManager.h =================================================================== --- llvm/include/llvm/IR/PassManager.h +++ llvm/include/llvm/IR/PassManager.h @@ -729,18 +729,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< @@ -749,22 +751,14 @@ class Result { public: explicit Result(AnalysisManagerT &AM) : AM(&AM) {} - Result(Result &&Arg) : AM(std::move(Arg.AM)) { - // 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.AM = nullptr; - } + Result(Result &&Arg) : AM(Arg.AM) { Arg.AM = nullptr; } Result &operator=(Result &&RHS) { AM = RHS.AM; - // 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.AM = nullptr; return *this; } ~Result() { - // AM is cleared in a moved from state where there is nothing to do. + // Null AM indicates we've been moved from, so there's nothing to do. if (!AM) return; @@ -776,23 +770,21 @@ /// \brief Accessor for the analysis manager. AnalysisManagerT &getManager() { return *AM; } - /// \brief Handler for invalidation of the module. + /// \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 - /// Function objects in the \c Module hasn't changed and thus we don't need - /// to invalidate *all* cached data associated with a \c Function* in the \c - /// FunctionAnalysisManager. + /// 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 FunctionAnalysisManager are potentially invalidated + /// 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 &) { - // If this proxy isn't marked as preserved, then we can't even invalidate - // individual function analyses, there may be an invalid set of Function - // objects in the cache making it impossible to incrementally preserve - // them. Just clear the entire manager. + // Clear AM if the proxy analysis is not preserved, as this indicates that + // the set of "smaller" IR units may have changed. if (!PA.preserved(InnerAnalysisManagerProxy::ID())) AM->clear(); @@ -808,13 +800,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 &, ExtraArgTs...) { return Result(*AM); @@ -838,18 +826,23 @@ typedef InnerAnalysisManagerProxy FunctionAnalysisManagerModuleProxy; -/// \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.) /// -/// This proxy *doesn't* manage the invalidation in any way. That is handled by -/// the recursive return path of each layer of the pass manager and the -/// returned PreservedAnalysis set. +/// 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. +/// +/// 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< @@ -862,7 +855,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 &) { @@ -897,18 +890,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 @@ -923,6 +913,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> { @@ -932,7 +926,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(); @@ -953,10 +946,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.preserve>(); PA.preserve(); return PA; @@ -974,7 +968,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 @@ -1004,23 +998,20 @@ } }; -/// \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. template PreservedAnalyses run(IRUnitT &Arg, AnalysisManagerT &AM, ExtraArgTs &&...) { - // We have to directly invalidate the analysis result as we can't + // We have to directly invalidate the analysis result, as we can't // enumerate all other analyses and use the preserved set to control it. AM.template invalidate(Arg); @@ -1028,10 +1019,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 @@ -1067,6 +1058,6 @@ return RepeatedPass(Count, std::move(P)); } -} +} // namespace llvm #endif