diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 2664657694f..3fccdf4e3f2 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -36,6 +36,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/polymorphic_ptr.h" #include "llvm/Support/type_traits.h" #include "llvm/IR/Function.h" @@ -48,6 +49,106 @@ namespace llvm { class Module; class Function; +/// \brief An abstract set of preserved analyses following a transformation pass +/// run. +/// +/// When a transformation pass is run, it can return a set of analyses whose +/// results were preserved by that transformation. The default set is "none", +/// and preserving analyses must be done explicitly. +/// +/// There is also an explicit all state which can be used (for example) when +/// the IR is not mutated at all. +class PreservedAnalyses { +public: + /// \brief Convenience factory function for the empty preserved set. + static PreservedAnalyses none() { return PreservedAnalyses(); } + + /// \brief Construct a special preserved set that preserves all passes. + static PreservedAnalyses all() { + PreservedAnalyses PA; + PA.PreservedPassIDs.insert((void *)AllPassesID); + return PA; + } + + PreservedAnalyses &operator=(PreservedAnalyses Arg) { + swap(Arg); + return *this; + } + + void swap(PreservedAnalyses &Arg) { + PreservedPassIDs.swap(Arg.PreservedPassIDs); + } + + /// \brief Mark a particular pass as preserved, adding it to the set. + template void preserve() { + if (!areAllPreserved()) + PreservedPassIDs.insert(PassT::ID()); + } + + /// \brief Intersect this set with another in place. + /// + /// This is a mutating operation on this preserved set, removing all + /// preserved passes which are not also preserved in the argument. + void intersect(const PreservedAnalyses &Arg) { + if (Arg.areAllPreserved()) + return; + if (areAllPreserved()) { + PreservedPassIDs = Arg.PreservedPassIDs; + return; + } + for (SmallPtrSet::const_iterator I = PreservedPassIDs.begin(), + E = PreservedPassIDs.end(); + I != E; ++I) + if (!Arg.PreservedPassIDs.count(*I)) + PreservedPassIDs.erase(*I); + } + +#if LLVM_HAS_RVALUE_REFERENCES + /// \brief Intersect this set with a temporary other set in place. + /// + /// This is a mutating operation on this preserved set, removing all + /// preserved passes which are not also preserved in the argument. + void intersect(PreservedAnalyses &&Arg) { + if (Arg.areAllPreserved()) + return; + if (areAllPreserved()) { + PreservedPassIDs = std::move(Arg.PreservedPassIDs); + return; + } + for (SmallPtrSet::const_iterator I = PreservedPassIDs.begin(), + E = PreservedPassIDs.end(); + I != E; ++I) + if (!Arg.PreservedPassIDs.count(*I)) + PreservedPassIDs.erase(*I); + } +#endif + + /// \brief Query whether a pass is marked as preserved by this set. + template bool preserved() const { + return preserved(PassT::ID()); + } + + /// \brief Query whether an abstract pass ID is marked as preserved by this + /// set. + bool preserved(void *PassID) const { + return PreservedPassIDs.count((void *)AllPassesID) || + PreservedPassIDs.count(PassID); + } + +private: + // Note that this must not be -1 or -2 as those are already used by the + // SmallPtrSet. + static const uintptr_t AllPassesID = (intptr_t)-3; + + bool areAllPreserved() const { return PreservedPassIDs.count((void *)AllPassesID); } + + SmallPtrSet PreservedPassIDs; +}; + +inline void swap(PreservedAnalyses &LHS, PreservedAnalyses &RHS) { + LHS.swap(RHS); +} + /// \brief Implementation details of the pass manager interfaces. namespace detail { @@ -59,7 +160,7 @@ template struct PassConcept { virtual PassConcept *clone() = 0; /// \brief The polymorphic API which runs the pass over a given IR entity. - virtual bool run(T Arg) = 0; + virtual PreservedAnalyses run(T Arg) = 0; }; /// \brief A template wrapper used to implement the polymorphic API. @@ -70,7 +171,7 @@ template struct PassConcept { template struct PassModel : PassConcept { PassModel(PassT Pass) : Pass(llvm_move(Pass)) {} virtual PassModel *clone() { return new PassModel(Pass); } - virtual bool run(T Arg) { return Pass.run(Arg); } + virtual PreservedAnalyses run(T Arg) { return Pass.run(Arg); } PassT Pass; }; @@ -161,7 +262,7 @@ public: /// /// This method should only be called for a single module as there is the /// expectation that the lifetime of a pass is bounded to that of a module. - void run(Module *M); + PreservedAnalyses run(Module *M); template void addPass(ModulePassT Pass) { Passes.push_back(new ModulePassModel(llvm_move(Pass))); @@ -189,7 +290,7 @@ public: Passes.push_back(new FunctionPassModel(llvm_move(Pass))); } - bool run(Function *F); + PreservedAnalyses run(Function *F); private: // Pull in the concept type and model template specialized for functions. @@ -215,11 +316,13 @@ public: : Pass(llvm_move(Pass)) {} /// \brief Runs the function pass across every function in the module. - bool run(Module *M) { - bool Changed = false; - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - Changed |= Pass.run(I); - return Changed; + PreservedAnalyses run(Module *M) { + PreservedAnalyses PA = PreservedAnalyses::all(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { + PreservedAnalyses PassPA = Pass.run(I); + PA.intersect(llvm_move(PassPA)); + } + return PA; } private: @@ -286,12 +389,9 @@ public: /// \brief Invalidate analyses cached for an IR Module. /// - /// Note that specific analysis results can disregard invalidation by - /// overriding their invalidate method. - /// - /// The module must be the module this analysis manager was constructed - /// around. - void invalidateAll(Module *M); + /// Walk through all of the analyses pertaining to this module and invalidate + /// them unless they are preserved by the PreservedAnalyses set. + void invalidate(Module *M, const PreservedAnalyses &PA); private: /// \brief Get a module pass result, running the pass if necessary. @@ -371,9 +471,10 @@ public: /// \brief Invalidate analyses cached for an IR Function. /// - /// Note that specific analysis results can disregard invalidation by - /// overriding the invalidate method. - void invalidateAll(Function *F); + /// Walk through all of the analyses cache for this IR function and + /// invalidate them unless they are preserved by the provided + /// PreservedAnalyses set. + void invalidate(Function *F, const PreservedAnalyses &PA); private: /// \brief Get a function pass result, running the pass if necessary. diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index 35fc534151a..0508b3cb281 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -12,20 +12,24 @@ using namespace llvm; -void ModulePassManager::run(Module *M) { - for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) - if (Passes[Idx]->run(M)) - if (AM) - AM->invalidateAll(M); +PreservedAnalyses ModulePassManager::run(Module *M) { + PreservedAnalyses PA = PreservedAnalyses::all(); + for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { + PreservedAnalyses PassPA = Passes[Idx]->run(M); + if (AM) + AM->invalidate(M, PassPA); + PA.intersect(llvm_move(PassPA)); + } + return PA; } -void ModuleAnalysisManager::invalidateAll(Module *M) { +void ModuleAnalysisManager::invalidate(Module *M, const PreservedAnalyses &PA) { // FIXME: This is a total hack based on the fact that erasure doesn't // invalidate iteration for DenseMap. for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), E = ModuleAnalysisResults.end(); I != E; ++I) - if (I->second->invalidate(M)) + if (!PA.preserved(I->first) && I->second->invalidate(M)) ModuleAnalysisResults.erase(I); } @@ -53,18 +57,18 @@ void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) { ModuleAnalysisResults.erase(PassID); } -bool FunctionPassManager::run(Function *F) { - bool Changed = false; - for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) - if (Passes[Idx]->run(F)) { - Changed = true; - if (AM) - AM->invalidateAll(F); - } - return Changed; +PreservedAnalyses FunctionPassManager::run(Function *F) { + PreservedAnalyses PA = PreservedAnalyses::all(); + for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { + PreservedAnalyses PassPA = Passes[Idx]->run(F); + if (AM) + AM->invalidate(F, PassPA); + PA.intersect(llvm_move(PassPA)); + } + return PA; } -void FunctionAnalysisManager::invalidateAll(Function *F) { +void FunctionAnalysisManager::invalidate(Function *F, const PreservedAnalyses &PA) { // Clear all the invalidated results associated specifically with this // function. SmallVector InvalidatedPassIDs; @@ -72,7 +76,7 @@ void FunctionAnalysisManager::invalidateAll(Function *F) { for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(), E = ResultsList.end(); I != E;) - if (I->second->invalidate(F)) { + if (!PA.preserved(I->first) && I->second->invalidate(F)) { InvalidatedPassIDs.push_back(I->first); I = ResultsList.erase(I); } else { diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 1e02d6ba02b..f2ce2214764 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -52,9 +52,9 @@ char TestAnalysisPass::PassID; struct TestModulePass { TestModulePass(int &RunCount) : RunCount(RunCount) {} - bool run(Module *M) { + PreservedAnalyses run(Module *M) { ++RunCount; - return true; + return PreservedAnalyses::none(); } int &RunCount; @@ -65,13 +65,13 @@ struct TestFunctionPass { int &AnalyzedInstrCount) : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} - bool run(Function *F) { + PreservedAnalyses run(Function *F) { ++RunCount; const TestAnalysisPass::Result &AR = AM.getResult(F); AnalyzedInstrCount += AR.InstructionCount; - return true; + return PreservedAnalyses::none(); } FunctionAnalysisManager &AM;