//===- ScopPass.cpp - The base class of Passes that operate on Polly IR ---===//
//
// 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 contains the definitions of the ScopPass members.
//
//===----------------------------------------------------------------------===//

#include "polly/ScopPass.h"
#include "polly/ScopInfo.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/TargetTransformInfo.h"

using namespace llvm;
using namespace polly;

bool ScopPass::runOnRegion(Region *R, RGPassManager &RGM) {
  S = nullptr;

  if (skipRegion(*R))
    return false;

  if ((S = getAnalysis<ScopInfoRegionPass>().getScop()))
    return runOnScop(*S);

  return false;
}

void ScopPass::print(raw_ostream &OS, const Module *M) const {
  if (S)
    printScop(OS, *S);
}

void ScopPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<ScopInfoRegionPass>();

  AU.addPreserved<AAResultsWrapperPass>();
  AU.addPreserved<BasicAAWrapperPass>();
  AU.addPreserved<LoopInfoWrapperPass>();
  AU.addPreserved<DominatorTreeWrapperPass>();
  AU.addPreserved<GlobalsAAWrapperPass>();
  AU.addPreserved<ScopDetectionWrapperPass>();
  AU.addPreserved<ScalarEvolutionWrapperPass>();
  AU.addPreserved<SCEVAAWrapperPass>();
  AU.addPreserved<OptimizationRemarkEmitterWrapperPass>();
  AU.addPreserved<RegionInfoPass>();
  AU.addPreserved<ScopInfoRegionPass>();
  AU.addPreserved<TargetTransformInfoWrapperPass>();
}

namespace polly {
template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
}

namespace llvm {

template class PassManager<Scop, ScopAnalysisManager,
                           ScopStandardAnalysisResults &, SPMUpdater &>;
template class InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
                                         ScopStandardAnalysisResults &>;

template <>
PreservedAnalyses
PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
            SPMUpdater &>::run(Scop &S, ScopAnalysisManager &AM,
                               ScopStandardAnalysisResults &AR, SPMUpdater &U) {
  auto PA = PreservedAnalyses::all();
  for (auto &Pass : Passes) {
    auto PassPA = Pass->run(S, AM, AR, U);

    AM.invalidate(S, PassPA);
    PA.intersect(std::move(PassPA));
  }

  // All analyses for 'this' Scop have been invalidated above.
  // If ScopPasses affect break other scops they have to propagate this
  // information through the updater
  PA.preserveSet<AllAnalysesOn<Scop>>();
  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<ScopAnalysisManagerFunctionProxy>();
  if (!(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
      Inv.invalidate<ScopInfoAnalysis>(F, PA) ||
      Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
      Inv.invalidate<LoopAnalysis>(F, PA) ||
      Inv.invalidate<DominatorTreeAnalysis>(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, scop->getName());

    InnerAM = nullptr;
    return true; // Invalidate the proxy result as well.
  }

  bool allPreserved = PA.allAnalysesInSetPreserved<AllAnalysesOn<Scop>>();

  // Invalidate all non-preserved analyses
  // Even if all analyses were preserved, we still need to run deferred
  // invalidation
  for (auto &S : *SI) {
    Optional<PreservedAnalyses> InnerPA;
    auto *scop = S.second.get();
    if (!scop)
      continue;

    if (auto *OuterProxy =
            InnerAM->getCachedResult<FunctionAnalysisManagerScopProxy>(*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 (!allPreserved)
      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<ScopInfoAnalysis>(F));
}
} // namespace llvm

namespace polly {
template <>
OwningScopAnalysisManagerFunctionProxy::Result
OwningScopAnalysisManagerFunctionProxy::run(Function &F,
                                            FunctionAnalysisManager &FAM) {
  return Result(InnerAM, FAM.getResult<ScopInfoAnalysis>(F));
}
} // namespace polly
