xref: /llvm-project/polly/lib/Transform/ScopInliner.cpp (revision 601d7eab0665ba298d81952da11593124fd893a0)
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 #include "polly/Support/PollyDebug.h"
25 #define DEBUG_TYPE "polly-scop-inliner"
26 
27 using namespace llvm;
28 using namespace polly;
29 
30 namespace {
31 class ScopInliner final : public CallGraphSCCPass {
32   using llvm::Pass::doInitialization;
33 
34 public:
35   static char ID;
36 
ScopInliner()37   ScopInliner() : CallGraphSCCPass(ID) {}
38 
doInitialization(CallGraph & CG)39   bool doInitialization(CallGraph &CG) override {
40     if (!polly::PollyAllowFullFunction) {
41       report_fatal_error(
42           "Aborting from ScopInliner because it only makes sense to run with "
43           "-polly-allow-full-function. "
44           "The heurtistic for ScopInliner checks that the full function is a "
45           "Scop, which happens if and only if polly-allow-full-function is "
46           " enabled. "
47           " If not, the entry block is not included in the Scop");
48     }
49     return true;
50   }
51 
runOnSCC(CallGraphSCC & SCC)52   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");
58     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;
107   };
108 
getAnalysisUsage(AnalysisUsage & AU) const109   void getAnalysisUsage(AnalysisUsage &AU) const override {
110     CallGraphSCCPass::getAnalysisUsage(AU);
111   }
112 };
113 } // namespace
114 char ScopInliner::ID;
115 
createScopInlinerPass()116 Pass *polly::createScopInlinerPass() {
117   ScopInliner *pass = new ScopInliner();
118   return pass;
119 }
120 
121 INITIALIZE_PASS_BEGIN(
122     ScopInliner, "polly-scop-inliner",
123     "inline functions based on how much of the function is a scop.", false,
124     false)
125 INITIALIZE_PASS_END(
126     ScopInliner, "polly-scop-inliner",
127     "inline functions based on how much of the function is a scop.", false,
128     false)
129