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 llvm;
27 using namespace polly;
28 
29 namespace {
30 class ScopInliner final : 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     // Populate analysis managers and register Polly-specific analyses.
70     LoopAnalysisManager LAM;
71     FunctionAnalysisManager FAM;
72     CGSCCAnalysisManager CGAM;
73     ModuleAnalysisManager MAM;
74     FAM.registerPass([] { return ScopAnalysis(); });
75     PB.registerModuleAnalyses(MAM);
76     PB.registerCGSCCAnalyses(CGAM);
77     PB.registerFunctionAnalyses(FAM);
78     PB.registerLoopAnalyses(LAM);
79     PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
80 
81     RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F);
82     ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F);
83 
84     const bool HasScopAsTopLevelRegion =
85         SD.ValidRegions.contains(RI.getTopLevelRegion());
86 
87     bool Changed = false;
88     if (HasScopAsTopLevelRegion) {
89       LLVM_DEBUG(dbgs() << "Skipping " << F->getName()
90                         << " has scop as top level region");
91       F->addFnAttr(llvm::Attribute::AlwaysInline);
92 
93       ModulePassManager MPM;
94       MPM.addPass(AlwaysInlinerPass());
95       Module *M = F->getParent();
96       assert(M && "Function has illegal module");
97       PreservedAnalyses PA = MPM.run(*M, MAM);
98       if (!PA.areAllPreserved())
99         Changed = true;
100     } else {
101       LLVM_DEBUG(dbgs() << F->getName()
102                         << " does NOT have scop as top level region\n");
103     }
104 
105     return Changed;
106   };
107 
getAnalysisUsage(AnalysisUsage & AU) const108   void getAnalysisUsage(AnalysisUsage &AU) const override {
109     CallGraphSCCPass::getAnalysisUsage(AU);
110   }
111 };
112 } // namespace
113 char ScopInliner::ID;
114 
createScopInlinerPass()115 Pass *polly::createScopInlinerPass() {
116   ScopInliner *pass = new ScopInliner();
117   return pass;
118 }
119 
120 INITIALIZE_PASS_BEGIN(
121     ScopInliner, "polly-scop-inliner",
122     "inline functions based on how much of the function is a scop.", false,
123     false)
124 INITIALIZE_PASS_END(
125     ScopInliner, "polly-scop-inliner",
126     "inline functions based on how much of the function is a scop.", false,
127     false)
128