[polly] r309826 - [Polly][PM][WIP] Polly pass registration

Philip Pfaffe via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 2 08:52:25 PDT 2017


Author: pfaffe
Date: Wed Aug  2 08:52:25 2017
New Revision: 309826

URL: http://llvm.org/viewvc/llvm-project?rev=309826&view=rev
Log:
[Polly][PM][WIP] Polly pass registration

Summary:
This patch is a first attempt at registering Polly passes with the LLVM tools. Tool plugins are still unsupported, but this registration is usable from the tools if Polly is linked into them (albeit requiring minimal patches to those tools). Registration requires a small amount of machinery (the owning analysis proxies), necessary for injecting ScopAnalysisManager objects into the calling tools.

This patch is marked WIP because the registration is incomplete. Parsing manual pipelines is fully supported, but default pass injection into the O3 pipeline is lacking, mostly because there is opportunity for some redesign here, I believe. The first point of order would be insertion points. I think it makes sense to run before the vectorizers. Running Polly Early, however, is weird. Mostly because it actually is the default (which to me is unexpected), and because Polly runs it's own O1 pipeline. Why not instead insert it at an appropriate place somewhere after simplification happend? Running after the loop optimizers seems intuitive, but it also seems wasteful, since multiple consecutive loops might well be a single scop, and we don't need to run for all of them.

My second request for comments would be regarding all those smallish helper passes we have,  like PollyViewer, PollyPrinter, PollyImportJScop. Right now these are controlled by command line options, deciding whether they should be part of the Polly pipeline. What is your opinion on treating them like real passes, and have the user write an appropriate pipeline if they want to use any of them?

Reviewers: grosser, Meinersbur, bollu

Reviewed By: grosser

Subscribers: llvm-commits, pollydev

Tags: #polly

Differential Revision: https://reviews.llvm.org/D35458

Added:
    polly/trunk/include/polly/CodePreparation.h
    polly/trunk/lib/Support/PollyPasses.def
Modified:
    polly/trunk/include/polly/ScopPass.h
    polly/trunk/include/polly/Support/ScopHelper.h
    polly/trunk/lib/Analysis/ScopPass.cpp
    polly/trunk/lib/Support/RegisterPasses.cpp
    polly/trunk/lib/Support/ScopHelper.cpp
    polly/trunk/lib/Transform/CodePreparation.cpp

Added: polly/trunk/include/polly/CodePreparation.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/CodePreparation.h?rev=309826&view=auto
==============================================================================
--- polly/trunk/include/polly/CodePreparation.h (added)
+++ polly/trunk/include/polly/CodePreparation.h Wed Aug  2 08:52:25 2017
@@ -0,0 +1,13 @@
+#ifndef POLLY_CODEPREPARATION_H
+#define POLLY_CODEPREPARATION_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace polly {
+struct CodePreparationPass : public llvm::PassInfoMixin<CodePreparationPass> {
+  llvm::PreservedAnalyses run(llvm::Function &F,
+                              llvm::FunctionAnalysisManager &FAM);
+};
+}
+
+#endif /* POLLY_CODEPREPARATION_H */

Modified: polly/trunk/include/polly/ScopPass.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopPass.h?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopPass.h (original)
+++ polly/trunk/include/polly/ScopPass.h Wed Aug  2 08:52:25 2017
@@ -77,6 +77,21 @@ private:
   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(
@@ -95,6 +110,40 @@ extern template class OuterAnalysisManag
 } // 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:
+  friend AnalysisInfoMixin<
+      OwningInnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>>;
+
+  static AnalysisKey Key;
+
+  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 &>;

Modified: polly/trunk/include/polly/Support/ScopHelper.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ScopHelper.h?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ScopHelper.h (original)
+++ polly/trunk/include/polly/Support/ScopHelper.h Wed Aug  2 08:52:25 2017
@@ -315,6 +315,16 @@ void simplifyRegion(llvm::Region *R, llv
 ///
 void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock, llvm::Pass *P);
 
+/// Split the entry block of a function to store the newly inserted
+///        allocations outside of all Scops.
+///
+/// @param DT DominatorTree to be updated.
+/// @param LI LoopInfo to be updated.
+/// @param RI RegionInfo to be updated.
+void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock,
+                              llvm::DominatorTree *DT, llvm::LoopInfo *LI,
+                              llvm::RegionInfo *RI);
+
 /// Wrapper for SCEVExpander extended to all Polly features.
 ///
 /// This wrapper will internally call the SCEVExpander but also makes sure that

