//===- 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 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(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> CallSitesToInline; for (Use &U : F.uses()) { if (CallBase *CB = dyn_cast(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); } }