1 //===---- ScopInliner.cpp - Polyhedral based inliner ----------------------===//
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 // Take a SCC and:
10 // 1. If it has more than one component, bail out (contains cycles)
11 // 2. If it has just one component, and if the function is entirely a scop,
12 // inline it.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "polly/LinkAllPasses.h"
17 #include "polly/ScopDetection.h"
18 #include "llvm/Analysis/CallGraph.h"
19 #include "llvm/Analysis/CallGraphSCCPass.h"
20 #include "llvm/IR/PassManager.h"
21 #include "llvm/Passes/PassBuilder.h"
22 #include "llvm/Transforms/IPO/AlwaysInliner.h"
23
24 #define DEBUG_TYPE "polly-scop-inliner"
25
26 using namespace polly;
27 extern bool polly::PollyAllowFullFunction;
28
29 namespace {
30 class ScopInliner : public CallGraphSCCPass {
31 using llvm::Pass::doInitialization;
32
33 public:
34 static char ID;
35
ScopInliner()36 ScopInliner() : CallGraphSCCPass(ID) {}
37
doInitialization(CallGraph & CG)38 bool doInitialization(CallGraph &CG) override {
39 if (!polly::PollyAllowFullFunction) {
40 report_fatal_error(
41 "Aborting from ScopInliner because it only makes sense to run with "
42 "-polly-allow-full-function. "
43 "The heurtistic for ScopInliner checks that the full function is a "
44 "Scop, which happens if and only if polly-allow-full-function is "
45 " enabled. "
46 " If not, the entry block is not included in the Scop");
47 }
48 return true;
49 }
50
runOnSCC(CallGraphSCC & SCC)51 bool runOnSCC(CallGraphSCC &SCC) override {
52 // We do not try to inline non-trivial SCCs because this would lead to
53 // "infinite" inlining if we are not careful.
54 if (SCC.size() > 1)
55 return false;
56 assert(SCC.size() == 1 && "found empty SCC");
57 Function *F = (*SCC.begin())->getFunction();
58
59 // If the function is a nullptr, or the function is a declaration.
60 if (!F)
61 return false;
62 if (F->isDeclaration()) {
63 LLVM_DEBUG(dbgs() << "Skipping " << F->getName()
64 << "because it is a declaration.\n");
65 return false;
66 }
67
68 PassBuilder PB;
69 FunctionAnalysisManager FAM;
70 FAM.registerPass([] { return ScopAnalysis(); });
71 PB.registerFunctionAnalyses(FAM);
72
73 RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F);
74 ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F);
75
76 const bool HasScopAsTopLevelRegion =
77 SD.ValidRegions.count(RI.getTopLevelRegion()) > 0;
78
79 if (HasScopAsTopLevelRegion) {
80 LLVM_DEBUG(dbgs() << "Skipping " << F->getName()
81 << " has scop as top level region");
82 F->addFnAttr(llvm::Attribute::AlwaysInline);
83
84 ModuleAnalysisManager MAM;
85 PB.registerModuleAnalyses(MAM);
86 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
87 ModulePassManager MPM;
88 MPM.addPass(AlwaysInlinerPass());
89 Module *M = F->getParent();
90 assert(M && "Function has illegal module");
91 MPM.run(*M, MAM);
92 } else {
93 LLVM_DEBUG(dbgs() << F->getName()
94 << " does NOT have scop as top level region\n");
95 }
96
97 return false;
98 };
99
getAnalysisUsage(AnalysisUsage & AU) const100 void getAnalysisUsage(AnalysisUsage &AU) const override {
101 CallGraphSCCPass::getAnalysisUsage(AU);
102 }
103 };
104 } // namespace
105 char ScopInliner::ID;
106
createScopInlinerPass()107 Pass *polly::createScopInlinerPass() {
108 ScopInliner *pass = new ScopInliner();
109 return pass;
110 }
111
112 INITIALIZE_PASS_BEGIN(
113 ScopInliner, "polly-scop-inliner",
114 "inline functions based on how much of the function is a scop.", false,
115 false)
116 INITIALIZE_PASS_END(
117 ScopInliner, "polly-scop-inliner",
118 "inline functions based on how much of the function is a scop.", false,
119 false)
120