Modified: polly/trunk/lib/Analysis/ScopPass.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopPass.cpp?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopPass.cpp (original)
+++ polly/trunk/lib/Analysis/ScopPass.cpp Wed Aug  2 08:52:25 2017
@@ -41,6 +41,8 @@ void ScopPass::getAnalysisUsage(Analysis
   AU.setPreservesAll();
 }
 
+template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+
 namespace llvm {
 
 template class PassManager<Scop, ScopAnalysisManager,
@@ -130,6 +132,12 @@ bool ScopAnalysisManagerFunctionProxy::R
 }
 
 template <>
+OwningScopAnalysisManagerFunctionProxy::Result
+OwningScopAnalysisManagerFunctionProxy::run(Function &F,
+                                            FunctionAnalysisManager &FAM) {
+  return Result(InnerAM, FAM.getResult<ScopInfoAnalysis>(F));
+}
+template <>
 ScopAnalysisManagerFunctionProxy::Result
 ScopAnalysisManagerFunctionProxy::run(Function &F,
                                       FunctionAnalysisManager &FAM) {

Added: polly/trunk/lib/Support/PollyPasses.def
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/PollyPasses.def?rev=309826&view=auto
==============================================================================
--- polly/trunk/lib/Support/PollyPasses.def (added)
+++ polly/trunk/lib/Support/PollyPasses.def Wed Aug  2 08:52:25 2017
@@ -0,0 +1,29 @@
+#ifndef FUNCTION_ANALYSIS
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
+#endif
+FUNCTION_ANALYSIS("polly-detect", ScopAnalysis())
+FUNCTION_ANALYSIS("polly-function-scops", ScopInfoAnalysis())
+#undef FUNCTION_ANALYSIS
+
+#ifndef FUNCTION_PASS
+#define FUNCTION_PASS(NAME, CREATE_PASS)
+#endif
+FUNCTION_PASS("polly-prepare", CodePreparationPass())
+FUNCTION_PASS("print<polly-detect>", ScopAnalysisPrinterPass(errs()))
+FUNCTION_PASS("print<polly-function-scops>", ScopInfoPrinterPass(errs()))
+#undef FUNCTION_PASS
+
+#ifndef SCOP_ANALYSIS
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)
+#endif
+SCOP_ANALYSIS("polly-ast", IslAstAnalysis())
+SCOP_ANALYSIS("polly-dependences", DependenceAnalysis())
+#undef SCOP_ANALYSIS
+
+#ifndef SCOP_PASS
+#define SCOP_PASS(NAME, CREATE_PASS)
+#endif
+SCOP_PASS("print<polly-ast>", IslAstPrinterPass(outs()))
+SCOP_PASS("print<polly-dependences>", DependenceInfoPrinterPass(outs()))
+SCOP_PASS("polly-codegen", CodeGenerationPass())
+#undef SCOP_PASS

Modified: polly/trunk/lib/Support/RegisterPasses.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/RegisterPasses.cpp?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/lib/Support/RegisterPasses.cpp (original)
+++ polly/trunk/lib/Support/RegisterPasses.cpp Wed Aug  2 08:52:25 2017
@@ -23,7 +23,9 @@
 #include "polly/Canonicalization.h"
 #include "polly/CodeGen/CodeGeneration.h"
 #include "polly/CodeGen/CodegenCleanup.h"
+#include "polly/CodeGen/IslAst.h"
 #include "polly/CodeGen/PPCGCodeGeneration.h"
+#include "polly/CodePreparation.h"
 #include "polly/DeLICM.h"
 #include "polly/DependenceInfo.h"
 #include "polly/FlattenSchedule.h"
@@ -37,6 +39,8 @@
 #include "polly/Support/DumpModulePass.h"
 #include "llvm/Analysis/CFGPrinter.h"
 #include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -430,6 +434,69 @@ registerPollyScalarOptimizerLatePasses(c
   PM.add(createCodegenCleanupPass());
 }
 
