blob: 7e5041e9fb54c528b697e47ae792c79f15ba9fe4 [file] [log] [blame]
//===--------- 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<Scop, ScopStandardAnalysisResults &>;
using ScopAnalysisManagerFunctionProxy =
InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
using FunctionAnalysisManagerScopProxy =
OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
ScopStandardAnalysisResults &>;
} // 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<ScopAnalysisManager, Function>::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 <typename AnalysisT>
struct RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
ScopStandardAnalysisResults &, SPMUpdater &>
: PassInfoMixin<
RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
ScopStandardAnalysisResults &, SPMUpdater &>> {
PreservedAnalyses run(Scop &L, ScopAnalysisManager &AM,
ScopStandardAnalysisResults &AR, SPMUpdater &) {
(void)AM.template getResult<AnalysisT>(L, AR);
return PreservedAnalyses::all();
}
};
template <>
InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
Function &F, FunctionAnalysisManager &FAM);
template <>
PreservedAnalyses
PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
SPMUpdater &>::run(Scop &InitialS, ScopAnalysisManager &AM,
ScopStandardAnalysisResults &, SPMUpdater &);
extern template class PassManager<Scop, ScopAnalysisManager,
ScopStandardAnalysisResults &, SPMUpdater &>;
extern template class InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
ScopStandardAnalysisResults &>;
} // namespace llvm
namespace polly {
template <typename AnalysisManagerT, typename IRUnitT, typename... ExtraArgTs>
class OwningInnerAnalysisManagerProxy
: public InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT> {
public:
OwningInnerAnalysisManagerProxy()
: InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>(InnerAM) {}
using Result = typename InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT,
ExtraArgTs...>::Result;
Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
ExtraArgTs...) {
return Result(InnerAM);
}
AnalysisManagerT &getManager() { return InnerAM; }
private:
AnalysisManagerT InnerAM;
};
template <>
OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
Function &F, FunctionAnalysisManager &FAM);
extern template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager,
Function>;
using OwningScopAnalysisManagerFunctionProxy =
OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
using ScopPassManager =
PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
SPMUpdater &>;
/// 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(0) {}
/// 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.
///
virtual 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 {
public:
SPMUpdater(SmallPriorityWorklist<Region *, 4> &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<Region *, 4> &Worklist;
ScopAnalysisManager &SAM;
template <typename ScopPassT> friend class FunctionToScopPassAdaptor;
};
template <typename ScopPassT>
class FunctionToScopPassAdaptor
: public PassInfoMixin<FunctionToScopPassAdaptor<ScopPassT>> {
public:
explicit FunctionToScopPassAdaptor(ScopPassT Pass) : Pass(std::move(Pass)) {}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
ScopDetection &SD = AM.getResult<ScopAnalysis>(F);
ScopInfo &SI = AM.getResult<ScopInfoAnalysis>(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<ScopInfoAnalysis>();
PA.abandon<ScopAnalysis>();
AM.invalidate(F, PA);
return PreservedAnalyses::all();
}
SmallPriorityWorklist<Region *, 4> Worklist;
for (auto &S : SI)
if (S.second)
Worklist.insert(S.first);
ScopStandardAnalysisResults AR = {AM.getResult<DominatorTreeAnalysis>(F),
AM.getResult<ScopInfoAnalysis>(F),
AM.getResult<ScalarEvolutionAnalysis>(F),
AM.getResult<LoopAnalysis>(F),
AM.getResult<RegionInfoAnalysis>(F),
AM.getResult<TargetIRAnalysis>(F)};
ScopAnalysisManager &SAM =
AM.getResult<ScopAnalysisManagerFunctionProxy>(F).getManager();
SPMUpdater Updater{Worklist, SAM};
while (!Worklist.empty()) {
Region *R = Worklist.pop_back_val();
if (!SD.isMaxRegionInScop(*R, /*Verifying=*/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 <typename ScopPassT>
FunctionToScopPassAdaptor<ScopPassT>
createFunctionToScopPassAdaptor(ScopPassT Pass) {
return FunctionToScopPassAdaptor<ScopPassT>(std::move(Pass));
}
} // namespace polly
#endif