//===--------- 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 final
 
    : 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(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<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 struct FunctionToScopPassAdaptor;
 
};
 
 
 
template <typename ScopPassT>
 
struct FunctionToScopPassAdaptor final
 
    : PassInfoMixin<FunctionToScopPassAdaptor<ScopPassT>> {
 
  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, /*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 <typename ScopPassT>
 
FunctionToScopPassAdaptor<ScopPassT>
 
createFunctionToScopPassAdaptor(ScopPassT Pass) {
 
  return FunctionToScopPassAdaptor<ScopPassT>(std::move(Pass));
 
}
 
} // namespace polly
 
 
 
#endif