+static void buildDefaultPollyPipeline(FunctionPassManager &PM,
+                                      PassBuilder::OptimizationLevel Level) {
+  if (!polly::shouldEnablePolly())
+    return;
+  PassBuilder PB;
+  ScopPassManager SPM;
+
+  // TODO add utility passes for the various command line options, once they're
+  // ported
+  assert(!DumpBefore && "This option is not implemented");
+  assert(DumpBeforeFile.empty() && "This option is not implemented");
+
+  if (PollyDetectOnly)
+    return;
+
+  assert(!PollyViewer && "This option is not implemented");
+  assert(!PollyOnlyViewer && "This option is not implemented");
+  assert(!PollyPrinter && "This option is not implemented");
+  assert(!PollyOnlyPrinter && "This option is not implemented");
+  assert(!EnablePolyhedralInfo && "This option is not implemented");
+  assert(!EnableDeLICM && "This option is not implemented");
+  assert(!EnableSimplify && "This option is not implemented");
+  assert(!ImportJScop && "This option is not implemented");
+  assert(!DeadCodeElim && "This option is not implemented");
+  assert(!EnablePruneUnprofitable && "This option is not implemented");
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID)
+    switch (Optimizer) {
+    case OPTIMIZER_NONE:
+      break; /* Do nothing */
+    case OPTIMIZER_ISL:
+      assert("ISL optimizer is not implemented");
+      break;
+    }
+
+  assert(!ExportJScop && "This option is not implemented");
+
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID) {
+    switch (CodeGeneration) {
+    case CODEGEN_FULL:
+      SPM.addPass(polly::CodeGenerationPass());
+      break;
+    case CODEGEN_AST:
+    default: // Does it actually make sense to distinguish IslAst codegen?
+      break;
+    }
+  }
+#ifdef GPU_CODEGEN
+  else
+    assert("Hybrid Target with GPU support is not implemented");
+#endif
+
+  PM.addPass(CodePreparationPass());
+  PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  PM.addPass(PB.buildFunctionSimplificationPipeline(
+      Level, PassBuilder::ThinLTOPhase::None)); // Cleanup
+
+  assert(!DumpAfter && "This option is not implemented");
+  assert(DumpAfterFile.empty() && "This option is not implemented");
+
+  if (CFGPrinter)
+    PM.addPass(llvm::CFGPrinterPass());
+}
+
 /// Register Polly to be available as an optimizer
 ///
 ///
@@ -478,4 +545,140 @@ static llvm::RegisterStandardPasses
 static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate(
     llvm::PassManagerBuilder::EP_VectorizerStart,
     registerPollyScalarOptimizerLatePasses);
+
+static OwningScopAnalysisManagerFunctionProxy
+createScopAnalyses(FunctionAnalysisManager &FAM) {
+  OwningScopAnalysisManagerFunctionProxy Proxy;
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  Proxy.getManager().registerPass([] { return CREATE_PASS; });
+
+#include "PollyPasses.def"
+
+  Proxy.getManager().registerPass(
+      [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); });
+  return Proxy;
+}
+
+static void registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
+  FAM.registerPass([] { return CREATE_PASS; });
+
+#include "PollyPasses.def"
+
+  FAM.registerPass([&FAM] { return createScopAnalyses(FAM); });
+}
+
+static bool
+parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM,
+                      ArrayRef<PassBuilder::PipelineElement> Pipeline) {
+  if (parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>(
+          "polly-scop-analyses", Name, FPM))
+    return true;
+
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
+  if (parseAnalysisUtilityPasses<                                              \
+          std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
+                                                              FPM))            \
+    return true;
+
+#define FUNCTION_PASS(NAME, CREATE_PASS)                                       \
+  if (Name == NAME) {                                                          \
+    FPM.addPass(CREATE_PASS);                                                  \
+    return true;                                                               \
+  }
+
+#include "PollyPasses.def"
+  return false;
+}
+
+static bool parseScopPass(StringRef Name, ScopPassManager &SPM) {
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  if (parseAnalysisUtilityPasses<                                              \
+          std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
+                                                              SPM))            \
+    return true;
+
+#define SCOP_PASS(NAME, CREATE_PASS)                                           \
+  if (Name == NAME) {                                                          \
+    SPM.addPass(CREATE_PASS);                                                  \
+    return true;                                                               \
+  }
+
+#include "PollyPasses.def"
+
+  return false;
+}
+
+static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM,
+                              ArrayRef<PassBuilder::PipelineElement> Pipeline) {
+  if (Name != "scop")
+    return false;
+  if (!Pipeline.empty()) {
+    ScopPassManager SPM;
+    for (const auto &E : Pipeline)
+      if (!parseScopPass(E.Name, SPM))
+        return false;
+    FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  }
+  return true;
+}
+
+static bool isScopPassName(StringRef Name) {
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  if (Name == "require<" NAME ">")                                             \
+    return true;                                                               \
+  if (Name == "invalidate<" NAME ">")                                          \
+    return true;
+
+#define SCOP_PASS(NAME, CREATE_PASS)                                           \
+  if (Name == NAME)                                                            \
+    return true;
+
+#include "PollyPasses.def"
+
+  return false;
+}
+
+static bool
+parseTopLevelPipeline(ModulePassManager &MPM,
+                      ArrayRef<PassBuilder::PipelineElement> Pipeline,
+                      bool VerifyEachPass, bool DebugLogging) {
+  std::vector<PassBuilder::PipelineElement> FullPipeline;
+  StringRef FirstName = Pipeline.front().Name;
+
+  if (!isScopPassName(FirstName))
+    return false;
+
+  FunctionPassManager FPM(DebugLogging);
+  ScopPassManager SPM(DebugLogging);
+
+  for (auto &Element : Pipeline) {
+    auto &Name = Element.Name;
+    auto &InnerPipeline = Element.InnerPipeline;
+    if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines
+      return false;
+    if (!parseScopPass(Name, SPM))
+      return false;
+  }
+
+  FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  if (VerifyEachPass)
+    FPM.addPass(VerifierPass());
+  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+  if (VerifyEachPass)
+    MPM.addPass(VerifierPass());
+
+  return true;
+}
+
+void RegisterPollyPasses(PassBuilder &PB) {
+  PB.registerAnalysisRegistrationCallback(registerFunctionAnalyses);
+  PB.registerPipelineParsingCallback(parseFunctionPipeline);
+  PB.registerPipelineParsingCallback(parseScopPipeline);
+  PB.registerParseTopLevelPipelineCallback(parseTopLevelPipeline);
+
+  if (PassPosition == POSITION_BEFORE_VECTORIZER)
+    PB.registerVectorizerStartEPCallback(buildDefaultPollyPipeline);
+  // FIXME else Error?
+}
 } // namespace polly

