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