aboutsummaryrefslogtreecommitdiff
path: root/polly/lib/Transform/ScopInliner.cpp
blob: 50082abf55a0d6d0f54cdd29ef2409546b0236f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//===---- 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,
                        IntrusiveRefCntPtr<vfs::FileSystem> FS) {
  // 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(
      /*TM=*/nullptr,
      /*PipelineTuningOptions=*/{},
      /*PGOOpt=*/{},
      /*PIC=*/nullptr, std::move(FS));
  // 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(IntrusiveRefCntPtr<vfs::FileSystem> FS)
    : FS(std::move(FS)) {
  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, FS);
  return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
}