https://github.com/Meinersbur updated https://github.com/llvm/llvm-project/pull/125427
>From 06b025db36dff8c1a3b0b22ae884d6506611f455 Mon Sep 17 00:00:00 2001 From: Michael Kruse <llvm-proj...@meinersbur.de> Date: Sun, 2 Feb 2025 18:48:32 +0100 Subject: [PATCH 1/2] Update ScopInliner to support NPM --- polly/docs/ReleaseNotes.rst | 2 + polly/include/polly/LinkAllPasses.h | 2 +- polly/include/polly/ScopInliner.h | 34 ++++ polly/lib/Support/PollyPasses.def | 6 + polly/lib/Support/RegisterPasses.cpp | 41 ++++- polly/lib/Transform/ScopInliner.cpp | 159 +++++++++++------- polly/test/ScopInliner/ignore-declares.ll | 3 +- polly/test/ScopInliner/invariant-load-func.ll | 5 +- polly/test/ScopInliner/simple-inline-loop.ll | 3 +- 9 files changed, 184 insertions(+), 71 deletions(-) create mode 100644 polly/include/polly/ScopInliner.h diff --git a/polly/docs/ReleaseNotes.rst b/polly/docs/ReleaseNotes.rst index f7c9689089be2..f5ea47b69cf02 100644 --- a/polly/docs/ReleaseNotes.rst +++ b/polly/docs/ReleaseNotes.rst @@ -11,3 +11,5 @@ In Polly |version| the following important changes have been incorporated. the new features that have recently been committed to our development branch. + * ScopInliner has been updated for the New Pass Manager. + diff --git a/polly/include/polly/LinkAllPasses.h b/polly/include/polly/LinkAllPasses.h index 54e7c5a43ab93..65846653f98e5 100644 --- a/polly/include/polly/LinkAllPasses.h +++ b/polly/include/polly/LinkAllPasses.h @@ -120,7 +120,7 @@ struct PollyForcePassLinking { namespace llvm { void initializeCodePreparationPass(llvm::PassRegistry &); -void initializeScopInlinerPass(llvm::PassRegistry &); +void initializeScopInlinerWrapperPassPass(llvm::PassRegistry &); void initializeScopDetectionWrapperPassPass(llvm::PassRegistry &); void initializeScopDetectionPrinterLegacyPassPass(llvm::PassRegistry &); void initializeScopInfoRegionPassPass(PassRegistry &); diff --git a/polly/include/polly/ScopInliner.h b/polly/include/polly/ScopInliner.h new file mode 100644 index 0000000000000..014667804330f --- /dev/null +++ b/polly/include/polly/ScopInliner.h @@ -0,0 +1,34 @@ +//===------ ScopInliner.h ------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef POLLY_POLLYINLINER_H +#define POLLY_POLLYINLINER_H + +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/IR/PassManager.h" + +namespace polly { +class ScopInlinerPass : public llvm::PassInfoMixin<ScopInlinerPass> { +public: + ScopInlinerPass(); + + llvm::PreservedAnalyses run(llvm::LazyCallGraph::SCC &C, + llvm::CGSCCAnalysisManager &AM, + llvm::LazyCallGraph &CG, + llvm::CGSCCUpdateResult &UR); +}; + +llvm::Pass *createScopInlinerWrapperPass(); +} // namespace polly + +namespace llvm { +void initializeScopInlinerWrapperPassPass(llvm::PassRegistry &); +} + +#endif /* POLLY_POLLYINLINER_H */ diff --git a/polly/lib/Support/PollyPasses.def b/polly/lib/Support/PollyPasses.def index e068f31fdb703..2c792a5867100 100644 --- a/polly/lib/Support/PollyPasses.def +++ b/polly/lib/Support/PollyPasses.def @@ -1,3 +1,9 @@ +#ifndef CGSCC_PASS +#define CGSCC_PASS(NAME, CREATE_PASS, PARSER) +#endif +CGSCC_PASS("polly-inline", ScopInlinerPass(), parseNoOptions) +#undef CGSCC_PASS + #ifndef FUNCTION_ANALYSIS #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) #endif diff --git a/polly/lib/Support/RegisterPasses.cpp b/polly/lib/Support/RegisterPasses.cpp index a46e61aafbeb7..3ace336cb588b 100644 --- a/polly/lib/Support/RegisterPasses.cpp +++ b/polly/lib/Support/RegisterPasses.cpp @@ -35,6 +35,7 @@ #include "polly/ScopDetection.h" #include "polly/ScopGraphPrinter.h" #include "polly/ScopInfo.h" +#include "polly/ScopInliner.h" #include "polly/Simplify.h" #include "polly/Support/DumpFunctionPass.h" #include "polly/Support/DumpModulePass.h" @@ -46,10 +47,13 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Transforms/IPO.h" +using namespace llvm; namespace cl = llvm::cl; +using namespace polly; using llvm::FunctionPassManager; using llvm::OptimizationLevel; @@ -233,7 +237,7 @@ void initializePollyPasses(llvm::PassRegistry &Registry) { initializePollyCanonicalizePass(Registry); initializeScopDetectionWrapperPassPass(Registry); initializeScopDetectionPrinterLegacyPassPass(Registry); - initializeScopInlinerPass(Registry); + initializeScopInlinerWrapperPassPass(Registry); initializeScopInfoRegionPassPass(Registry); initializeScopInfoPrinterLegacyRegionPassPass(Registry); initializeScopInfoWrapperPassPass(Registry); @@ -434,6 +438,16 @@ static void buildLatePollyPipeline(FunctionPassManager &PM, false); } +static llvm::Expected<std::monostate> parseNoOptions(StringRef Params) { + if (!Params.empty()) + return make_error<StringError>( + formatv("'{0}' passed to pass that does not take any options", Params) + .str(), + inconvertibleErrorCode()); + + return std::monostate{}; +} + static OwningScopAnalysisManagerFunctionProxy createScopAnalyses(FunctionAnalysisManager &FAM, PassInstrumentationCallbacks *PIC) { @@ -461,6 +475,25 @@ static void registerFunctionAnalyses(FunctionAnalysisManager &FAM, FAM.registerPass([&FAM, PIC] { return createScopAnalyses(FAM, PIC); }); } +static llvm::Expected<bool> +parseCGPipeline(StringRef Name, llvm::CGSCCPassManager &CGPM, + PassInstrumentationCallbacks *PIC, + ArrayRef<PassBuilder::PipelineElement> Pipeline) { + assert(Pipeline.empty()); + +#define CGSCC_PASS(NAME, CREATE_PASS, PARSER) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto Params = PassBuilder::parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + CGPM.addPass(CREATE_PASS); \ + return true; \ + } +#include "PollyPasses.def" + + return false; +} + static bool parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM, ArrayRef<PassBuilder::PipelineElement> Pipeline) { @@ -590,6 +623,12 @@ parseTopLevelPipeline(llvm::ModulePassManager &MPM, /// handle LICMed code to make it useful. void registerPollyPasses(PassBuilder &PB) { PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks(); + PB.registerPipelineParsingCallback( + [PIC](StringRef Name, CGSCCPassManager &CGPM, + ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { + ExitOnError Err("Unable to parse Polly call graph pass: "); + return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline)); + }); PB.registerAnalysisRegistrationCallback([PIC](FunctionAnalysisManager &FAM) { registerFunctionAnalyses(FAM, PIC); }); diff --git a/polly/lib/Transform/ScopInliner.cpp b/polly/lib/Transform/ScopInliner.cpp index b78206c1e40ba..c04ba3498339e 100644 --- a/polly/lib/Transform/ScopInliner.cpp +++ b/polly/lib/Transform/ScopInliner.cpp @@ -13,10 +13,14 @@ // //===----------------------------------------------------------------------===// -#include "polly/LinkAllPasses.h" +#include "polly/ScopInliner.h" #include "polly/ScopDetection.h" +#include "polly/ScopInliner.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/RegionInfo.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" @@ -28,13 +32,77 @@ using namespace llvm; using namespace polly; namespace { -class ScopInliner final : public CallGraphSCCPass { + +/// Inliner implementation that works with both, LPM (using SCC_t=CallGraph) and +/// NPM (using SCC_t=LazyCallGraph::SCC) +template <typename SCC_t> bool runScopInlinerImpl(Function *F, SCC_t &SCC) { + // We do not try to inline non-trivial SCCs because this would lead to + // "infinite" inlining if we are not careful. + if (SCC.size() > 1) + return false; + assert(SCC.size() == 1 && "found empty SCC"); + + // If the function is a nullptr, or the function is a declaration. + if (!F) + return false; + if (F->isDeclaration()) { + POLLY_DEBUG(dbgs() << "Skipping " << F->getName() + << "because it is a declaration.\n"); + return false; + } + + PassBuilder PB; + // Populate analysis managers and register Polly-specific analyses. + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + auto &DT = FAM.getResult<DominatorTreeAnalysis>(*F); + auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(*F); + auto &LI = FAM.getResult<LoopAnalysis>(*F); + auto &RI = FAM.getResult<RegionInfoAnalysis>(*F); + auto &AA = FAM.getResult<AAManager>(*F); + auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F); + ScopDetection SD(DT, SE, LI, RI, AA, ORE); + SD.detect(*F); + + const bool HasScopAsTopLevelRegion = + SD.ValidRegions.contains(RI.getTopLevelRegion()); + + bool Changed = false; + if (HasScopAsTopLevelRegion) { + POLLY_DEBUG(dbgs() << "Skipping " << F->getName() + << " has scop as top level region"); + F->addFnAttr(llvm::Attribute::AlwaysInline); + + ModulePassManager MPM; + MPM.addPass(AlwaysInlinerPass()); + Module *M = F->getParent(); + assert(M && "Function has illegal module"); + PreservedAnalyses PA = MPM.run(*M, MAM); + if (!PA.areAllPreserved()) + Changed = true; + } else { + POLLY_DEBUG(dbgs() << F->getName() + << " does NOT have scop as top level region\n"); + } + + return Changed; +} + +class ScopInlinerWrapperPass final : public CallGraphSCCPass { using llvm::Pass::doInitialization; public: static char ID; - ScopInliner() : CallGraphSCCPass(ID) {} + ScopInlinerWrapperPass() : CallGraphSCCPass(ID) {} bool doInitialization(CallGraph &CG) override { if (!polly::PollyAllowFullFunction) { @@ -50,60 +118,8 @@ class ScopInliner final : public CallGraphSCCPass { } bool runOnSCC(CallGraphSCC &SCC) override { - // We do not try to inline non-trivial SCCs because this would lead to - // "infinite" inlining if we are not careful. - if (SCC.size() > 1) - return false; - assert(SCC.size() == 1 && "found empty SCC"); Function *F = (*SCC.begin())->getFunction(); - - // If the function is a nullptr, or the function is a declaration. - if (!F) - return false; - if (F->isDeclaration()) { - POLLY_DEBUG(dbgs() << "Skipping " << F->getName() - << "because it is a declaration.\n"); - return false; - } - - PassBuilder PB; - // Populate analysis managers and register Polly-specific analyses. - LoopAnalysisManager LAM; - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; - FAM.registerPass([] { return ScopAnalysis(); }); - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F); - ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F); - - const bool HasScopAsTopLevelRegion = - SD.ValidRegions.contains(RI.getTopLevelRegion()); - - bool Changed = false; - if (HasScopAsTopLevelRegion) { - POLLY_DEBUG(dbgs() << "Skipping " << F->getName() - << " has scop as top level region"); - F->addFnAttr(llvm::Attribute::AlwaysInline); - - ModulePassManager MPM; - MPM.addPass(AlwaysInlinerPass()); - Module *M = F->getParent(); - assert(M && "Function has illegal module"); - PreservedAnalyses PA = MPM.run(*M, MAM); - if (!PA.areAllPreserved()) - Changed = true; - } else { - POLLY_DEBUG(dbgs() << F->getName() - << " does NOT have scop as top level region\n"); - } - - return Changed; + return runScopInlinerImpl(F, SCC); }; void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -111,18 +127,39 @@ class ScopInliner final : public CallGraphSCCPass { } }; } // namespace -char ScopInliner::ID; +char ScopInlinerWrapperPass::ID; -Pass *polly::createScopInlinerPass() { - ScopInliner *pass = new ScopInliner(); +Pass *polly::createScopInlinerWrapperPass() { + ScopInlinerWrapperPass *pass = new ScopInlinerWrapperPass(); return pass; } INITIALIZE_PASS_BEGIN( - ScopInliner, "polly-scop-inliner", + ScopInlinerWrapperPass, "polly-scop-inliner", "inline functions based on how much of the function is a scop.", false, false) INITIALIZE_PASS_END( - ScopInliner, "polly-scop-inliner", + ScopInlinerWrapperPass, "polly-scop-inliner", "inline functions based on how much of the function is a scop.", false, false) + +polly::ScopInlinerPass::ScopInlinerPass() { + if (!polly::PollyAllowFullFunction) { + report_fatal_error( + "Aborting from ScopInliner because it only makes sense to run with " + "-polly-allow-full-function. " + "The heurtistic for ScopInliner checks that the full function is a " + "Scop, which happens if and only if polly-allow-full-function is " + " enabled. " + " If not, the entry block is not included in the Scop"); + } +} + +PreservedAnalyses polly::ScopInlinerPass::run(llvm::LazyCallGraph::SCC &SCC, + llvm::CGSCCAnalysisManager &AM, + llvm::LazyCallGraph &CG, + llvm::CGSCCUpdateResult &UR) { + Function *F = &SCC.begin()->getFunction(); + bool Changed = runScopInlinerImpl(F, SCC); + return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); +} diff --git a/polly/test/ScopInliner/ignore-declares.ll b/polly/test/ScopInliner/ignore-declares.ll index 11722dcb32166..5c0cfa103f0bf 100644 --- a/polly/test/ScopInliner/ignore-declares.ll +++ b/polly/test/ScopInliner/ignore-declares.ll @@ -1,5 +1,4 @@ -; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \ -; RUN: -polly-scops -disable-output < %s +; RUN: opt %loadNPMPolly -polly-detect-full-functions '-passes=cgscc(polly-inline),function(print<polly-function-scops>)' -disable-output < %s ; Check that we do not crash if there are declares. We should skip function ; declarations and not try to query for domtree. diff --git a/polly/test/ScopInliner/invariant-load-func.ll b/polly/test/ScopInliner/invariant-load-func.ll index ffd2ec9cdb60f..58c556a455fb9 100644 --- a/polly/test/ScopInliner/invariant-load-func.ll +++ b/polly/test/ScopInliner/invariant-load-func.ll @@ -1,12 +1,9 @@ -; RUN: opt %loadNPMPolly -polly-detect-full-functions -polly-scop-inliner \ -; RUN: -polly-invariant-load-hoisting '-passes=print<polly-function-scops>' -disable-output < %s | FileCheck %s +; RUN: opt %loadNPMPolly -polly-detect-full-functions -polly-invariant-load-hoisting '-passes=cgscc(polly-inline),function(print<polly-function-scops>)' -disable-output < %s 2>&1 | FileCheck %s ; Check that we inline a function that requires invariant load hoisting ; correctly. ; CHECK: Max Loop Depth: 2 -; REQUIRES: pollyacc - ; void to_be_inlined(int A[], int *begin, int *end) { ; for(int i = *begin; i < *end; i++) { diff --git a/polly/test/ScopInliner/simple-inline-loop.ll b/polly/test/ScopInliner/simple-inline-loop.ll index a5e3483edad05..f12798a3d831a 100644 --- a/polly/test/ScopInliner/simple-inline-loop.ll +++ b/polly/test/ScopInliner/simple-inline-loop.ll @@ -1,5 +1,4 @@ -; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \ -; RUN: -polly-print-scops -disable-output < %s | FileCheck %s +; RUN: opt %loadNPMPolly -polly-detect-full-functions '-passes=cgscc(polly-inline),function(print<polly-function-scops>)' -disable-output < %s 2>&1 | FileCheck %s ; Check that we get the 2 nested loops by inlining `to_be_inlined` into ; `inline_site`. >From 8705fdc402b91a068e7a5025cbd38d4a6e14655b Mon Sep 17 00:00:00 2001 From: Michael Kruse <llvm-proj...@meinersbur.de> Date: Tue, 4 Feb 2025 22:02:51 +0100 Subject: [PATCH 2/2] Sort registerPipelineParsingCallback --- polly/lib/Support/RegisterPasses.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/polly/lib/Support/RegisterPasses.cpp b/polly/lib/Support/RegisterPasses.cpp index 3ace336cb588b..ad37760780c08 100644 --- a/polly/lib/Support/RegisterPasses.cpp +++ b/polly/lib/Support/RegisterPasses.cpp @@ -623,12 +623,6 @@ parseTopLevelPipeline(llvm::ModulePassManager &MPM, /// handle LICMed code to make it useful. void registerPollyPasses(PassBuilder &PB) { PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks(); - PB.registerPipelineParsingCallback( - [PIC](StringRef Name, CGSCCPassManager &CGPM, - ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { - ExitOnError Err("Unable to parse Polly call graph pass: "); - return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline)); - }); PB.registerAnalysisRegistrationCallback([PIC](FunctionAnalysisManager &FAM) { registerFunctionAnalyses(FAM, PIC); }); @@ -638,6 +632,12 @@ void registerPollyPasses(PassBuilder &PB) { ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { return parseScopPipeline(Name, FPM, PIC, Pipeline); }); + PB.registerPipelineParsingCallback( + [PIC](StringRef Name, CGSCCPassManager &CGPM, + ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { + ExitOnError Err("Unable to parse Polly call graph pass: "); + return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline)); + }); PB.registerParseTopLevelPipelineCallback( [PIC](llvm::ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits