Skip to content

Commit 06b025d

Browse files
committed
Update ScopInliner to support NPM
1 parent c882519 commit 06b025d

File tree

9 files changed

+184
-71
lines changed

9 files changed

+184
-71
lines changed

polly/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ In Polly |version| the following important changes have been incorporated.
1111
the new features that have recently been committed to our development
1212
branch.
1313

14+
* ScopInliner has been updated for the New Pass Manager.
15+

polly/include/polly/LinkAllPasses.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct PollyForcePassLinking {
120120

121121
namespace llvm {
122122
void initializeCodePreparationPass(llvm::PassRegistry &);
123-
void initializeScopInlinerPass(llvm::PassRegistry &);
123+
void initializeScopInlinerWrapperPassPass(llvm::PassRegistry &);
124124
void initializeScopDetectionWrapperPassPass(llvm::PassRegistry &);
125125
void initializeScopDetectionPrinterLegacyPassPass(llvm::PassRegistry &);
126126
void initializeScopInfoRegionPassPass(PassRegistry &);

polly/include/polly/ScopInliner.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===------ ScopInliner.h ------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef POLLY_POLLYINLINER_H
10+
#define POLLY_POLLYINLINER_H
11+
12+
#include "llvm/Analysis/CGSCCPassManager.h"
13+
#include "llvm/Analysis/LazyCallGraph.h"
14+
#include "llvm/IR/PassManager.h"
15+
16+
namespace polly {
17+
class ScopInlinerPass : public llvm::PassInfoMixin<ScopInlinerPass> {
18+
public:
19+
ScopInlinerPass();
20+
21+
llvm::PreservedAnalyses run(llvm::LazyCallGraph::SCC &C,
22+
llvm::CGSCCAnalysisManager &AM,
23+
llvm::LazyCallGraph &CG,
24+
llvm::CGSCCUpdateResult &UR);
25+
};
26+
27+
llvm::Pass *createScopInlinerWrapperPass();
28+
} // namespace polly
29+
30+
namespace llvm {
31+
void initializeScopInlinerWrapperPassPass(llvm::PassRegistry &);
32+
}
33+
34+
#endif /* POLLY_POLLYINLINER_H */

polly/lib/Support/PollyPasses.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#ifndef CGSCC_PASS
2+
#define CGSCC_PASS(NAME, CREATE_PASS, PARSER)
3+
#endif
4+
CGSCC_PASS("polly-inline", ScopInlinerPass(), parseNoOptions)
5+
#undef CGSCC_PASS
6+
17
#ifndef FUNCTION_ANALYSIS
28
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
39
#endif

polly/lib/Support/RegisterPasses.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "polly/ScopDetection.h"
3636
#include "polly/ScopGraphPrinter.h"
3737
#include "polly/ScopInfo.h"
38+
#include "polly/ScopInliner.h"
3839
#include "polly/Simplify.h"
3940
#include "polly/Support/DumpFunctionPass.h"
4041
#include "polly/Support/DumpModulePass.h"
@@ -46,10 +47,13 @@
4647
#include "llvm/Passes/PassBuilder.h"
4748
#include "llvm/Passes/PassPlugin.h"
4849
#include "llvm/Support/CommandLine.h"
50+
#include "llvm/Support/Error.h"
4951
#include "llvm/Support/TargetSelect.h"
5052
#include "llvm/Transforms/IPO.h"
5153

54+
using namespace llvm;
5255
namespace cl = llvm::cl;
56+
using namespace polly;
5357

5458
using llvm::FunctionPassManager;
5559
using llvm::OptimizationLevel;
@@ -233,7 +237,7 @@ void initializePollyPasses(llvm::PassRegistry &Registry) {
233237
initializePollyCanonicalizePass(Registry);
234238
initializeScopDetectionWrapperPassPass(Registry);
235239
initializeScopDetectionPrinterLegacyPassPass(Registry);
236-
initializeScopInlinerPass(Registry);
240+
initializeScopInlinerWrapperPassPass(Registry);
237241
initializeScopInfoRegionPassPass(Registry);
238242
initializeScopInfoPrinterLegacyRegionPassPass(Registry);
239243
initializeScopInfoWrapperPassPass(Registry);
@@ -434,6 +438,16 @@ static void buildLatePollyPipeline(FunctionPassManager &PM,
434438
false);
435439
}
436440

441+
static llvm::Expected<std::monostate> parseNoOptions(StringRef Params) {
442+
if (!Params.empty())
443+
return make_error<StringError>(
444+
formatv("'{0}' passed to pass that does not take any options", Params)
445+
.str(),
446+
inconvertibleErrorCode());
447+
448+
return std::monostate{};
449+
}
450+
437451
static OwningScopAnalysisManagerFunctionProxy
438452
createScopAnalyses(FunctionAnalysisManager &FAM,
439453
PassInstrumentationCallbacks *PIC) {
@@ -461,6 +475,25 @@ static void registerFunctionAnalyses(FunctionAnalysisManager &FAM,
461475
FAM.registerPass([&FAM, PIC] { return createScopAnalyses(FAM, PIC); });
462476
}
463477

478+
static llvm::Expected<bool>
479+
parseCGPipeline(StringRef Name, llvm::CGSCCPassManager &CGPM,
480+
PassInstrumentationCallbacks *PIC,
481+
ArrayRef<PassBuilder::PipelineElement> Pipeline) {
482+
assert(Pipeline.empty());
483+
484+
#define CGSCC_PASS(NAME, CREATE_PASS, PARSER) \
485+
if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \
486+
auto Params = PassBuilder::parsePassParameters(PARSER, Name, NAME); \
487+
if (!Params) \
488+
return Params.takeError(); \
489+
CGPM.addPass(CREATE_PASS); \
490+
return true; \
491+
}
492+
#include "PollyPasses.def"
493+
494+
return false;
495+
}
496+
464497
static bool
465498
parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM,
466499
ArrayRef<PassBuilder::PipelineElement> Pipeline) {
@@ -590,6 +623,12 @@ parseTopLevelPipeline(llvm::ModulePassManager &MPM,
590623
/// handle LICMed code to make it useful.
591624
void registerPollyPasses(PassBuilder &PB) {
592625
PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks();
626+
PB.registerPipelineParsingCallback(
627+
[PIC](StringRef Name, CGSCCPassManager &CGPM,
628+
ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool {
629+
ExitOnError Err("Unable to parse Polly call graph pass: ");
630+
return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline));
631+
});
593632
PB.registerAnalysisRegistrationCallback([PIC](FunctionAnalysisManager &FAM) {
594633
registerFunctionAnalyses(FAM, PIC);
595634
});

polly/lib/Transform/ScopInliner.cpp

Lines changed: 98 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16-
#include "polly/LinkAllPasses.h"
16+
#include "polly/ScopInliner.h"
1717
#include "polly/ScopDetection.h"
18+
#include "polly/ScopInliner.h"
1819
#include "llvm/Analysis/CallGraph.h"
1920
#include "llvm/Analysis/CallGraphSCCPass.h"
21+
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
22+
#include "llvm/Analysis/RegionInfo.h"
23+
#include "llvm/IR/Dominators.h"
2024
#include "llvm/IR/PassManager.h"
2125
#include "llvm/Passes/PassBuilder.h"
2226
#include "llvm/Transforms/IPO/AlwaysInliner.h"
@@ -28,13 +32,77 @@ using namespace llvm;
2832
using namespace polly;
2933

3034
namespace {
31-
class ScopInliner final : public CallGraphSCCPass {
35+
36+
/// Inliner implementation that works with both, LPM (using SCC_t=CallGraph) and
37+
/// NPM (using SCC_t=LazyCallGraph::SCC)
38+
template <typename SCC_t> bool runScopInlinerImpl(Function *F, SCC_t &SCC) {
39+
// We do not try to inline non-trivial SCCs because this would lead to
40+
// "infinite" inlining if we are not careful.
41+
if (SCC.size() > 1)
42+
return false;
43+
assert(SCC.size() == 1 && "found empty SCC");
44+
45+
// If the function is a nullptr, or the function is a declaration.
46+
if (!F)
47+
return false;
48+
if (F->isDeclaration()) {
49+
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
50+
<< "because it is a declaration.\n");
51+
return false;
52+
}
53+
54+
PassBuilder PB;
55+
// Populate analysis managers and register Polly-specific analyses.
56+
LoopAnalysisManager LAM;
57+
FunctionAnalysisManager FAM;
58+
CGSCCAnalysisManager CGAM;
59+
ModuleAnalysisManager MAM;
60+
PB.registerModuleAnalyses(MAM);
61+
PB.registerCGSCCAnalyses(CGAM);
62+
PB.registerFunctionAnalyses(FAM);
63+
PB.registerLoopAnalyses(LAM);
64+
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
65+
66+
auto &DT = FAM.getResult<DominatorTreeAnalysis>(*F);
67+
auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(*F);
68+
auto &LI = FAM.getResult<LoopAnalysis>(*F);
69+
auto &RI = FAM.getResult<RegionInfoAnalysis>(*F);
70+
auto &AA = FAM.getResult<AAManager>(*F);
71+
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
72+
ScopDetection SD(DT, SE, LI, RI, AA, ORE);
73+
SD.detect(*F);
74+
75+
const bool HasScopAsTopLevelRegion =
76+
SD.ValidRegions.contains(RI.getTopLevelRegion());
77+
78+
bool Changed = false;
79+
if (HasScopAsTopLevelRegion) {
80+
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
81+
<< " has scop as top level region");
82+
F->addFnAttr(llvm::Attribute::AlwaysInline);
83+
84+
ModulePassManager MPM;
85+
MPM.addPass(AlwaysInlinerPass());
86+
Module *M = F->getParent();
87+
assert(M && "Function has illegal module");
88+
PreservedAnalyses PA = MPM.run(*M, MAM);
89+
if (!PA.areAllPreserved())
90+
Changed = true;
91+
} else {
92+
POLLY_DEBUG(dbgs() << F->getName()
93+
<< " does NOT have scop as top level region\n");
94+
}
95+
96+
return Changed;
97+
}
98+
99+
class ScopInlinerWrapperPass final : public CallGraphSCCPass {
32100
using llvm::Pass::doInitialization;
33101

34102
public:
35103
static char ID;
36104

37-
ScopInliner() : CallGraphSCCPass(ID) {}
105+
ScopInlinerWrapperPass() : CallGraphSCCPass(ID) {}
38106

39107
bool doInitialization(CallGraph &CG) override {
40108
if (!polly::PollyAllowFullFunction) {
@@ -50,79 +118,48 @@ class ScopInliner final : public CallGraphSCCPass {
50118
}
51119

52120
bool runOnSCC(CallGraphSCC &SCC) override {
53-
// We do not try to inline non-trivial SCCs because this would lead to
54-
// "infinite" inlining if we are not careful.
55-
if (SCC.size() > 1)
56-
return false;
57-
assert(SCC.size() == 1 && "found empty SCC");
58121
Function *F = (*SCC.begin())->getFunction();
59-
60-
// If the function is a nullptr, or the function is a declaration.
61-
if (!F)
62-
return false;
63-
if (F->isDeclaration()) {
64-
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
65-
<< "because it is a declaration.\n");
66-
return false;
67-
}
68-
69-
PassBuilder PB;
70-
// Populate analysis managers and register Polly-specific analyses.
71-
LoopAnalysisManager LAM;
72-
FunctionAnalysisManager FAM;
73-
CGSCCAnalysisManager CGAM;
74-
ModuleAnalysisManager MAM;
75-
FAM.registerPass([] { return ScopAnalysis(); });
76-
PB.registerModuleAnalyses(MAM);
77-
PB.registerCGSCCAnalyses(CGAM);
78-
PB.registerFunctionAnalyses(FAM);
79-
PB.registerLoopAnalyses(LAM);
80-
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
81-
82-
RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F);
83-
ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F);
84-
85-
const bool HasScopAsTopLevelRegion =
86-
SD.ValidRegions.contains(RI.getTopLevelRegion());
87-
88-
bool Changed = false;
89-
if (HasScopAsTopLevelRegion) {
90-
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
91-
<< " has scop as top level region");
92-
F->addFnAttr(llvm::Attribute::AlwaysInline);
93-
94-
ModulePassManager MPM;
95-
MPM.addPass(AlwaysInlinerPass());
96-
Module *M = F->getParent();
97-
assert(M && "Function has illegal module");
98-
PreservedAnalyses PA = MPM.run(*M, MAM);
99-
if (!PA.areAllPreserved())
100-
Changed = true;
101-
} else {
102-
POLLY_DEBUG(dbgs() << F->getName()
103-
<< " does NOT have scop as top level region\n");
104-
}
105-
106-
return Changed;
122+
return runScopInlinerImpl(F, SCC);
107123
};
108124

109125
void getAnalysisUsage(AnalysisUsage &AU) const override {
110126
CallGraphSCCPass::getAnalysisUsage(AU);
111127
}
112128
};
113129
} // namespace
114-
char ScopInliner::ID;
130+
char ScopInlinerWrapperPass::ID;
115131

