1d828281eSDávid Bolvanský //===- AlwaysInliner.cpp - Code to inline always_inline functions ----------===//
267fc52f0SChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
667fc52f0SChandler Carruth //
767fc52f0SChandler Carruth //===----------------------------------------------------------------------===//
867fc52f0SChandler Carruth //
967fc52f0SChandler Carruth // This file implements a custom inliner that handles only functions that
1067fc52f0SChandler Carruth // are marked as "always inline".
1167fc52f0SChandler Carruth //
1267fc52f0SChandler Carruth //===----------------------------------------------------------------------===//
1367fc52f0SChandler Carruth
1467fc52f0SChandler Carruth #include "llvm/Transforms/IPO/AlwaysInliner.h"
1567fc52f0SChandler Carruth #include "llvm/ADT/SetVector.h"
1642f76e19SArthur Eubanks #include "llvm/Analysis/AliasAnalysis.h"
17aec2fa35SDaniel Jasper #include "llvm/Analysis/AssumptionCache.h"
1867fc52f0SChandler Carruth #include "llvm/Analysis/InlineCost.h"
1971c3a551Sserge-sans-paille #include "llvm/Analysis/OptimizationRemarkEmitter.h"
20eb557350SArthur Eubanks #include "llvm/Analysis/ProfileSummaryInfo.h"
2167fc52f0SChandler Carruth #include "llvm/IR/Module.h"
2205da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
231d963114SChandler Carruth #include "llvm/Transforms/IPO/Inliner.h"
2467fc52f0SChandler Carruth #include "llvm/Transforms/Utils/Cloning.h"
256e9bb7e0SChandler Carruth #include "llvm/Transforms/Utils/ModuleUtils.h"
2667fc52f0SChandler Carruth
2767fc52f0SChandler Carruth using namespace llvm;
2867fc52f0SChandler Carruth
2967fc52f0SChandler Carruth #define DEBUG_TYPE "inline"
3067fc52f0SChandler Carruth
run(Module & M,ModuleAnalysisManager & MAM)3109f56b51SLeonard Chan PreservedAnalyses AlwaysInlinerPass::run(Module &M,
3209f56b51SLeonard Chan ModuleAnalysisManager &MAM) {
3309f56b51SLeonard Chan // Add inline assumptions during code generation.
3409f56b51SLeonard Chan FunctionAnalysisManager &FAM =
3509f56b51SLeonard Chan MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
3608e2386dSMircea Trofin auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
3709f56b51SLeonard Chan return FAM.getResult<AssumptionAnalysis>(F);
3809f56b51SLeonard Chan };
39eb557350SArthur Eubanks auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
4009f56b51SLeonard Chan
414aae4e3fSMircea Trofin SmallSetVector<CallBase *, 16> Calls;
4267fc52f0SChandler Carruth bool Changed = false;
434eaff12bSChandler Carruth SmallVector<Function *, 16> InlinedFunctions;
4431e60b91SXun Li for (Function &F : M) {
4531e60b91SXun Li // When callee coroutine function is inlined into caller coroutine function
4631e60b91SXun Li // before coro-split pass,
4731e60b91SXun Li // coro-early pass can not handle this quiet well.
4831e60b91SXun Li // So we won't inline the coroutine function if it have not been unsplited
4931e60b91SXun Li if (F.isPresplitCoroutine())
5031e60b91SXun Li continue;
5131e60b91SXun Li
52fe30370bSDávid Bolvanský if (!F.isDeclaration() && isInlineViable(F).isSuccess()) {
5367fc52f0SChandler Carruth Calls.clear();
5467fc52f0SChandler Carruth
5567fc52f0SChandler Carruth for (User *U : F.users())
564aae4e3fSMircea Trofin if (auto *CB = dyn_cast<CallBase>(U))
571be1fd73SDávid Bolvanský if (CB->getCalledFunction() == &F &&
581be1fd73SDávid Bolvanský CB->hasFnAttr(Attribute::AlwaysInline) &&
591be1fd73SDávid Bolvanský !CB->getAttributes().hasFnAttr(Attribute::NoInline))
604aae4e3fSMircea Trofin Calls.insert(CB);
6167fc52f0SChandler Carruth
623bf703fbSArthur Eubanks for (CallBase *CB : Calls) {
633bf703fbSArthur Eubanks Function *Caller = CB->getCaller();
643bf703fbSArthur Eubanks OptimizationRemarkEmitter ORE(Caller);
6584c6689bSEllis Hoag DebugLoc DLoc = CB->getDebugLoc();
6684c6689bSEllis Hoag BasicBlock *Block = CB->getParent();
673bf703fbSArthur Eubanks
68eb557350SArthur Eubanks InlineFunctionInfo IFI(
69eb557350SArthur Eubanks /*cg=*/nullptr, GetAssumptionCache, &PSI,
7084c6689bSEllis Hoag &FAM.getResult<BlockFrequencyAnalysis>(*Caller),
71eb557350SArthur Eubanks &FAM.getResult<BlockFrequencyAnalysis>(F));
72eb557350SArthur Eubanks
7342f76e19SArthur Eubanks InlineResult Res = InlineFunction(
7442f76e19SArthur Eubanks *CB, IFI, &FAM.getResult<AAManager>(F), InsertLifetime);
7584c6689bSEllis Hoag if (!Res.isSuccess()) {
7684c6689bSEllis Hoag ORE.emit([&]() {
7784c6689bSEllis Hoag return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc,
7884c6689bSEllis Hoag Block)
7984c6689bSEllis Hoag << "'" << ore::NV("Callee", &F) << "' is not inlined into '"
8084c6689bSEllis Hoag << ore::NV("Caller", Caller)
8184c6689bSEllis Hoag << "': " << ore::NV("Reason", Res.getFailureReason());
8284c6689bSEllis Hoag });
8384c6689bSEllis Hoag continue;
8484c6689bSEllis Hoag }
85a20220d2SGuozhi Wei
86*f6b5142aSEllis Hoag emitInlinedIntoBasedOnCost(
87*f6b5142aSEllis Hoag ORE, DLoc, Block, F, *Caller,
88*f6b5142aSEllis Hoag InlineCost::getAlways("always inline attribute"),
89*f6b5142aSEllis Hoag /*ForProfileContext=*/false, DEBUG_TYPE);
90*f6b5142aSEllis Hoag
91a20220d2SGuozhi Wei // Merge the attributes based on the inlining.
92a20220d2SGuozhi Wei AttributeFuncs::mergeAttributesForInlining(*Caller, F);
93a20220d2SGuozhi Wei
943bf703fbSArthur Eubanks Changed = true;
953bf703fbSArthur Eubanks }
964eaff12bSChandler Carruth
97fe30370bSDávid Bolvanský if (F.hasFnAttribute(Attribute::AlwaysInline)) {
984eaff12bSChandler Carruth // Remember to try and delete this function afterward. This both avoids
99fe30370bSDávid Bolvanský // re-walking the rest of the module and avoids dealing with any
100fe30370bSDávid Bolvanský // iterator invalidation issues while deleting functions.
1014eaff12bSChandler Carruth InlinedFunctions.push_back(&F);
1024eaff12bSChandler Carruth }
10331e60b91SXun Li }
104fe30370bSDávid Bolvanský }
1054eaff12bSChandler Carruth
1066e9bb7e0SChandler Carruth // Remove any live functions.
1076e9bb7e0SChandler Carruth erase_if(InlinedFunctions, [&](Function *F) {
1086e9bb7e0SChandler Carruth F->removeDeadConstantUsers();
1096e9bb7e0SChandler Carruth return !F->isDefTriviallyDead();
1106e9bb7e0SChandler Carruth });
1116e9bb7e0SChandler Carruth
1126e9bb7e0SChandler Carruth // Delete the non-comdat ones from the module and also from our vector.
1136e9bb7e0SChandler Carruth auto NonComdatBegin = partition(
1146e9bb7e0SChandler Carruth InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
1154a9db736SArthur Eubanks for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end())) {
1166e9bb7e0SChandler Carruth M.getFunctionList().erase(F);
1174a9db736SArthur Eubanks Changed = true;
1184a9db736SArthur Eubanks }
1196e9bb7e0SChandler Carruth InlinedFunctions.erase(NonComdatBegin, InlinedFunctions.end());
1206e9bb7e0SChandler Carruth
1216e9bb7e0SChandler Carruth if (!InlinedFunctions.empty()) {
1226e9bb7e0SChandler Carruth // Now we just have the comdat functions. Filter out the ones whose comdats
1236e9bb7e0SChandler Carruth // are not actually dead.
124c8189da2SNikita Popov filterDeadComdatFunctions(InlinedFunctions);
1256e9bb7e0SChandler Carruth // The remaining functions are actually dead.
1264a9db736SArthur Eubanks for (Function *F : InlinedFunctions) {
1276e9bb7e0SChandler Carruth M.getFunctionList().erase(F);
1284a9db736SArthur Eubanks Changed = true;
1294a9db736SArthur Eubanks }
13067fc52f0SChandler Carruth }
13167fc52f0SChandler Carruth
13267fc52f0SChandler Carruth return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
13367fc52f0SChandler Carruth }
13467fc52f0SChandler Carruth
13567fc52f0SChandler Carruth namespace {
13667fc52f0SChandler Carruth
13767fc52f0SChandler Carruth /// Inliner pass which only handles "always inline" functions.
13867fc52f0SChandler Carruth ///
13967fc52f0SChandler Carruth /// Unlike the \c AlwaysInlinerPass, this uses the more heavyweight \c Inliner
14067fc52f0SChandler Carruth /// base class to provide several facilities such as array alloca merging.
1411d963114SChandler Carruth class AlwaysInlinerLegacyPass : public LegacyInlinerBase {
14267fc52f0SChandler Carruth
14367fc52f0SChandler Carruth public:
AlwaysInlinerLegacyPass()1441d963114SChandler Carruth AlwaysInlinerLegacyPass() : LegacyInlinerBase(ID, /*InsertLifetime*/ true) {
14567fc52f0SChandler Carruth initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
14667fc52f0SChandler Carruth }
14767fc52f0SChandler Carruth
AlwaysInlinerLegacyPass(bool InsertLifetime)1481d963114SChandler Carruth AlwaysInlinerLegacyPass(bool InsertLifetime)
1491d963114SChandler Carruth : LegacyInlinerBase(ID, InsertLifetime) {
15067fc52f0SChandler Carruth initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
15167fc52f0SChandler Carruth }
15267fc52f0SChandler Carruth
15367fc52f0SChandler Carruth /// Main run interface method. We override here to avoid calling skipSCC().
runOnSCC(CallGraphSCC & SCC)15467fc52f0SChandler Carruth bool runOnSCC(CallGraphSCC &SCC) override { return inlineCalls(SCC); }
15567fc52f0SChandler Carruth
15667fc52f0SChandler Carruth static char ID; // Pass identification, replacement for typeid
15767fc52f0SChandler Carruth
1584aae4e3fSMircea Trofin InlineCost getInlineCost(CallBase &CB) override;
15967fc52f0SChandler Carruth
16067fc52f0SChandler Carruth using llvm::Pass::doFinalization;
doFinalization(CallGraph & CG)16167fc52f0SChandler Carruth bool doFinalization(CallGraph &CG) override {
16267fc52f0SChandler Carruth return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true);
16367fc52f0SChandler Carruth }
16467fc52f0SChandler Carruth };
16567fc52f0SChandler Carruth }
16667fc52f0SChandler Carruth
16767fc52f0SChandler Carruth char AlwaysInlinerLegacyPass::ID = 0;
16867fc52f0SChandler Carruth INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline",
16967fc52f0SChandler Carruth "Inliner for always_inline functions", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)170aec2fa35SDaniel Jasper INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
17167fc52f0SChandler Carruth INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
17267fc52f0SChandler Carruth INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
17367fc52f0SChandler Carruth INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
17467fc52f0SChandler Carruth INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline",
17567fc52f0SChandler Carruth "Inliner for always_inline functions", false, false)
17667fc52f0SChandler Carruth
17767fc52f0SChandler Carruth Pass *llvm::createAlwaysInlinerLegacyPass(bool InsertLifetime) {
17867fc52f0SChandler Carruth return new AlwaysInlinerLegacyPass(InsertLifetime);
17967fc52f0SChandler Carruth }
18067fc52f0SChandler Carruth
1815f8f34e4SAdrian Prantl /// Get the inline cost for the always-inliner.
18267fc52f0SChandler Carruth ///
18367fc52f0SChandler Carruth /// The always inliner *only* handles functions which are marked with the
18467fc52f0SChandler Carruth /// attribute to force inlining. As such, it is dramatically simpler and avoids
18567fc52f0SChandler Carruth /// using the powerful (but expensive) inline cost analysis. Instead it uses
18667fc52f0SChandler Carruth /// a very simple and boring direct walk of the instructions looking for
18767fc52f0SChandler Carruth /// impossible-to-inline constructs.
18867fc52f0SChandler Carruth ///
18967fc52f0SChandler Carruth /// Note, it would be possible to go to some lengths to cache the information
19067fc52f0SChandler Carruth /// computed here, but as we only expect to do this for relatively few and
19167fc52f0SChandler Carruth /// small functions which have the explicit attribute to force inlining, it is
19267fc52f0SChandler Carruth /// likely not worth it in practice.
getInlineCost(CallBase & CB)1934aae4e3fSMircea Trofin InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallBase &CB) {
1944aae4e3fSMircea Trofin Function *Callee = CB.getCalledFunction();
19567fc52f0SChandler Carruth
19667fc52f0SChandler Carruth // Only inline direct calls to functions with always-inline attributes
19715b17d0aSYevgeny Rouban // that are viable for inlining.
19815b17d0aSYevgeny Rouban if (!Callee)
19915b17d0aSYevgeny Rouban return InlineCost::getNever("indirect call");
20067fc52f0SChandler Carruth
20131e60b91SXun Li // When callee coroutine function is inlined into caller coroutine function
20231e60b91SXun Li // before coro-split pass,
20331e60b91SXun Li // coro-early pass can not handle this quiet well.
20431e60b91SXun Li // So we won't inline the coroutine function if it have not been unsplited
20531e60b91SXun Li if (Callee->isPresplitCoroutine())
20631e60b91SXun Li return InlineCost::getNever("unsplited coroutine call");
20731e60b91SXun Li
20815b17d0aSYevgeny Rouban // FIXME: We shouldn't even get here for declarations.
20915b17d0aSYevgeny Rouban if (Callee->isDeclaration())
21015b17d0aSYevgeny Rouban return InlineCost::getNever("no definition");
21115b17d0aSYevgeny Rouban
2124aae4e3fSMircea Trofin if (!CB.hasFnAttr(Attribute::AlwaysInline))
21315b17d0aSYevgeny Rouban return InlineCost::getNever("no alwaysinline attribute");
21415b17d0aSYevgeny Rouban
215d828281eSDávid Bolvanský if (Callee->hasFnAttribute(Attribute::AlwaysInline) && CB.isNoInline())
216d828281eSDávid Bolvanský return InlineCost::getNever("noinline call site attribute");
217d828281eSDávid Bolvanský
21815b17d0aSYevgeny Rouban auto IsViable = isInlineViable(*Callee);
2195466597fSMircea Trofin if (!IsViable.isSuccess())
2205466597fSMircea Trofin return InlineCost::getNever(IsViable.getFailureReason());
22115b17d0aSYevgeny Rouban
22215b17d0aSYevgeny Rouban return InlineCost::getAlways("always inliner");
22367fc52f0SChandler Carruth }
224