Modified: polly/trunk/lib/Support/ScopHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/ScopHelper.cpp?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/lib/Support/ScopHelper.cpp (original)
+++ polly/trunk/lib/Support/ScopHelper.cpp Wed Aug  2 08:52:25 2017
@@ -194,13 +194,19 @@ static BasicBlock *splitBlock(BasicBlock
   return NewBlock;
 }
 
-void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
+void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, DominatorTree *DT,
+                                     LoopInfo *LI, RegionInfo *RI) {
   // Find first non-alloca instruction. Every basic block has a non-alloca
   // instruction, as every well formed basic block has a terminator.
   BasicBlock::iterator I = EntryBlock->begin();
   while (isa<AllocaInst>(I))
     ++I;
 
+  // splitBlock updates DT, LI and RI.
+  splitBlock(EntryBlock, &*I, DT, LI, RI);
+}
+
+void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
   auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
   auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
   auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
@@ -209,7 +215,7 @@ void polly::splitEntryBlockForAlloca(Bas
   RegionInfo *RI = RIP ? &RIP->getRegionInfo() : nullptr;
 
   // splitBlock updates DT, LI and RI.
-  splitBlock(EntryBlock, &*I, DT, LI, RI);
+  polly::splitEntryBlockForAlloca(EntryBlock, DT, LI, RI);
 }
 
 /// The SCEVExpander will __not__ generate any code for an existing SDiv/SRem

Modified: polly/trunk/lib/Transform/CodePreparation.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/CodePreparation.cpp?rev=309826&r1=309825&r2=309826&view=diff
==============================================================================
--- polly/trunk/lib/Transform/CodePreparation.cpp (original)
+++ polly/trunk/lib/Transform/CodePreparation.cpp Wed Aug  2 08:52:25 2017
@@ -16,6 +16,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "polly/CodePreparation.h"
 #include "polly/LinkAllPasses.h"
 #include "polly/ScopDetection.h"
 #include "polly/Support/ScopHelper.h"
@@ -57,6 +58,28 @@ public:
 };
 } // namespace
 
+PreservedAnalyses CodePreparationPass::run(Function &F,
+                                           FunctionAnalysisManager &FAM) {
+
+  // Find first non-alloca instruction. Every basic block has a non-alloca
+  // instruction, as every well formed basic block has a terminator.
+  auto &EntryBlock = F.getEntryBlock();
+  BasicBlock::iterator I = EntryBlock.begin();
+  while (isa<AllocaInst>(I))
+    ++I;
+
+  auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
+  auto &LI = FAM.getResult<LoopAnalysis>(F);
+
+  // splitBlock updates DT, LI and RI.
+  splitEntryBlockForAlloca(&EntryBlock, &DT, &LI, nullptr);
+
+  PreservedAnalyses PA;
+  PA.preserve<DominatorTreeAnalysis>();
+  PA.preserve<LoopAnalysis>();
+  return PA;
+}
+
 void CodePreparation::clear() {}
 
 CodePreparation::~CodePreparation() { clear(); }




More information about the llvm-commits mailing list