LLVM 23.0.0git
FunctionSpecialization.h
Go to the documentation of this file.
1//===- FunctionSpecialization.h - Function Specialization -----------------===//
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// Overview:
10// ---------
11// Function Specialization is a transformation which propagates the constant
12// parameters of a function call from the caller to the callee. It is part of
13// the Inter-Procedural Sparse Conditional Constant Propagation (IPSCCP) pass.
14// The transformation runs iteratively a number of times which is controlled
15// by the option `funcspec-max-iters`. Running it multiple times is needed
16// for specializing recursive functions, but also exposes new opportunities
17// arising from specializations which return constant values or contain calls
18// which can be specialized.
19//
20// Function Specialization supports propagating constant parameters like
21// function pointers, literal constants and addresses of global variables.
22// By propagating function pointers, indirect calls become direct calls. This
23// exposes inlining opportunities which we would have otherwise missed. That's
24// why function specialization is run before the inliner in the optimization
25// pipeline; that is by design.
26//
27// Cost Model:
28// -----------
29// The cost model facilitates a utility for estimating the specialization bonus
30// from propagating a constant argument. This is the InstCostVisitor, a class
31// that inherits from the InstVisitor. The bonus itself is expressed as codesize
32// and latency savings. Codesize savings means the amount of code that becomes
33// dead in the specialization from propagating the constant, whereas latency
34// savings represents the cycles we are saving from replacing instructions with
35// constant values. The InstCostVisitor overrides a set of `visit*` methods to
36// be able to handle different types of instructions. These attempt to constant-
37// fold the instruction in which case a constant is returned and propagated
38// further.
39//
40// Function pointers are not handled by the InstCostVisitor. They are treated
41// separately as they could expose inlining opportunities via indirect call
42// promotion. The inlining bonus contributes to the total specialization score.
43//
44// For a specialization to be profitable its bonus needs to exceed a minimum
45// threshold. There are three options for controlling the threshold which are
46// expressed as percentages of the original function size:
47// * funcspec-min-codesize-savings
48// * funcspec-min-latency-savings
49// * funcspec-min-inlining-bonus
50// There's also an option for controlling the codesize growth from recursive
51// specializations. That is `funcspec-max-codesize-growth`.
52//
53// Once we have all the potential specializations with their score we need to
54// choose the best ones, which fit in the module specialization budget. That
55// is controlled by the option `funcspec-max-clones`. To find the best `NSpec`
56// specializations we use a max-heap. For more details refer to D139346.
57//
58// Ideas:
59// ------
60// - With a function specialization attribute for arguments, we could have
61// a direct way to steer function specialization, avoiding the cost-model,
62// and thus control compile-times / code-size.
63//
64// - Perhaps a post-inlining function specialization pass could be more
65// aggressive on literal constants.
66//
67// Limitations:
68// ------------
69// - We are unable to consider specializations of functions called from indirect
70// callsites whose pointer operand has a lattice value that is known to be
71// constant, either from IPSCCP or previous iterations of FuncSpec. This is
72// because SCCP has not yet replaced the uses of the known constant.
73//
74// References:
75// -----------
76// 2021 LLVM Dev Mtg “Introducing function specialisation, and can we enable
77// it by default?”, https://www.youtube.com/watch?v=zJiCjeXgV5Q
78//
79//===----------------------------------------------------------------------===//
80
81#ifndef LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H
82#define LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H
83
88#include "llvm/IR/InstVisitor.h"
94
95namespace llvm {
96// Map of potential specializations for each function. The FunctionSpecializer
97// keeps the discovered specialisation opportunities for the module in a single
98// vector, where the specialisations of each function form a contiguous range.
99// This map's value is the beginning and the end of that range.
101
102// Just a shorter abbreviation to improve indentation.
104
105// Map of known constants found during the specialization bonus estimation.
107
108// Specialization signature, used to uniquely designate a specialization within
109// a function.
110struct SpecSig {
111 // Hashing support, used to distinguish between ordinary and empty keys.
112 unsigned Key = 0;
114
115 bool operator==(const SpecSig &Other) const {
116 if (Key != Other.Key)
117 return false;
118 return Args == Other.Args;
119 }
120
121 friend hash_code hash_value(const SpecSig &S) {
123 }
124};
125
126// Specialization instance.
127struct Spec {
128 // Original function.
130
131 // Cloned function, a specialized version of the original one.
132 Function *Clone = nullptr;
133
134 // Specialization signature.
136
137 // Profitability of the specialization.
138 unsigned Score;
139
140 // Number of instructions in the specialization.
141 unsigned CodeSize;
142
143 // List of call sites, matching this specialization.
145
146 Spec(Function *F, const SpecSig &S, unsigned Score, unsigned CodeSize)
147 : F(F), Sig(S), Score(Score), CodeSize(CodeSize) {}
148 Spec(Function *F, const SpecSig &&S, unsigned Score, unsigned CodeSize)
149 : F(F), Sig(S), Score(Score), CodeSize(CodeSize) {}
150};
151
152class InstCostVisitor : public InstVisitor<InstCostVisitor, Constant *> {
153 std::function<BlockFrequencyInfo &(Function &)> GetBFI;
154 Function *F;
155 const DataLayout &DL;
157 const SCCPSolver &Solver;
158
159 ConstMap KnownConstants;
160 // Basic blocks known to be unreachable after constant propagation.
161 DenseSet<BasicBlock *> DeadBlocks;
162 // PHI nodes we have visited before.
163 DenseSet<Instruction *> VisitedPHIs;
164 // PHI nodes we have visited once without successfully constant folding them.
165 // Once the InstCostVisitor has processed all the specialization arguments,
166 // it should be possible to determine whether those PHIs can be folded
167 // (some of their incoming values may have become constant or dead).
168 SmallVector<Instruction *> PendingPHIs;
169
170 ConstMap::iterator LastVisited;
171
172public:
173 InstCostVisitor(std::function<BlockFrequencyInfo &(Function &)> GetBFI,
174 Function *F, const DataLayout &DL, TargetTransformInfo &TTI,
175 SCCPSolver &Solver)
176 : GetBFI(GetBFI), F(F), DL(DL), TTI(TTI), Solver(Solver) {}
177
179 return Solver.isBlockExecutable(BB) && !DeadBlocks.contains(BB);
180 }
181
183
185
187
188private:
189 friend class InstVisitor<InstCostVisitor, Constant *>;
190
191 Constant *findConstantFor(Value *V) const;
192
193 bool canEliminateSuccessor(BasicBlock *BB, BasicBlock *Succ) const;
194
195 Cost getCodeSizeSavingsForUser(Instruction *User, Value *Use = nullptr,
196 Constant *C = nullptr);
197
198 Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList);
199 Cost estimateSwitchInst(SwitchInst &I);
200 Cost estimateCondBrInst(CondBrInst &I);
201
202 // Transitively Incoming Values (TIV) is a set of Values that can "feed" a
203 // value to the initial PHI-node. It is defined like this:
204 //
205 // * the initial PHI-node belongs to TIV.
206 //
207 // * for every PHI-node in TIV, its operands belong to TIV
208 //
209 // If TIV for the initial PHI-node (P) contains more than one constant or a
210 // value that is not a PHI-node, then P cannot be folded to a constant.
211 //
212 // As soon as we detect these cases, we bail, without constructing the
213 // full TIV.
214 // Otherwise P can be folded to the one constant in TIV.
215 bool discoverTransitivelyIncomingValues(Constant *Const, PHINode *Root,
216 DenseSet<PHINode *> &TransitivePHIs);
217
218 Constant *visitInstruction(Instruction &I) { return nullptr; }
219 Constant *visitPHINode(PHINode &I);
220 Constant *visitFreezeInst(FreezeInst &I);
221 Constant *visitCallBase(CallBase &I);
222 Constant *visitLoadInst(LoadInst &I);
223 Constant *visitGetElementPtrInst(GetElementPtrInst &I);
224 Constant *visitSelectInst(SelectInst &I);
225 Constant *visitCastInst(CastInst &I);
226 Constant *visitCmpInst(CmpInst &I);
227 Constant *visitUnaryOperator(UnaryOperator &I);
228 Constant *visitBinaryOperator(BinaryOperator &I);
229};
230
232
233 /// The IPSCCP Solver.
234 SCCPSolver &Solver;
235
236 Module &M;
237
238 /// Analysis manager, needed to invalidate analyses.
240
241 /// Analyses used to help determine if a function should be specialized.
242 std::function<BlockFrequencyInfo &(Function &)> GetBFI;
243 std::function<const TargetLibraryInfo &(Function &)> GetTLI;
244 std::function<TargetTransformInfo &(Function &)> GetTTI;
245 std::function<AssumptionCache &(Function &)> GetAC;
246
247 SmallPtrSet<Function *, 32> Specializations;
248 SmallPtrSet<Function *, 32> DeadFunctions;
249 DenseMap<Function *, CodeMetrics> FunctionMetrics;
250 DenseMap<Function *, unsigned> FunctionGrowth;
251 unsigned NGlobals = 0;
252
253public:
255 SCCPSolver &Solver, Module &M, FunctionAnalysisManager *FAM,
256 std::function<BlockFrequencyInfo &(Function &)> GetBFI,
257 std::function<const TargetLibraryInfo &(Function &)> GetTLI,
258 std::function<TargetTransformInfo &(Function &)> GetTTI,
259 std::function<AssumptionCache &(Function &)> GetAC)
260 : Solver(Solver), M(M), FAM(FAM), GetBFI(GetBFI), GetTLI(GetTLI),
261 GetTTI(GetTTI), GetAC(GetAC) {}
262
264
265 LLVM_ABI bool run();
266
268 auto &TTI = GetTTI(*F);
269 return InstCostVisitor(GetBFI, F, M.getDataLayout(), TTI, Solver);
270 }
271
272 bool isDeadFunction(Function *F) { return DeadFunctions.contains(F); }
273
274private:
275 Constant *getPromotableAlloca(AllocaInst *Alloca, CallInst *Call);
276
277 /// A constant stack value is an AllocaInst that has a single constant
278 /// value stored to it. Return this constant if such an alloca stack value
279 /// is a function argument.
280 Constant *getConstantStackValue(CallInst *Call, Value *Val);
281
282 /// See if there are any new constant values for the callers of \p F via
283 /// stack variables and promote them to global variables.
284 void promoteConstantStackValues(Function *F);
285
286 /// Clean up fully specialized functions.
287 void removeDeadFunctions();
288
289 /// Remove any ssa_copy intrinsics that may have been introduced.
290 void cleanUpSSA();
291
292 /// @brief Find potential specialization opportunities.
293 /// @param F Function to specialize
294 /// @param FuncSize Cost of specializing a function.
295 /// @param AllSpecs A vector to add potential specializations to.
296 /// @param SM A map for a function's specialisation range
297 /// @return True, if any potential specializations were found
298 bool findSpecializations(Function *F, unsigned FuncSize,
299 SmallVectorImpl<Spec> &AllSpecs, SpecMap &SM);
300
301 /// Compute the inlining bonus for replacing argument \p A with constant \p C.
302 unsigned getInliningBonus(Argument *A, Constant *C);
303
304 bool isCandidateFunction(Function *F);
305
306 /// @brief Create a specialization of \p F and prime the SCCPSolver
307 /// @param F Function to specialize
308 /// @param S Which specialization to create
309 /// @return The new, cloned function
310 Function *createSpecialization(Function *F, const SpecSig &S);
311
312 /// Determine if it is possible to specialise the function for constant values
313 /// of the formal parameter \p A.
314 bool isArgumentInteresting(Argument *A);
315
316 /// Check if the value \p V (an actual argument) is a constant or can only
317 /// have a constant value. Return that constant.
318 Constant *getCandidateConstant(Value *V);
319
320 /// @brief Find and update calls to \p F, which match a specialization
321 /// @param F Orginal function
322 /// @param Begin Start of a range of possibly matching specialisations
323 /// @param End End of a range (exclusive) of possibly matching specialisations
324 void updateCallSites(Function *F, const Spec *Begin, const Spec *End);
325};
326} // namespace llvm
327
328#endif // LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_ABI
Definition Compiler.h:213
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
static constexpr unsigned SM(unsigned Version)
This pass exposes codegen information to IR-level passes.
an instruction to allocate memory on the stack
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
This class represents a function call, abstracting a target machine's calling convention.
This is the base class for all instructions that perform data casts.
Definition InstrTypes.h:512
This class is the base class for the comparison instructions.
Definition InstrTypes.h:728
Conditional Branch instruction.
This is an important base class in LLVM.
Definition Constant.h:43
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
DenseMapIterator< KeyT, ValueT, KeyInfoT, BucketT > iterator
Definition DenseMap.h:135
Implements a dense probed hash-table based set.
Definition DenseSet.h:289
This class represents a freeze function that returns random concrete value if an operand is either a ...
LLVM_ABI bool run()
Attempt to specialize functions in the module to enable constant propagation across function boundari...
FunctionSpecializer(SCCPSolver &Solver, Module &M, FunctionAnalysisManager *FAM, std::function< BlockFrequencyInfo &(Function &)> GetBFI, std::function< const TargetLibraryInfo &(Function &)> GetTLI, std::function< TargetTransformInfo &(Function &)> GetTTI, std::function< AssumptionCache &(Function &)> GetAC)
InstCostVisitor getInstCostVisitorFor(Function *F)
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
LLVM_ABI Cost getLatencySavingsForKnownConstants()
Compute the latency savings from replacing all arguments with constants for a specialization candidat...
LLVM_ABI Cost getCodeSizeSavingsForArg(Argument *A, Constant *C)
Compute the codesize savings for replacing argument A with constant C.
LLVM_ABI Cost getCodeSizeSavingsFromPendingPHIs()
InstCostVisitor(std::function< BlockFrequencyInfo &(Function &)> GetBFI, Function *F, const DataLayout &DL, TargetTransformInfo &TTI, SCCPSolver &Solver)
bool isBlockExecutable(BasicBlock *BB) const
Base class for instruction visitors.
Definition InstVisitor.h:78
An instruction for reading from memory.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
SCCPSolver - This interface class is a general purpose solver for Sparse Conditional Constant Propaga...
Definition SCCPSolver.h:66
This class represents the LLVM 'select' instruction.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Multiway switch.
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM Value Representation.
Definition Value.h:75
An opaque object representing a hash code.
Definition Hashing.h:78
CallInst * Call
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
InstructionCost Cost
DenseMap< Value *, Constant * > ConstMap
DenseMap< Function *, std::pair< unsigned, unsigned > > SpecMap
@ Other
Any other memory.
Definition ModRef.h:68
TargetTransformInfo TTI
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:325
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:305
SmallVector< ArgInfo, 4 > Args
bool operator==(const SpecSig &Other) const
friend hash_code hash_value(const SpecSig &S)
Spec(Function *F, const SpecSig &&S, unsigned Score, unsigned CodeSize)
SmallVector< CallBase * > CallSites
Spec(Function *F, const SpecSig &S, unsigned Score, unsigned CodeSize)