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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- Inliner.h - Inliner pass and infrastructure --------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_IPO_INLINER_H
#define LLVM_TRANSFORMS_IPO_INLINER_H
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/InlineAdvisor.h"
#include "llvm/Analysis/InlineCost.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
class AssumptionCacheTracker;
class CallGraph;
class ProfileSummaryInfo;
/// This class contains all of the helper code which is used to perform the
/// inlining operations that do not depend on the policy. It contains the core
/// bottom-up inlining infrastructure that specific inliner passes use.
struct LegacyInlinerBase : public CallGraphSCCPass {
explicit LegacyInlinerBase(char &ID);
explicit LegacyInlinerBase(char &ID, bool InsertLifetime);
/// For this class, we declare that we require and preserve the call graph.
/// If the derived class implements this method, it should always explicitly
/// call the implementation here.
void getAnalysisUsage(AnalysisUsage &Info) const override;
using llvm::Pass::doInitialization;
bool doInitialization(CallGraph &CG) override;
/// Main run interface method, this implements the interface required by the
/// Pass class.
bool runOnSCC(CallGraphSCC &SCC) override;
using llvm::Pass::doFinalization;
/// Remove now-dead linkonce functions at the end of processing to avoid
/// breaking the SCC traversal.
bool doFinalization(CallGraph &CG) override;
/// This method must be implemented by the subclass to determine the cost of
/// inlining the specified call site. If the cost returned is greater than
/// the current inline threshold, the call site is not inlined.
virtual InlineCost getInlineCost(CallBase &CB) = 0;
/// Remove dead functions.
///
/// This also includes a hack in the form of the 'AlwaysInlineOnly' flag
/// which restricts it to deleting functions with an 'AlwaysInline'
/// attribute. This is useful for the InlineAlways pass that only wants to
/// deal with that subset of the functions.
bool removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly = false);
/// This function performs the main work of the pass. The default of
/// Inlinter::runOnSCC() calls skipSCC() before calling this method, but
/// derived classes which cannot be skipped can override that method and call
/// this function unconditionally.
bool inlineCalls(CallGraphSCC &SCC);
private:
// Insert @llvm.lifetime intrinsics.
bool InsertLifetime = true;
protected:
AssumptionCacheTracker *ACT;
ProfileSummaryInfo *PSI;
std::function<const TargetLibraryInfo &(Function &)> GetTLI;
ImportedFunctionsInliningStatistics ImportedFunctionsStats;
};
/// The inliner pass for the new pass manager.
///
/// This pass wires together the inlining utilities and the inline cost
/// analysis into a CGSCC pass. It considers every call in every function in
/// the SCC and tries to inline if profitable. It can be tuned with a number of
/// parameters to control what cost model is used and what tradeoffs are made
/// when making the decision.
///
/// It should be noted that the legacy inliners do considerably more than this
/// inliner pass does. They provide logic for manually merging allocas, and
/// doing considerable DCE including the DCE of dead functions. This pass makes
/// every attempt to be simpler. DCE of functions requires complex reasoning
/// about comdat groups, etc. Instead, it is expected that other more focused
/// passes be composed to achieve the same end result.
class InlinerPass : public PassInfoMixin<InlinerPass> {
public:
InlinerPass(bool OnlyMandatory = false,
ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None)
: OnlyMandatory(OnlyMandatory), LTOPhase(LTOPhase) {}
InlinerPass(InlinerPass &&Arg) = default;
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
LazyCallGraph &CG, CGSCCUpdateResult &UR);
void printPipeline(raw_ostream &OS,
function_ref<StringRef(StringRef)> MapClassName2PassName);
private:
InlineAdvisor &getAdvisor(const ModuleAnalysisManagerCGSCCProxy::Result &MAM,
FunctionAnalysisManager &FAM, Module &M);
std::unique_ptr<InlineAdvisor> OwnedAdvisor;
const bool OnlyMandatory;
const ThinOrFullLTOPhase LTOPhase;
};
/// Module pass, wrapping the inliner pass. This works in conjunction with the
/// InlineAdvisorAnalysis to facilitate inlining decisions taking into account
/// module-wide state, that need to keep track of inter-inliner pass runs, for
/// a given module. An InlineAdvisor is configured and kept alive for the
/// duration of the ModuleInlinerWrapperPass::run.
class ModuleInlinerWrapperPass
: public PassInfoMixin<ModuleInlinerWrapperPass> {
public:
ModuleInlinerWrapperPass(
InlineParams Params = getInlineParams(), bool MandatoryFirst = true,
InlineContext IC = {},
InliningAdvisorMode Mode = InliningAdvisorMode::Default,
unsigned MaxDevirtIterations = 0);
ModuleInlinerWrapperPass(ModuleInlinerWrapperPass &&Arg) = default;
PreservedAnalyses run(Module &, ModuleAnalysisManager &);
/// Allow adding more CGSCC passes, besides inlining. This should be called
/// before run is called, as part of pass pipeline building.
CGSCCPassManager &getPM() { return PM; }
/// Add a module pass that runs before the CGSCC passes.
template <class T> void addModulePass(T Pass) {
MPM.addPass(std::move(Pass));
}
/// Add a module pass that runs after the CGSCC passes.
template <class T> void addLateModulePass(T Pass) {
AfterCGMPM.addPass(std::move(Pass));
}
void printPipeline(raw_ostream &OS,
function_ref<StringRef(StringRef)> MapClassName2PassName);
private:
const InlineParams Params;
const InlineContext IC;
const InliningAdvisorMode Mode;
const unsigned MaxDevirtIterations;
// TODO: Clean this up so we only have one ModulePassManager.
CGSCCPassManager PM;
ModulePassManager MPM;
ModulePassManager AfterCGMPM;
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_IPO_INLINER_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|