1//===- ReduceInlineCallSites.cpp ------------------------------------------===//
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#include "ReduceInlineCallSites.h"
10#include "llvm/IR/InstrTypes.h"
11#include "llvm/Support/CommandLine.h"
12#include "llvm/Transforms/Utils/Cloning.h"
13
14using namespace llvm;
15
16extern cl::OptionCategory LLVMReduceOptions;
17
18static cl::opt<int> CallsiteInlineThreshold(
19 "reduce-callsite-inline-threshold",
20 cl::desc("Number of instructions in a function to unconditionally inline "
21 "(-1 for inline all)"),
22 cl::init(Val: 5), cl::cat(LLVMReduceOptions));
23
24static bool functionHasMoreThanNonTerminatorInsts(const Function &F,
25 uint64_t NumInsts) {
26 uint64_t InstCount = 0;
27 for (const BasicBlock &BB : F) {
28 for (const Instruction &I : make_range(x: BB.begin(), y: std::prev(x: BB.end()))) {
29 (void)I;
30 if (InstCount++ > NumInsts)
31 return true;
32 }
33 }
34
35 return false;
36}
37
38static bool hasOnlyOneCallUse(const Function &F) {
39 unsigned UseCount = 0;
40 for (const Use &U : F.uses()) {
41 const CallBase *CB = dyn_cast<CallBase>(Val: U.getUser());
42 if (!CB || !CB->isCallee(U: &U))
43 return false;
44 if (UseCount++ > 1)
45 return false;
46 }
47
48 return UseCount == 1;
49}
50
51// TODO: This could use more thought.
52static bool inlineWillReduceComplexity(const Function &Caller,
53 const Function &Callee) {
54 // Backdoor to force all possible inlining.
55 if (CallsiteInlineThreshold < 0)
56 return true;
57
58 if (!hasOnlyOneCallUse(F: Callee))
59 return false;
60
61 // Permit inlining small functions into big functions, or big functions into
62 // small functions.
63 if (!functionHasMoreThanNonTerminatorInsts(F: Callee, NumInsts: CallsiteInlineThreshold) &&
64 !functionHasMoreThanNonTerminatorInsts(F: Caller, NumInsts: CallsiteInlineThreshold))
65 return true;
66
67 return false;
68}
69
70static void reduceCallSites(Oracle &O, Function &F) {
71 std::vector<std::pair<CallBase *, InlineFunctionInfo>> CallSitesToInline;
72
73 for (Use &U : F.uses()) {
74 if (CallBase *CB = dyn_cast<CallBase>(Val: U.getUser())) {
75 // Ignore callsites with wrong call type.
76 if (!CB->isCallee(U: &U))
77 continue;
78
79 // We do not consider isInlineViable here. It is overly conservative in
80 // cases that the inliner should handle correctly (e.g. disallowing inline
81 // of of functions with indirectbr). Some of the other cases are for other
82 // correctness issues which we do need to worry about here.
83
84 // TODO: Should we delete the function body?
85 InlineFunctionInfo IFI;
86 if (CanInlineCallSite(CB: *CB, IFI).isSuccess() &&
87 inlineWillReduceComplexity(Caller: *CB->getFunction(), Callee: F) && !O.shouldKeep())
88 CallSitesToInline.emplace_back(args&: CB, args: std::move(IFI));
89 }
90 }
91
92 // TODO: InlineFunctionImpl will implicitly perform some simplifications /
93 // optimizations which we should be able to opt-out of.
94 for (auto [CB, IFI] : CallSitesToInline)
95 InlineFunctionImpl(CB&: *CB, IFI);
96}
97
98void llvm::reduceInlineCallSitesDeltaPass(Oracle &O, ReducerWorkItem &Program) {
99 for (Function &F : Program.getModule()) {
100 if (!F.isDeclaration())
101 reduceCallSites(O, F);
102 }
103}
104