LLVM 24.0.0git
AlwaysInliner.cpp
Go to the documentation of this file.
1//===- AlwaysInliner.cpp - Code to inline always_inline functions ----------===//
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// This file implements a custom inliner that handles only functions that
10// are marked as "always inline".
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/SetVector.h"
25#include "llvm/IR/Module.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "inline"
33
34namespace {
35
36bool AlwaysInlineImpl(
37 Module &M, bool InsertLifetime, ProfileSummaryInfo &PSI,
39 function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
40 function_ref<AAResults &(Function &)> GetAAR,
42 function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
44 bool Changed = false;
45 SmallVector<Function *, 16> InlinedComdatFunctions;
46 SmallVector<Function *, 4> NeedFlattening;
47
48 auto TryInline = [&](CallBase &CB, Function &Callee,
49 OptimizationRemarkEmitter &ORE, const char *InlineReason,
50 SmallVectorImpl<CallBase *> *NewCallSites =
51 nullptr) -> bool {
52 Function *Caller = CB.getCaller();
53 DebugLoc DLoc = CB.getDebugLoc();
55
56 TargetTransformInfo &CalleeTTI = GetTTI(Callee);
57 std::optional<InlineResult> CanInlineWithAttributes =
58 getAttributeBasedInliningDecision(CB, &Callee, CalleeTTI, GetTLI);
59 if (!CanInlineWithAttributes || !CanInlineWithAttributes->isSuccess()) {
60 ORE.emit([&]() {
61 return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
62 << "'" << ore::NV("Callee", &Callee) << ", is not inlined into"
63 << ore::NV("Caller", Caller) << "': "
64 << ore::NV("Reason",
65 CanInlineWithAttributes.has_value()
66 ? CanInlineWithAttributes->getFailureReason()
67 : "due to incompatible function attributes");
68 });
69 return false;
70 }
71
72 InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
74 CB, IFI, /*MergeAttributes=*/true, &GetAAR(Callee), InsertLifetime,
75 /*TrackInlineHistory=*/NewCallSites != nullptr);
76 if (!Res.isSuccess()) {
77 ORE.emit([&]() {
78 return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
79 << "'" << ore::NV("Callee", &Callee) << "' is not inlined into '"
80 << ore::NV("Caller", Caller)
81 << "': " << ore::NV("Reason", Res.getFailureReason());
82 });
83 return false;
84 }
85
86 emitInlinedIntoBasedOnCost(ORE, DLoc, Block, Callee, *Caller,
87 InlineCost::getAlways(InlineReason),
88 /*ForProfileContext=*/false, DEBUG_TYPE);
89 if (FAM)
90 FAM->invalidate(*Caller, PreservedAnalyses::none());
91 if (NewCallSites)
92 *NewCallSites = std::move(IFI.InlinedCallSites);
93 return true;
94 };
95
96 for (Function &F : make_early_inc_range(M)) {
97 if (F.hasFnAttribute(Attribute::Flatten))
98 NeedFlattening.push_back(&F);
99
100 if (F.isPresplitCoroutine())
101 continue;
102
103 if (F.isDeclaration() || !isInlineViable(F).isSuccess())
104 continue;
105
106 Calls.clear();
107
108 for (User *U : F.users())
109 if (auto *CB = dyn_cast<CallBase>(U))
110 if (CB->getCalledFunction() == &F &&
111 CB->hasFnAttr(Attribute::AlwaysInline) &&
112 !CB->getAttributes().hasFnAttr(Attribute::NoInline))
113 Calls.insert(CB);
114
115 for (CallBase *CB : Calls) {
117 Changed |= TryInline(*CB, F, ORE, "always inline attribute");
118 }
119
120 F.removeDeadConstantUsers();
121 if (F.hasFnAttribute(Attribute::AlwaysInline) && F.isDefTriviallyDead()) {
122 if (F.hasComdat()) {
123 InlinedComdatFunctions.push_back(&F);
124 } else {
125 if (FAM)
126 FAM->clear(F, F.getName());
127 M.getFunctionList().erase(F);
128 Changed = true;
129 }
130 }
131 }
132
133 // Flatten functions with the flatten attribute using a local worklist.
134 for (Function *F : NeedFlattening) {
137 SmallVector<CallBase *> NewCallSites;
139
140 // Collect initial calls.
141 for (BasicBlock &BB : *F) {
142 for (Instruction &I : BB) {
143 if (auto *CB = dyn_cast<CallBase>(&I)) {
144 Function *Callee = CB->getCalledFunction();
145 if (!Callee || Callee->isDeclaration())
146 continue;
147 Worklist.push_back({CB, -1});
148 }
149 }
150 }
151
152 while (!Worklist.empty()) {
153 auto Item = Worklist.pop_back_val();
154 CallBase *CB = Item.first;
155 int InlineHistoryID = Item.second;
156 Function *Callee = CB->getCalledFunction();
157 if (!Callee)
158 continue;
159
160 // Detect recursion.
161 if (Callee == F) {
162 ORE.emit([&]() {
163 return OptimizationRemarkMissed("inline", "NotInlined",
164 CB->getDebugLoc(), CB->getParent())
165 << "'" << ore::NV("Callee", Callee)
166 << "' is not inlined into '"
167 << ore::NV("Caller", CB->getCaller())
168 << "': recursive call during flattening";
169 });
170 continue;
171 }
172
173 // Use getAttributeBasedInliningDecision for all attribute-based checks
174 // including TTI/TLI compatibility and isInlineViable.
175 TargetTransformInfo &CalleeTTI = GetTTI(*Callee);
176 auto Decision =
177 getAttributeBasedInliningDecision(*CB, Callee, CalleeTTI, GetTLI);
178 if (!Decision || !Decision->isSuccess())
179 continue;
180
181 if (!TryInline(*CB, *Callee, ORE, "flatten attribute", &NewCallSites))
182 continue;
183
184 Changed = true;
185
186 // Add new call sites from the inlined function to the worklist.
187 if (!NewCallSites.empty()) {
188 int NewHistoryID = InlineHistory.size();
189 InlineHistory.push_back({Callee, InlineHistoryID});
190 for (CallBase *NewCB : NewCallSites) {
191 Function *NewCallee = NewCB->getCalledFunction();
192 if (NewCallee && !NewCallee->isDeclaration())
193 Worklist.push_back({NewCB, NewHistoryID});
194 }
195 }
196 }
197 }
198
199 if (!InlinedComdatFunctions.empty()) {
200 // Now we just have the comdat functions. Filter out the ones whose comdats
201 // are not actually dead.
202 filterDeadComdatFunctions(InlinedComdatFunctions);
203 // The remaining functions are actually dead.
204 for (Function *F : InlinedComdatFunctions) {
205 if (FAM)
206 FAM->clear(*F, F->getName());
207 M.getFunctionList().erase(F);
208 Changed = true;
209 }
210 }
211
212 return Changed;
213}
214
215struct AlwaysInlinerLegacyPass : public ModulePass {
216 bool InsertLifetime;
217
218 AlwaysInlinerLegacyPass()
219 : AlwaysInlinerLegacyPass(/*InsertLifetime*/ true) {}
220
221 AlwaysInlinerLegacyPass(bool InsertLifetime)
222 : ModulePass(ID), InsertLifetime(InsertLifetime) {}
223
224 /// Main run interface method.
225 bool runOnModule(Module &M) override {
226
227 auto &PSI = getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
228 auto GetAAR = [&](Function &F) -> AAResults & {
229 return getAnalysis<AAResultsWrapperPass>(F).getAAResults();
230 };
231 auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
232 return getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
233 };
234 auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
235 return getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
236 };
237 auto GetTLI = [&](Function &F) -> const TargetLibraryInfo & {
238 return getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
239 };
240
241 return AlwaysInlineImpl(M, InsertLifetime, PSI, /*FAM=*/nullptr,
242 GetAssumptionCache, GetAAR, GetTTI, GetTLI);
243 }
244
245 static char ID; // Pass identification, replacement for typeid
246
247 void getAnalysisUsage(AnalysisUsage &AU) const override {
253 }
254};
255
256} // namespace
257
258char AlwaysInlinerLegacyPass::ID = 0;
259INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline",
260 "Inliner for always_inline functions", false, false)
266INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline",
267 "Inliner for always_inline functions", false, false)
268
270 return new AlwaysInlinerLegacyPass(InsertLifetime);
271}
272
276 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
277 auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
278 return FAM.getResult<AssumptionAnalysis>(F);
279 };
280 auto GetAAR = [&](Function &F) -> AAResults & {
281 return FAM.getResult<AAManager>(F);
282 };
283 auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
284 return FAM.getResult<TargetIRAnalysis>(F);
285 };
286 auto GetTLI = [&](Function &F) -> const TargetLibraryInfo & {
287 return FAM.getResult<TargetLibraryAnalysis>(F);
288 };
289 auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
290
291 bool Changed = AlwaysInlineImpl(M, InsertLifetime, PSI, &FAM,
292 GetAssumptionCache, GetAAR, GetTTI, GetTLI);
293 if (!Changed)
294 return PreservedAnalyses::all();
295
297 // We have already invalidated all analyses on modified functions.
299 return PA;
300}
Provides passes to inlining "always_inline" functions.
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file implements a set that has insertion order iteration characteristics.
This pass exposes codegen information to IR-level passes.
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
This templated class represents "all analyses that operate over <aparticular IR unit>" (e....
Definition Analysis.h:50
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
A function analysis which provides an AssumptionCache.
An immutable pass that tracks lazily created AssumptionCache objects.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
AttributeList getAttributes() const
Return the attributes for this call.
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
A debug info location.
Definition DebugLoc.h:126
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
static InlineCost getAlways(const char *Reason, std::optional< CostBenefitPair > CostBenefit=std::nullopt)
Definition InlineCost.h:127
This class captures the data input to the InlineFunction call, and records the auxiliary results prod...
Definition Cloning.h:259
SmallVector< CallBase *, 8 > InlinedCallSites
All of the new call sites inlined into the caller.
Definition Cloning.h:282
InlineResult is basically true or false.
Definition InlineCost.h:181
bool isSuccess() const
Definition InlineCost.h:190
const char * getFailureReason() const
Definition InlineCost.h:191
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
The optimization diagnostic interface.
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for missed-optimization remarks.
Pass interface - Implemented by all 'passes'.
Definition Pass.h:99
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
Analysis providing profile information.
void clear()
Completely clear the SetVector.
Definition SetVector.h:267
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
A SetVector that performs no allocations if smaller than a certain size.
Definition SetVector.h:339
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
Wrapper pass for TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, bool MergeAttributes=false, AAResults *CalleeAAR=nullptr, bool InsertLifetime=true, bool TrackInlineHistory=false, Function *ForwardVarArgsTo=nullptr, OptimizationRemarkEmitter *ORE=nullptr)
This function inlines the called function into the basic block of the caller.
LLVM_ABI InlineResult isInlineViable(Function &Callee)
Check if it is mechanically possible to inline the function Callee, based on the contents of the func...
LLVM_ABI void emitInlinedIntoBasedOnCost(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, const Function &Callee, const Function &Caller, const InlineCost &IC, bool ForProfileContext=false, const char *PassName=nullptr)
Emit ORE message based in cost (default heuristic).
LLVM_ABI Pass * createAlwaysInlinerLegacyPass(bool InsertLifetime=true)
Create a legacy pass manager instance of a pass to inline and remove functions marked as "always_inli...
LLVM_ABI std::optional< InlineResult > getAttributeBasedInliningDecision(CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI, function_ref< const TargetLibraryInfo &(Function &)> GetTLI)
Returns InlineResult::success() if the call site should be always inlined because of user directives,...
LLVM_ABI void filterDeadComdatFunctions(SmallVectorImpl< Function * > &DeadComdatFunctions)
Filter out potentially dead comdat functions where other entries keep the entire comdat group alive.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39