116-
Pass *polly::createScopInlinerPass() {
117-
ScopInliner *pass = new ScopInliner();
132+
Pass *polly::createScopInlinerWrapperPass() {
133+
ScopInlinerWrapperPass *pass = new ScopInlinerWrapperPass();
118134
return pass;
119135
}
120136

121137
INITIALIZE_PASS_BEGIN(
122-
ScopInliner, "polly-scop-inliner",
138+
ScopInlinerWrapperPass, "polly-scop-inliner",
123139
"inline functions based on how much of the function is a scop.", false,
124140
false)
125141
INITIALIZE_PASS_END(
126-
ScopInliner, "polly-scop-inliner",
142+
ScopInlinerWrapperPass, "polly-scop-inliner",
127143
"inline functions based on how much of the function is a scop.", false,
128144
false)
145+
146+
polly::ScopInlinerPass::ScopInlinerPass() {
147+
if (!polly::PollyAllowFullFunction) {
148+
report_fatal_error(
149+
"Aborting from ScopInliner because it only makes sense to run with "
150+
"-polly-allow-full-function. "
151+
"The heurtistic for ScopInliner checks that the full function is a "
152+
"Scop, which happens if and only if polly-allow-full-function is "
153+
" enabled. "
154+
" If not, the entry block is not included in the Scop");
155+
}
156+
}
157+
158+
PreservedAnalyses polly::ScopInlinerPass::run(llvm::LazyCallGraph::SCC &SCC,
159+
llvm::CGSCCAnalysisManager &AM,
160+
llvm::LazyCallGraph &CG,
161+
llvm::CGSCCUpdateResult &UR) {
162+
Function *F = &SCC.begin()->getFunction();
163+
bool Changed = runScopInlinerImpl(F, SCC);
164+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
165+
}

polly/test/ScopInliner/ignore-declares.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \
2-
; RUN: -polly-scops -disable-output < %s
1+
; RUN: opt %loadNPMPolly -polly-detect-full-functions '-passes=cgscc(polly-inline),function(print<polly-function-scops>)' -disable-output < %s
32

43
; Check that we do not crash if there are declares. We should skip function
54
; declarations and not try to query for domtree.

polly/test/ScopInliner/invariant-load-func.ll

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
; RUN: opt %loadNPMPolly -polly-detect-full-functions -polly-scop-inliner \
2-
; RUN: -polly-invariant-load-hoisting '-passes=print<polly-function-scops>' -disable-output < %s | FileCheck %s
1+
; 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
32

43
; Check that we inline a function that requires invariant load hoisting
54
; correctly.
65
; CHECK: Max Loop Depth: 2
76

8-
; REQUIRES: pollyacc
9-
107

118
; void to_be_inlined(int A[], int *begin, int *end) {
129
; for(int i = *begin; i < *end; i++) {

polly/test/ScopInliner/simple-inline-loop.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \
2-
; RUN: -polly-print-scops -disable-output < %s | FileCheck %s
1+
; RUN: opt %loadNPMPolly -polly-detect-full-functions '-passes=cgscc(polly-inline),function(print<polly-function-scops>)' -disable-output < %s 2>&1 | FileCheck %s
32

43
; Check that we get the 2 nested loops by inlining `to_be_inlined` into
54
; `inline_site`.

0 commit comments

Comments
 (0)