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