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
|
//===- ReduceInlineCallSites.cpp ------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "ReduceInlineCallSites.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/Cloning.h"
using namespace llvm;
extern cl::OptionCategory LLVMReduceOptions;
static cl::opt<int> CallsiteInlineThreshold(
"reduce-callsite-inline-threshold",
cl::desc("Number of instructions in a function to unconditionally inline "
"(-1 for inline all)"),
cl::init(5), cl::cat(LLVMReduceOptions));
static bool functionHasMoreThanNonTerminatorInsts(const Function &F,
uint64_t NumInsts) {
uint64_t InstCount = 0;
for (const BasicBlock &BB : F) {
for (const Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) {
(void)I;
if (InstCount++ > NumInsts)
return true;
}
}
return false;
}
static bool hasOnlyOneCallUse(const Function &F) {
unsigned UseCount = 0;
for (const Use &U : F.uses()) {
const CallBase *CB = dyn_cast<CallBase>(U.getUser());
if (!CB || !CB->isCallee(&U))
return false;
if (UseCount++ > 1)
return false;
}
return UseCount == 1;
}
// TODO: This could use more thought.
static bool inlineWillReduceComplexity(const Function &Caller,
const Function &Callee) {
// Backdoor to force all possible inlining.
if (CallsiteInlineThreshold < 0)
return true;
if (!hasOnlyOneCallUse(Callee))
return false;
// Permit inlining small functions into big functions, or big functions into
// small functions.
if (!functionHasMoreThanNonTerminatorInsts(Callee, CallsiteInlineThreshold) &&
!functionHasMoreThanNonTerminatorInsts(Caller, CallsiteInlineThreshold))
return true;
return false;
}
static void reduceCallSites(Oracle &O, Function &F) {
std::vector<std::pair<CallBase *, InlineFunctionInfo>> CallSitesToInline;
for (Use &U : F.uses()) {
if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) {
// Ignore callsites with wrong call type.
if (!CB->isCallee(&U))
continue;
// We do not consider isInlineViable here. It is overly conservative in
// cases that the inliner should handle correctly (e.g. disallowing inline
// of of functions with indirectbr). Some of the other cases are for other
// correctness issues which we do need to worry about here.
// TODO: Should we delete the function body?
InlineFunctionInfo IFI;
if (CanInlineCallSite(*CB, IFI).isSuccess() &&
inlineWillReduceComplexity(*CB->getFunction(), F) && !O.shouldKeep())
CallSitesToInline.emplace_back(CB, std::move(IFI));
}
}
// TODO: InlineFunctionImpl will implicitly perform some simplifications /
// optimizations which we should be able to opt-out of.
for (auto [CB, IFI] : CallSitesToInline)
InlineFunctionImpl(*CB, IFI);
}
void llvm::reduceInlineCallSitesDeltaPass(Oracle &O, ReducerWorkItem &Program) {
for (Function &F : Program.getModule()) {
if (!F.isDeclaration())
reduceCallSites(O, F);
}
}
|