//===--------- ScopPass.h - Pass for Static Control Parts --------*-C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // 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. // //===----------------------------------------------------------------------===// #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/Analysis/TargetTransformInfo.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PassManagerImpl.h" namespace polly { using llvm::AllAnalysesOn; using llvm::AnalysisManager; using llvm::DominatorTreeAnalysis; using llvm::InnerAnalysisManagerProxy; using llvm::LoopAnalysis; using llvm::OuterAnalysisManagerProxy; using llvm::PassManager; using llvm::RegionInfoAnalysis; using llvm::ScalarEvolutionAnalysis; using llvm::SmallPriorityWorklist; using llvm::TargetIRAnalysis; using llvm::TargetTransformInfo; class Scop; class SPMUpdater; struct ScopStandardAnalysisResults; using ScopAnalysisManager = AnalysisManager; using ScopAnalysisManagerFunctionProxy = InnerAnalysisManagerProxy; using FunctionAnalysisManagerScopProxy = OuterAnalysisManagerProxy; } // namespace polly namespace llvm { using polly::Scop; using polly::ScopAnalysisManager; using polly::ScopAnalysisManagerFunctionProxy; using polly::ScopInfo; using polly::ScopStandardAnalysisResults; using polly::SPMUpdater; 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; }; // A partial specialization of the require analysis template pass to handle // extra parameters template struct RequireAnalysisPass : PassInfoMixin< RequireAnalysisPass> { PreservedAnalyses run(Scop &L, ScopAnalysisManager &AM, ScopStandardAnalysisResults &AR, SPMUpdater &) { (void)AM.template getResult(L, AR); return PreservedAnalyses::all(); } }; template <> InnerAnalysisManagerProxy::Result InnerAnalysisManagerProxy::run( Function &F, FunctionAnalysisManager &FAM); template <> PreservedAnalyses PassManager::run(Scop &InitialS, ScopAnalysisManager &AM, ScopStandardAnalysisResults &, SPMUpdater &); extern template class PassManager; extern template class InnerAnalysisManagerProxy; extern template class OuterAnalysisManagerProxy; } // namespace llvm namespace polly { template class OwningInnerAnalysisManagerProxy final : public InnerAnalysisManagerProxy { public: OwningInnerAnalysisManagerProxy() : InnerAnalysisManagerProxy(InnerAM) {} using Result = typename InnerAnalysisManagerProxy::Result; Result run(IRUnitT &IR, AnalysisManager &AM, ExtraArgTs...) { return Result(InnerAM); } AnalysisManagerT &getManager() { return InnerAM; } private: AnalysisManagerT InnerAM; }; template <> OwningInnerAnalysisManagerProxy::Result OwningInnerAnalysisManagerProxy::run( Function &F, FunctionAnalysisManager &FAM); extern template class OwningInnerAnalysisManagerProxy; using OwningScopAnalysisManagerFunctionProxy = OwningInnerAnalysisManagerProxy; 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 /// runOnRegion, subclasses override runOnScop. class ScopPass : public RegionPass { Scop *S; protected: explicit ScopPass(char &ID) : RegionPass(ID), S(nullptr) {} /// runOnScop - This method must be overloaded to perform the /// desired Polyhedral transformation or analysis. /// virtual bool runOnScop(Scop &S) = 0; /// Print method for SCoPs. virtual void printScop(raw_ostream &OS, Scop &S) const {} /// getAnalysisUsage - Subclasses that override getAnalysisUsage /// must call this. /// void getAnalysisUsage(AnalysisUsage &AU) const override; private: bool runOnRegion(Region *R, RGPassManager &RGM) override; void print(raw_ostream &OS, const Module *) const override; }; struct ScopStandardAnalysisResults { DominatorTree &DT; ScopInfo &SI; ScalarEvolution &SE; LoopInfo &LI; RegionInfo &RI; TargetTransformInfo &TTI; }; class SPMUpdater final { public: SPMUpdater(SmallPriorityWorklist &Worklist, ScopAnalysisManager &SAM) : InvalidateCurrentScop(false), Worklist(Worklist), SAM(SAM) {} bool invalidateCurrentScop() const { return InvalidateCurrentScop; } void invalidateScop(Scop &S) { if (&S == CurrentScop) InvalidateCurrentScop = true; Worklist.erase(&S.getRegion()); SAM.clear(S, S.getName()); } private: Scop *CurrentScop; bool InvalidateCurrentScop; SmallPriorityWorklist &Worklist; ScopAnalysisManager &SAM; template friend struct FunctionToScopPassAdaptor; }; template struct FunctionToScopPassAdaptor final : PassInfoMixin> { explicit FunctionToScopPassAdaptor(ScopPassT Pass) : Pass(std::move(Pass)) {} PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { ScopDetection &SD = AM.getResult(F); ScopInfo &SI = AM.getResult(F); if (SI.empty()) { // With no scops having been detected, no IR changes have been made and // therefore all analyses are preserved. However, we must still free the // Scop analysis results which may hold AssertingVH that cause an error // if its value is destroyed. PreservedAnalyses PA = PreservedAnalyses::all(); PA.abandon(); PA.abandon(); AM.invalidate(F, PA); return PreservedAnalyses::all(); } SmallPriorityWorklist Worklist; for (auto &S : SI) if (S.second) Worklist.insert(S.first); ScopStandardAnalysisResults AR = {AM.getResult(F), AM.getResult(F), AM.getResult(F), AM.getResult(F), AM.getResult(F), AM.getResult(F)}; ScopAnalysisManager &SAM = AM.getResult(F).getManager(); SPMUpdater Updater{Worklist, SAM}; while (!Worklist.empty()) { Region *R = Worklist.pop_back_val(); if (!SD.isMaxRegionInScop(*R, /*Verify=*/false)) continue; Scop *scop = SI.getScop(R); if (!scop) continue; Updater.CurrentScop = scop; Updater.InvalidateCurrentScop = false; PreservedAnalyses PassPA = Pass.run(*scop, SAM, AR, Updater); SAM.invalidate(*scop, PassPA); if (Updater.invalidateCurrentScop()) SI.recompute(); }; // FIXME: For the same reason as we add a BarrierNoopPass in the legacy pass // manager, do not preserve any analyses. While CodeGeneration may preserve // IR analyses sufficiently to process another Scop in the same function (it // has to, otherwise the ScopDetection result itself would need to be // invalidated), it is not sufficient for other purposes. For instance, // CodeGeneration does not inform LoopInfo about new loops in the // Polly-generated IR. return PreservedAnalyses::none(); } private: ScopPassT Pass; }; template FunctionToScopPassAdaptor createFunctionToScopPassAdaptor(ScopPassT Pass) { return FunctionToScopPassAdaptor(std::move(Pass)); } } // namespace polly #endif