| //===---- ScopInliner.cpp - Polyhedral based inliner ----------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Take a SCC and: |
| // 1. If it has more than one component, bail out (contains cycles) |
| // 2. If it has just one component, and if the function is entirely a scop, |
| // inline it. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "polly/ScopInliner.h" |
| #include "polly/ScopDetection.h" |
| #include "polly/ScopInliner.h" |
| #include "llvm/Analysis/CallGraph.h" |
| #include "llvm/Analysis/CallGraphSCCPass.h" |
| #include "llvm/Analysis/OptimizationRemarkEmitter.h" |
| #include "llvm/Analysis/RegionInfo.h" |
| #include "llvm/IR/Dominators.h" |
| #include "llvm/Passes/PassBuilder.h" |
| #include "llvm/Transforms/IPO/AlwaysInliner.h" |
| |
| #include "polly/Support/PollyDebug.h" |
| #define DEBUG_TYPE "polly-scop-inliner" |
| |
| using namespace llvm; |
| using namespace polly; |
| |
| namespace { |
| |
| /// Inliner implementation that works with both, LPM (using SCC_t=CallGraph) and |
| /// NPM (using SCC_t=LazyCallGraph::SCC) |
| template <typename SCC_t> bool runScopInlinerImpl(Function *F, SCC_t &SCC) { |
| // We do not try to inline non-trivial SCCs because this would lead to |
| // "infinite" inlining if we are not careful. |
| if (SCC.size() > 1) |
| return false; |
| assert(SCC.size() == 1 && "found empty SCC"); |
| |
| // If the function is a nullptr, or the function is a declaration. |
| if (!F) |
| return false; |
| if (F->isDeclaration()) { |
| POLLY_DEBUG(dbgs() << "Skipping " << F->getName() |
| << "because it is a declaration.\n"); |
| return false; |
| } |
| |
| PassBuilder PB; |
| // Populate analysis managers and register Polly-specific analyses. |
| LoopAnalysisManager LAM; |
| FunctionAnalysisManager FAM; |
| CGSCCAnalysisManager CGAM; |
| ModuleAnalysisManager MAM; |
| PB.registerModuleAnalyses(MAM); |
| PB.registerCGSCCAnalyses(CGAM); |
| PB.registerFunctionAnalyses(FAM); |
| PB.registerLoopAnalyses(LAM); |
| PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); |
| |
| auto &DT = FAM.getResult<DominatorTreeAnalysis>(*F); |
| auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(*F); |
| auto &LI = FAM.getResult<LoopAnalysis>(*F); |
| auto &RI = FAM.getResult<RegionInfoAnalysis>(*F); |
| auto &AA = FAM.getResult<AAManager>(*F); |
| auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F); |
| ScopDetection SD(DT, SE, LI, RI, AA, ORE); |
| SD.detect(*F); |
| |
| const bool HasScopAsTopLevelRegion = |
| SD.ValidRegions.contains(RI.getTopLevelRegion()); |
| |
| bool Changed = false; |
| if (HasScopAsTopLevelRegion) { |
| POLLY_DEBUG(dbgs() << "Skipping " << F->getName() |
| << " has scop as top level region"); |
| F->addFnAttr(llvm::Attribute::AlwaysInline); |
| |
| ModulePassManager MPM; |
| MPM.addPass(AlwaysInlinerPass()); |
| Module *M = F->getParent(); |
| assert(M && "Function has illegal module"); |
| PreservedAnalyses PA = MPM.run(*M, MAM); |
| if (!PA.areAllPreserved()) |
| Changed = true; |
| } else { |
| POLLY_DEBUG(dbgs() << F->getName() |
| << " does NOT have scop as top level region\n"); |
| } |
| |
| return Changed; |
| } |
| } // namespace |
| |
| polly::ScopInlinerPass::ScopInlinerPass() { |
| if (!polly::PollyAllowFullFunction) { |
| report_fatal_error( |
| "Aborting from ScopInliner because it only makes sense to run with " |
| "-polly-allow-full-function. " |
| "The heurtistic for ScopInliner checks that the full function is a " |
| "Scop, which happens if and only if polly-allow-full-function is " |
| " enabled. " |
| " If not, the entry block is not included in the Scop"); |
| } |
| } |
| |
| PreservedAnalyses polly::ScopInlinerPass::run(llvm::LazyCallGraph::SCC &SCC, |
| llvm::CGSCCAnalysisManager &AM, |
| llvm::LazyCallGraph &CG, |
| llvm::CGSCCUpdateResult &UR) { |
| Function *F = &SCC.begin()->getFunction(); |
| bool Changed = runScopInlinerImpl(F, SCC); |
| return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); |
| } |