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