Index: include/polly/CodePreparation.h =================================================================== --- /dev/null +++ include/polly/CodePreparation.h @@ -0,0 +1,13 @@ +#ifndef POLLY_CODEPREPARATION_H +#define POLLY_CODEPREPARATION_H + +#include "llvm/IR/PassManager.h" + +namespace polly { +struct CodePreparationPass : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Function &F, + llvm::FunctionAnalysisManager &FAM); +}; +} + +#endif /* POLLY_CODEPREPARATION_H */ Index: include/polly/ScopPass.h =================================================================== --- include/polly/ScopPass.h +++ include/polly/ScopPass.h @@ -77,6 +77,21 @@ 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( @@ -95,6 +110,40 @@ } // namespace llvm namespace polly { + +template +class OwningInnerAnalysisManagerProxy + : 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: + friend AnalysisInfoMixin< + OwningInnerAnalysisManagerProxy>; + + static AnalysisKey Key; + + AnalysisManagerT InnerAM; +}; + +template <> +OwningInnerAnalysisManagerProxy::Result +OwningInnerAnalysisManagerProxy::run( + Function &F, FunctionAnalysisManager &FAM); +extern template class OwningInnerAnalysisManagerProxy; + +using OwningScopAnalysisManagerFunctionProxy = + OwningInnerAnalysisManagerProxy; using ScopPassManager = PassManager; Index: include/polly/Support/ScopHelper.h =================================================================== --- include/polly/Support/ScopHelper.h +++ include/polly/Support/ScopHelper.h @@ -315,6 +315,16 @@ /// 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 Index: lib/Analysis/ScopPass.cpp =================================================================== --- lib/Analysis/ScopPass.cpp +++ lib/Analysis/ScopPass.cpp @@ -41,6 +41,8 @@ AU.setPreservesAll(); } +template class OwningInnerAnalysisManagerProxy; + namespace llvm { template class PassManager +OwningScopAnalysisManagerFunctionProxy::Result +OwningScopAnalysisManagerFunctionProxy::run(Function &F, + FunctionAnalysisManager &FAM) { + return Result(InnerAM, FAM.getResult(F)); +} +template <> ScopAnalysisManagerFunctionProxy::Result ScopAnalysisManagerFunctionProxy::run(Function &F, FunctionAnalysisManager &FAM) { Index: lib/Support/PollyPasses.def =================================================================== --- /dev/null +++ lib/Support/PollyPasses.def @@ -0,0 +1,28 @@ +#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("print", ScopAnalysisPrinterPass(errs())) +FUNCTION_PASS("print", 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", IslAstPrinterPass(outs())) +SCOP_PASS("print", DependenceInfoPrinterPass(outs())) +SCOP_PASS("polly-codegen", CodeGenerationPass()) +#undef SCOP_PASS Index: lib/Support/RegisterPasses.cpp =================================================================== --- lib/Support/RegisterPasses.cpp +++ lib/Support/RegisterPasses.cpp @@ -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" @@ -36,6 +38,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" @@ -417,6 +421,36 @@ 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 + + if (PollyDetectOnly) + return; + + if (Target == TARGET_CPU || Target == TARGET_HYBRID) + switch (CodeGeneration) { + case CODEGEN_FULL: + SPM.addPass(polly::CodeGenerationPass()); + break; + default: // Does it actually make sense to distinguish IslAst codegen? + break; + } + + PM.addPass(CodePreparationPass()); + PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); + PM.addPass(PB.buildFunctionSimplificationPipeline(Level)); // Cleanup + + if (CFGPrinter) + PM.addPass(llvm::CFGPrinterPass()); +} + /// Register Polly to be available as an optimizer /// /// @@ -465,4 +499,138 @@ static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate( llvm::PassManagerBuilder::EP_VectorizerStart, registerPollyScalarOptimizerLatePasses); + +static OwningScopAnalysisManagerFunctionProxy createScopAnalyses() { + OwningScopAnalysisManagerFunctionProxy Proxy; +#define SCOP_ANALYSIS(NAME, CREATE_PASS) \ + Proxy.getManager().registerPass([] { return CREATE_PASS; }); + +#include "PollyPasses.def" + + return Proxy; +} + +static void registerFunctionAnalyses(FunctionAnalysisManager &FAM) { +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ + FAM.registerPass([] { return CREATE_PASS; }); + +#include "PollyPasses.def" + + FAM.registerPass(createScopAnalyses); +} + +static bool +parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM, + ArrayRef Pipeline) { + if (parseAnalysisUtilityPasses( + "polly-scop-analyses", Name, FPM)) + return true; + +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ + if (parseAnalysisUtilityPasses< \ + std::remove_reference::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::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 Pipeline) { + if (!Pipeline.empty()) { + if (Name == "scop") { + ScopPassManager SPM; + for (const auto &E : Pipeline) + if (!parseScopPass(E.Name, SPM)) + return false; + FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); + return true; + } + } + return false; +} + +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 Pipeline, + bool VerifyEachPass, bool DebugLogging) { + std::vector 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 Index: lib/Support/ScopHelper.cpp =================================================================== --- lib/Support/ScopHelper.cpp +++ lib/Support/ScopHelper.cpp @@ -194,13 +194,19 @@ 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(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(); auto *DT = DTWP ? &DTWP->getDomTree() : nullptr; auto *LIWP = P->getAnalysisIfAvailable(); @@ -209,7 +215,7 @@ 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 Index: lib/Transform/CodePreparation.cpp =================================================================== --- lib/Transform/CodePreparation.cpp +++ lib/Transform/CodePreparation.cpp @@ -16,6 +16,7 @@ // //===----------------------------------------------------------------------===// +#include "polly/CodePreparation.h" #include "polly/LinkAllPasses.h" #include "polly/ScopDetection.h" #include "polly/Support/ScopHelper.h" @@ -57,6 +58,30 @@ }; } // 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(I)) + ++I; + + auto &DT = FAM.getResult(F); + auto &LI = FAM.getResult(F); + auto &RI = FAM.getResult(F); + + // splitBlock updates DT, LI and RI. + splitEntryBlockForAlloca(&EntryBlock, &DT, &LI, &RI); + + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + PA.preserve(); + return PA; +} + void CodePreparation::clear() {} CodePreparation::~CodePreparation() { clear(); }