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