Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1527,6 +1527,8 @@ /// The underlying Region. Region &R; + /// The name of the SCoP (identical to the regions name) + std::string name; // Access functions of the SCoP. // @@ -2129,6 +2131,8 @@ /// could be executed. bool isEmpty() const { return Stmts.empty(); } + const StringRef getName() const { return name; } + typedef ArrayInfoSetTy::iterator array_iterator; typedef ArrayInfoSetTy::const_iterator const_array_iterator; typedef iterator_range array_range; @@ -2711,6 +2715,7 @@ iterator end() { return RegionToScopMap.end(); } const_iterator begin() const { return RegionToScopMap.begin(); } const_iterator end() const { return RegionToScopMap.end(); } + bool empty() const { return RegionToScopMap.empty(); } }; struct ScopInfoAnalysis : public AnalysisInfoMixin { Index: include/polly/ScopPass.h =================================================================== --- include/polly/ScopPass.h +++ include/polly/ScopPass.h @@ -6,24 +6,93 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// // This file defines the ScopPass class. ScopPasses are just RegionPasses, -// except they operate on Polly IR (Scop and ScopStmt) built by ScopInfo Pass. -// Because they operate on Polly IR, not the LLVM IR, ScopPasses are not allowed -// to modify the LLVM IR. Due to this limitation, the ScopPass class takes -// care of declaring that no LLVM passes are invalidated. +// except they operate on Polly IR (Scop and ScopStmt) built by ScopInfo +// Pass. Because they operate on Polly IR, not the LLVM IR, ScopPasses are not +// allowed to modify the LLVM IR. Due to this limitation, the ScopPass class +// takes care of declaring that no LLVM passes are invalidated. // //===----------------------------------------------------------------------===// #ifndef POLLY_SCOP_PASS_H #define POLLY_SCOP_PASS_H +#include "polly/ScopInfo.h" +#include "llvm/ADT/PriorityWorklist.h" #include "llvm/Analysis/RegionPass.h" +#include "llvm/IR/PassManager.h" using namespace llvm; namespace polly { class Scop; +struct ScopStandardAnalysisResults; + +using ScopAnalysisManager = + AnalysisManager; +using ScopAnalysisManagerFunctionProxy = + InnerAnalysisManagerProxy; +using FunctionAnalysisManagerScopProxy = + OuterAnalysisManagerProxy; +} // namespace polly + +namespace llvm { +using polly::Scop; +using polly::ScopInfo; +using polly::ScopAnalysisManager; +using polly::ScopStandardAnalysisResults; +using polly::ScopAnalysisManagerFunctionProxy; + +template <> +class InnerAnalysisManagerProxy::Result { +public: + explicit Result(ScopAnalysisManager &InnerAM, ScopInfo &SI) + : InnerAM(&InnerAM), SI(&SI) {} + Result(Result &&R) : InnerAM(std::move(R.InnerAM)), SI(R.SI) { + R.InnerAM = nullptr; + } + Result &operator=(Result &&RHS) { + InnerAM = RHS.InnerAM; + SI = RHS.SI; + RHS.InnerAM = nullptr; + return *this; + } + ~Result() { + if (!InnerAM) + return; + InnerAM->clear(); + } + + ScopAnalysisManager &getManager() { return *InnerAM; } + + bool invalidate(Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv); + +private: + ScopAnalysisManager *InnerAM; + ScopInfo *SI; +}; + +template <> +InnerAnalysisManagerProxy::Result +InnerAnalysisManagerProxy::run( + Function &F, FunctionAnalysisManager &FAM); + +template <> +PreservedAnalyses +PassManager::run( + Scop &InitialS, ScopAnalysisManager &AM, ScopStandardAnalysisResults &); +extern template class PassManager; +extern template class InnerAnalysisManagerProxy; +extern template class OuterAnalysisManagerProxy; +} // namespace llvm + +namespace polly { +using ScopPassManager = + PassManager; /// ScopPass - This class adapts the RegionPass interface to allow convenient /// creation of passes that operate on the Polly IR. Instead of overriding @@ -52,6 +121,57 @@ void print(raw_ostream &OS, const Module *) const override; }; +struct ScopStandardAnalysisResults { + DominatorTree &DT; + ScalarEvolution &SE; + LoopInfo &LI; + RegionInfo &RI; +}; + +template +class FunctionToScopPassAdaptor + : public PassInfoMixin> { +public: + explicit FunctionToScopPassAdaptor(ScopPassT Pass) : Pass(std::move(Pass)) {} + + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { + PreservedAnalyses PA = PreservedAnalyses::all(); + auto &Scops = AM.getResult(F); + if (Scops.empty()) + return PA; + + ScopAnalysisManager &SAM = + AM.getResult(F).getManager(); + + ScopStandardAnalysisResults AR = {AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + AM.getResult(F)}; + + for (auto &S : Scops) { + if (auto *scop = S.second.get()) { + PreservedAnalyses PassPA = Pass.run(*scop, SAM, AR); + + SAM.invalidate(*scop, PassPA); + PA.intersect(std::move(PassPA)); + } + } + + PA.preserveSet>(); + PA.preserve(); + return PA; + } + +private: + ScopPassT Pass; +}; // namespace polly + +template +FunctionToScopPassAdaptor +createFunctionToScopPassAdaptor(ScopPassT Pass) { + return FunctionToScopPassAdaptor(std::move(Pass)); +} + } // namespace polly #endif Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -3221,9 +3221,9 @@ Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI, ScopDetection::DetectionContext &DC) - : SE(&ScalarEvolution), R(R), IsOptimized(false), - HasSingleExitEdge(R.getExitingBlock()), HasErrorBlock(false), - MaxLoopDepth(0), CopyStmtsNum(0), DC(DC), + : SE(&ScalarEvolution), R(R), name("Scop for region " + R.getNameStr()), + IsOptimized(false), HasSingleExitEdge(R.getExitingBlock()), + HasErrorBlock(false), MaxLoopDepth(0), CopyStmtsNum(0), DC(DC), IslCtx(isl_ctx_alloc(), isl_ctx_free), Context(nullptr), Affinator(this, LI), AssumedContext(nullptr), InvalidContext(nullptr), Schedule(nullptr) { Index: lib/Analysis/ScopPass.cpp =================================================================== --- lib/Analysis/ScopPass.cpp +++ lib/Analysis/ScopPass.cpp @@ -14,6 +14,8 @@ #include "polly/ScopPass.h" #include "polly/ScopInfo.h" +#include "llvm/Analysis/AssumptionCache.h" + using namespace llvm; using namespace polly; @@ -35,3 +37,100 @@ AU.addRequired(); AU.setPreservesAll(); } + +namespace llvm { + +template class PassManager; +template class InnerAnalysisManagerProxy; +template class OuterAnalysisManagerProxy; + +template <> +PreservedAnalyses +PassManager::run( + Scop &S, ScopAnalysisManager &AM, ScopStandardAnalysisResults &AR) { + auto PA = PreservedAnalyses::all(); + for (auto &Pass : Passes) { + auto PassPA = Pass->run(S, AM, AR); + + AM.invalidate(S, PassPA); + PA.intersect(std::move(PassPA)); + } + + // All analyses for 'this' Scop have been invalidated above. Different Scops + // aren't affected + // FIXME is this correct wrt. the current pass behaviours? + PA.preserveSet>(); + return PA; +} + +bool ScopAnalysisManagerFunctionProxy::Result::invalidate( + Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv) { + + // First, check whether our ScopInfo is about to be invalidated + auto PAC = PA.getChecker(); + if (!(PAC.preserved() || PAC.preservedSet>() || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA))) { + + // As everything depends on ScopInfo, we must drop all existing results + for (auto &S : *SI) + if (auto *scop = S.second.get()) + if (InnerAM) + InnerAM->clear(*scop); + + InnerAM = nullptr; + return true; // Invalidate the proxy result as well. + } + + bool allPreserverd = PA.allAnalysesInSetPreserved>(); + + // Invalidate all non-preserved analyses + // Even if all analyses were preserved, we still need to run deferred + // invalidation + for (auto &S : *SI) { + Optional InnerPA; + auto *scop = S.second.get(); + if (!scop) + continue; + + if (auto *OuterProxy = + InnerAM->getCachedResult(*scop)) { + for (const auto &InvPair : OuterProxy->getOuterInvalidations()) { + auto *OuterAnalysisID = InvPair.first; + const auto &InnerAnalysisIDs = InvPair.second; + + if (Inv.invalidate(OuterAnalysisID, F, PA)) { + if (!InnerPA) + InnerPA = PA; + for (auto *InnerAnalysisID : InnerAnalysisIDs) + InnerPA->abandon(InnerAnalysisID); + } + } + + if (InnerPA) { + InnerAM->invalidate(*scop, *InnerPA); + continue; + } + } + + if (!allPreserverd) + InnerAM->invalidate(*scop, PA); + } + + return false; // This proxy is still valid +} + +template <> +ScopAnalysisManagerFunctionProxy::Result +ScopAnalysisManagerFunctionProxy::run(Function &F, + FunctionAnalysisManager &FAM) { + return Result(*InnerAM, FAM.getResult(F)); +} +} // namespace llvm Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -22,3 +22,4 @@ add_subdirectory(Isl) add_subdirectory(Flatten) add_subdirectory(DeLICM) +add_subdirectory(ScopPassManager) Index: unittests/ScopPassManager/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/ScopPassManager/CMakeLists.txt @@ -0,0 +1,3 @@ +add_polly_unittest(ScopPassManagerTests + PassManagerTest.cpp + ) Index: unittests/ScopPassManager/PassManagerTest.cpp =================================================================== --- /dev/null +++ unittests/ScopPassManager/PassManagerTest.cpp @@ -0,0 +1,66 @@ +#include "polly/CodeGen/IslAst.h" +#include "polly/DependenceInfo.h" +#include "polly/ScopPass.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "gtest/gtest.h" + +using namespace polly; +using namespace llvm; + +namespace { +class ScopPassRegistry : public ::testing::Test { +protected: + ModuleAnalysisManager MAM; + FunctionAnalysisManager FAM; + LoopAnalysisManager LAM; + CGSCCAnalysisManager CGAM; + ScopAnalysisManager SAM; + AAManager AM; + +public: + ScopPassRegistry(ScopPassRegistry &&) = delete; + ScopPassRegistry(const ScopPassRegistry &) = delete; + ScopPassRegistry &operator=(ScopPassRegistry &&) = delete; + ScopPassRegistry &operator=(const ScopPassRegistry &) = delete; + ScopPassRegistry() { + PassBuilder PB; + + AM = PB.buildDefaultAAPipeline(); + PB.registerModuleAnalyses(MAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.registerCGSCCAnalyses(CGAM); + + FAM.registerPass([] { return ScopAnalysis(); }); + FAM.registerPass([] { return ScopInfoAnalysis(); }); + FAM.registerPass([this] { return ScopAnalysisManagerFunctionProxy(SAM); }); + + SAM.registerPass([] { return IslAstAnalysis(); }); + SAM.registerPass([] { return DependenceAnalysis(); }); + SAM.registerPass([this] { return FunctionAnalysisManagerScopProxy(FAM); }); + + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + } +}; + +TEST_F(ScopPassRegistry, PrintScops) { + FunctionPassManager FPM; + FPM.addPass(ScopAnalysisPrinterPass(errs())); +} + +TEST_F(ScopPassRegistry, PrintScopInfo) { + FunctionPassManager FPM; + FPM.addPass(ScopInfoPrinterPass(errs())); +} + +TEST_F(ScopPassRegistry, PrinIslAstInfo) { + FunctionPassManager FPM; + ScopPassManager SPM; + SPM.addPass(IslAstPrinterPass(errs())); + FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); +} +} // namespace