Skip to content

Commit 82505fb

Browse files
authored
[Inliner] Put inline history into IR as !inline_history metadata (llvm#190700)
(Reland of llvm#190092 with verifier change to look through GlobalAliases) So that it's preserved across all inline invocations rather than just one inliner pass run. This prevents cases where devirtualization in the simplification pipeline uncovers inlining opportunities that should be discarded due to inline history, but we dropped the inline history between inliner pass runs, causing code size to blow up, sometimes exponentially. For compile time reasons, we want to limit this to only call sites that have the potential to inline through SCCs, potentially with the help of devirtualization. This means that the callee is in a non-trivial (Ref)SCC, or the call site was previously an indirect call, which can potentially be devirtualized to call any function. The CGSCCUpdater::InlinedInternalEdges logic still seems to be relevant even with this change, as monster_scc.ll blows up if I remove that code. http://llvm-compile-time-tracker.com/compare.php?from=e830d88e8ae5f44a97cc76136a0a4e83aa9157c0&to=ed535e732fc41b79ab8efda2417886cbd0812f7f&stat=instructions:u Fixes llvm#186926.
1 parent fa70ee4 commit 82505fb

File tree

19 files changed

+394
-213
lines changed

19 files changed

+394
-213
lines changed

llvm/docs/LangRef.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8852,6 +8852,25 @@ Example:
88528852
!0 = !{ptr @a}
88538853
!1 = !{ptr @b}
88548854

8855+
'``inline_history``' Metadata
8856+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8857+
The ``inline_history`` metadata may be attached to a call instruction. It
8858+
indicates that the call instruction has been inlined from the referenced
8859+
functions. The call itself should not be inlined if it is a call to any of the
8860+
referenced functions since that could result in infinite inlining as we
8861+
continually inline through mutually recursive functions.
8862+
8863+
This is intended to be added by and used by inliner passes.
8864+
8865+
The metadata operands must all be function pointers or ``null``. ``null`` can
8866+
appear when the referenced function is erased from the module, e.g. an internal
8867+
function that has had all calls to it inlined.
8868+
8869+
.. code-block:: text
8870+
8871+
call void @foo(), !inline_history !0
8872+
8873+
!0 = !{ptr @bar, null, ptr @baz}
88558874

88568875
Module Flags Metadata
88578876
=====================

llvm/include/llvm/Analysis/InlineOrder.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@ namespace llvm {
1717
class CallBase;
1818
template <typename Fn> class function_ref;
1919

20-
template <typename T> class InlineOrder {
20+
class InlineOrder {
2121
public:
2222
virtual ~InlineOrder() = default;
2323

2424
virtual size_t size() = 0;
2525

26-
virtual void push(const T &Elt) = 0;
26+
virtual void push(CallBase *Elt) = 0;
2727

28-
virtual T pop() = 0;
28+
virtual CallBase *pop() = 0;
2929

30-
virtual void erase_if(function_ref<bool(T)> Pred) = 0;
30+
virtual void erase_if(function_ref<bool(CallBase *)> Pred) = 0;
3131

3232
bool empty() { return !size(); }
3333
};
3434

35-
LLVM_ABI std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
35+
LLVM_ABI std::unique_ptr<InlineOrder>
3636
getDefaultInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
3737
ModuleAnalysisManager &MAM, Module &M);
3838

39-
LLVM_ABI std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
39+
LLVM_ABI std::unique_ptr<InlineOrder>
4040
getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
4141
ModuleAnalysisManager &MAM, Module &M);
4242

@@ -54,10 +54,9 @@ class PluginInlineOrderAnalysis
5454
public:
5555
LLVM_ABI static AnalysisKey Key;
5656

57-
typedef std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>> (
58-
*InlineOrderFactory)(FunctionAnalysisManager &FAM,
59-
const InlineParams &Params,
60-
ModuleAnalysisManager &MAM, Module &M);
57+
typedef std::unique_ptr<InlineOrder> (*InlineOrderFactory)(
58+
FunctionAnalysisManager &FAM, const InlineParams &Params,
59+
ModuleAnalysisManager &MAM, Module &M);
6160

6261
PluginInlineOrderAnalysis(InlineOrderFactory Factory) : Factory(Factory) {
6362
assert(Factory != nullptr &&

llvm/include/llvm/IR/FixedMetadataKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45)
6060
LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
6161
LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
6262
LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
63+
LLVM_FIXED_MD_KIND(MD_inline_history, "inline_history", 49)

llvm/include/llvm/Transforms/Utils/Cloning.h

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define LLVM_TRANSFORMS_UTILS_CLONING_H
1919

2020
#include "llvm/ADT/ArrayRef.h"
21+
#include "llvm/ADT/SmallPtrSet.h"
2122
#include "llvm/ADT/SmallVector.h"
2223
#include "llvm/ADT/Twine.h"
2324
#include "llvm/Analysis/AssumptionCache.h"
@@ -88,6 +89,10 @@ struct ClonedCodeInfo {
8889
/// check whether the main VMap mapping involves simplification or not.
8990
DenseMap<const Value *, const Value *> OrigVMap;
9091

92+
// Cloned calls that were originally an indirect call. They may be direct or
93+
// indirect after cloning.
94+
SmallPtrSet<const Value *, 4> OriginallyIndirectCalls;
95+
9196
ClonedCodeInfo() = default;
9297

9398
bool isSimplified(const Value *From, const Value *To) const {
@@ -225,11 +230,12 @@ LLVM_ABI void CloneFunctionBodyInto(
225230
ValueMaterializer *Materializer = nullptr,
226231
const MetadataPredicate *IdentityMD = nullptr);
227232

228-
LLVM_ABI void CloneAndPruneIntoFromInst(
229-
Function *NewFunc, const Function *OldFunc, const Instruction *StartingInst,
230-
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
231-
SmallVectorImpl<ReturnInst *> &Returns, const char *NameSuffix = "",
232-
ClonedCodeInfo *CodeInfo = nullptr);
233+
LLVM_ABI void
234+
CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
235+
const Instruction *StartingInst,
236+
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
237+
SmallVectorImpl<ReturnInst *> &Returns,
238+
const char *NameSuffix, ClonedCodeInfo &CodeInfo);
233239

234240
/// This works exactly like CloneFunctionInto,
235241
/// except that it does some simple constant prop and DCE on the fly. The
@@ -242,10 +248,11 @@ LLVM_ABI void CloneAndPruneIntoFromInst(
242248
/// If ModuleLevelChanges is false, VMap contains no non-identity GlobalValue
243249
/// mappings.
244250
///
245-
LLVM_ABI void CloneAndPruneFunctionInto(
246-
Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap,
247-
bool ModuleLevelChanges, SmallVectorImpl<ReturnInst *> &Returns,
248-
const char *NameSuffix = "", ClonedCodeInfo *CodeInfo = nullptr);
251+
LLVM_ABI void
252+
CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc,
253+
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
254+
SmallVectorImpl<ReturnInst *> &Returns,
255+
const char *NameSuffix, ClonedCodeInfo &CodeInfo);
249256

250257
/// This class captures the data input to the InlineFunction call, and records
251258
/// the auxiliary results produced by it.
@@ -311,6 +318,7 @@ LLVM_ABI void InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
311318
bool MergeAttributes = false,
312319
AAResults *CalleeAAR = nullptr,
313320
bool InsertLifetime = true,
321+
bool TrackInlineHistory = false,
314322
Function *ForwardVarArgsTo = nullptr,
315323
OptimizationRemarkEmitter *ORE = nullptr);
316324

@@ -340,6 +348,7 @@ LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
340348
bool MergeAttributes = false,
341349
AAResults *CalleeAAR = nullptr,
342350
bool InsertLifetime = true,
351+
bool TrackInlineHistory = false,
343352
Function *ForwardVarArgsTo = nullptr,
344353
OptimizationRemarkEmitter *ORE = nullptr);
345354

@@ -352,6 +361,7 @@ LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
352361
bool MergeAttributes = false,
353362
AAResults *CalleeAAR = nullptr,
354363
bool InsertLifetime = true,
364+
bool TrackInlineHistory = false,
355365
Function *ForwardVarArgsTo = nullptr,
356366
OptimizationRemarkEmitter *ORE = nullptr);
357367

@@ -433,14 +443,6 @@ LLVM_ABI void cloneAndAdaptNoAliasScopes(ArrayRef<MDNode *> NoAliasDeclScopes,
433443
LLVM_ABI void cloneAndAdaptNoAliasScopes(ArrayRef<MDNode *> NoAliasDeclScopes,
434444
Instruction *IStart, Instruction *IEnd,
435445
LLVMContext &Context, StringRef Ext);
436-
/// Check if Function F appears in the inline history chain.
437-
/// InlineHistory is a vector of (Function, ParentHistoryID) pairs.
438-
/// Returns true if F was already inlined in the chain leading to
439-
/// InlineHistoryID.
440-
LLVM_ABI bool
441-
inlineHistoryIncludes(Function *F, int InlineHistoryID,
442-
ArrayRef<std::pair<Function *, int>> InlineHistory);
443-
444446
} // end namespace llvm
445447

446448
#endif // LLVM_TRANSFORMS_UTILS_CLONING_H

llvm/lib/Analysis/InlineOrder.cpp

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,7 @@ class MLPriority {
199199
int Cost = INT_MAX;
200200
};
201201

202-
template <typename PriorityT>
203-
class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
204-
using T = std::pair<CallBase *, int>;
205-
202+
template <typename PriorityT> class PriorityInlineOrder : public InlineOrder {
206203
bool hasLowerPriority(const CallBase *L, const CallBase *R) const {
207204
const auto I1 = Priorities.find(L);
208205
const auto I2 = Priorities.find(R);
@@ -243,31 +240,21 @@ class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
243240

244241
size_t size() override { return Heap.size(); }
245242

246-
void push(const T &Elt) override {
247-
CallBase *CB = Elt.first;
248-
const int InlineHistoryID = Elt.second;
249-
243+
void push(CallBase *CB) override {
250244
Heap.push_back(CB);
251245
Priorities[CB] = PriorityT(CB, FAM, Params);
252246
std::push_heap(Heap.begin(), Heap.end(), isLess);
253-
InlineHistoryMap[CB] = InlineHistoryID;
254247
}
255248

256-
T pop() override {
249+
CallBase *pop() override {
257250
assert(size() > 0);
258251
pop_heap_adjust();
259252

260-
CallBase *CB = Heap.pop_back_val();
261-
T Result = std::make_pair(CB, InlineHistoryMap[CB]);
262-
InlineHistoryMap.erase(CB);
263-
return Result;
253+
return Heap.pop_back_val();
264254
}
265255

266-
void erase_if(function_ref<bool(T)> Pred) override {
267-
auto PredWrapper = [=](CallBase *CB) -> bool {
268-
return Pred(std::make_pair(CB, InlineHistoryMap[CB]));
269-
};
270-
llvm::erase_if(Heap, PredWrapper);
256+
void erase_if(function_ref<bool(CallBase *)> Pred) override {
257+
llvm::erase_if(Heap, Pred);
271258
std::make_heap(Heap.begin(), Heap.end(), isLess);
272259
}
273260

@@ -284,7 +271,7 @@ class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
284271

285272
AnalysisKey llvm::PluginInlineOrderAnalysis::Key;
286273

287-
std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
274+
std::unique_ptr<InlineOrder>
288275
llvm::getDefaultInlineOrder(FunctionAnalysisManager &FAM,
289276
const InlineParams &Params,
290277
ModuleAnalysisManager &MAM, Module &M) {
@@ -309,9 +296,10 @@ llvm::getDefaultInlineOrder(FunctionAnalysisManager &FAM,
309296
return nullptr;
310297
}
311298

312-
std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
313-
llvm::getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
314-
ModuleAnalysisManager &MAM, Module &M) {
299+
std::unique_ptr<InlineOrder> llvm::getInlineOrder(FunctionAnalysisManager &FAM,
300+
const InlineParams &Params,
301+
ModuleAnalysisManager &MAM,
302+
Module &M) {
315303
if (MAM.isPassRegistered<PluginInlineOrderAnalysis>()) {
316304
LLVM_DEBUG(dbgs() << " Current used priority: plugin ---- \n");
317305
return MAM.getResult<PluginInlineOrderAnalysis>(M).Factory(FAM, Params, MAM,

llvm/lib/IR/Verifier.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
549549
void visitAccessGroupMetadata(const MDNode *MD);
550550
void visitCapturesMetadata(Instruction &I, const MDNode *Captures);
551551
void visitAllocTokenMetadata(Instruction &I, MDNode *MD);
552+
void visitInlineHistoryMetadata(Instruction &I, MDNode *MD);
552553

553554
template <class Ty> bool isValidMetadataArray(const MDTuple &N);
554555
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
@@ -5619,6 +5620,20 @@ void Verifier::visitAllocTokenMetadata(Instruction &I, MDNode *MD) {
56195620
"expected integer constant", MD);
56205621
}
56215622

5623+
void Verifier::visitInlineHistoryMetadata(Instruction &I, MDNode *MD) {
5624+
Check(isa<CallBase>(I), "!inline_history should only exist on calls", &I);
5625+
for (Metadata *Op : MD->operands()) {
5626+
// Can be null when a function is erased.
5627+
if (!Op)
5628+
continue;
5629+
Check(isa<ValueAsMetadata>(Op) &&
5630+
isa<Function>(cast<ValueAsMetadata>(Op)
5631+
->getValue()
5632+
->stripPointerCastsAndAliases()),
5633+
"!inline_history operands must be functions or null", MD);
5634+
}
5635+
}
5636+
56225637
/// verifyInstruction - Verify that an instruction is well formed.
56235638
///
56245639
void Verifier::visitInstruction(Instruction &I) {
@@ -5851,6 +5866,9 @@ void Verifier::visitInstruction(Instruction &I) {
58515866
if (MDNode *MD = I.getMetadata(LLVMContext::MD_alloc_token))
58525867
visitAllocTokenMetadata(I, MD);
58535868

5869+
if (MDNode *MD = I.getMetadata(LLVMContext::MD_inline_history))
5870+
visitInlineHistoryMetadata(I, MD);
5871+
58545872
if (MDNode *N = I.getDebugLoc().getAsMDNode()) {
58555873
CheckDI(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
58565874
visitMDNode(*N, AreDebugLocsAllowed::Yes);

llvm/lib/Transforms/IPO/AlwaysInliner.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ bool AlwaysInlineImpl(
5353
BasicBlock *Block = CB.getParent();
5454

5555
InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
56-
InlineResult Res = InlineFunction(CB, IFI, /*MergeAttributes=*/true,
57-
&GetAAR(Callee), InsertLifetime);
56+
InlineResult Res = InlineFunction(
57+
CB, IFI, /*MergeAttributes=*/true, &GetAAR(Callee), InsertLifetime,
58+
/*TrackInlineHistory=*/NewCallSites != nullptr);
5859
if (!Res.isSuccess()) {
5960
ORE.emit([&]() {
6061
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
@@ -140,8 +141,7 @@ bool AlwaysInlineImpl(
140141
continue;
141142

142143
// Detect recursion.
143-
if (Callee == F ||
144-
inlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) {
144+
if (Callee == F) {
145145
ORE.emit([&]() {
146146
return OptimizationRemarkMissed("inline", "NotInlined",
147147
CB->getDebugLoc(), CB->getParent())

0 commit comments

Comments
 (0)