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 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 LLVM_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 bool Changed = false; 82 if (HasScopAsTopLevelRegion) { 83 LLVM_DEBUG(dbgs() << "Skipping " << F->getName() 84 << " has scop as top level region"); 85 F->addFnAttr(llvm::Attribute::AlwaysInline); 86 87 ModuleAnalysisManager MAM; 88 PB.registerModuleAnalyses(MAM); 89 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); 90 ModulePassManager MPM; 91 MPM.addPass(AlwaysInlinerPass()); 92 Module *M = F->getParent(); 93 assert(M && "Function has illegal module"); 94 PreservedAnalyses PA = MPM.run(*M, MAM); 95 if (!PA.areAllPreserved()) 96 Changed = true; 97 } else { 98 LLVM_DEBUG(dbgs() << F->getName() 99 << " does NOT have scop as top level region\n"); 100 } 101 102 return Changed; 103 }; 104 105 void getAnalysisUsage(AnalysisUsage &AU) const override { 106 CallGraphSCCPass::getAnalysisUsage(AU); 107 } 108 }; 109 } // namespace 110 char ScopInliner::ID; 111 112 Pass *polly::createScopInlinerPass() { 113 ScopInliner *pass = new ScopInliner(); 114 return pass; 115 } 116 117 INITIALIZE_PASS_BEGIN( 118 ScopInliner, "polly-scop-inliner", 119 "inline functions based on how much of the function is a scop.", false, 120 false) 121 INITIALIZE_PASS_END( 122 ScopInliner, "polly-scop-inliner", 123 "inline functions based on how much of the function is a scop.", false, 124 false) 125