blob: ed54731c6b2a3e143fcb1080584e9f1dc347598a [file] [log] [blame]
//===---- ScopInliner.cpp - Polyhedral based inliner ----------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See 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/LinkAllPasses.h"
#include "polly/ScopDetection.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#define DEBUG_TYPE "polly-scop-inliner"
using namespace llvm;
using namespace polly;
extern bool polly::PollyAllowFullFunction;
namespace {
class ScopInliner : public CallGraphSCCPass {
using llvm::Pass::doInitialization;
static char ID;
ScopInliner() : CallGraphSCCPass(ID) {}
bool doInitialization(CallGraph &CG) override {
if (!polly::PollyAllowFullFunction) {
"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");
return true;
bool runOnSCC(CallGraphSCC &SCC) override {
// 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");
Function *F = (*SCC.begin())->getFunction();
// If the function is a nullptr, or the function is a declaration.
if (!F)
return false;
if (F->isDeclaration()) {
LLVM_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;
FAM.registerPass([] { return ScopAnalysis(); });
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F);
ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F);
const bool HasScopAsTopLevelRegion =
SD.ValidRegions.count(RI.getTopLevelRegion()) > 0;
bool Changed = false;
if (HasScopAsTopLevelRegion) {
LLVM_DEBUG(dbgs() << "Skipping " << F->getName()
<< " has scop as top level region");
ModulePassManager MPM;
Module *M = F->getParent();
assert(M && "Function has illegal module");
PreservedAnalyses PA =*M, MAM);
if (!PA.areAllPreserved())
Changed = true;
} else {
LLVM_DEBUG(dbgs() << F->getName()
<< " does NOT have scop as top level region\n");
return Changed;
void getAnalysisUsage(AnalysisUsage &AU) const override {
} // namespace
char ScopInliner::ID;
Pass *polly::createScopInlinerPass() {
ScopInliner *pass = new ScopInliner();
return pass;
ScopInliner, "polly-scop-inliner",
"inline functions based on how much of the function is a scop.", false,
ScopInliner, "polly-scop-inliner",
"inline functions based on how much of the function is a scop.", false,