xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/IPO/AlwaysInliner.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- AlwaysInliner.cpp - Code to inline always_inline functions ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements a custom inliner that handles only functions that
100b57cec5SDimitry Andric // are marked as "always inline".
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Transforms/IPO/AlwaysInliner.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
16e8d8bef9SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
170b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
18*0fca6ea1SDimitry Andric #include "llvm/Analysis/InlineAdvisor.h"
190b57cec5SDimitry Andric #include "llvm/Analysis/InlineCost.h"
2081ad6265SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
21e8d8bef9SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
220b57cec5SDimitry Andric #include "llvm/IR/Module.h"
23480093f4SDimitry Andric #include "llvm/InitializePasses.h"
240b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
250b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #define DEBUG_TYPE "inline"
300b57cec5SDimitry Andric 
3106c3fb27SDimitry Andric namespace {
320b57cec5SDimitry Andric 
3306c3fb27SDimitry Andric bool AlwaysInlineImpl(
3406c3fb27SDimitry Andric     Module &M, bool InsertLifetime, ProfileSummaryInfo &PSI,
3506c3fb27SDimitry Andric     function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
3606c3fb27SDimitry Andric     function_ref<AAResults &(Function &)> GetAAR,
3706c3fb27SDimitry Andric     function_ref<BlockFrequencyInfo &(Function &)> GetBFI) {
385ffd83dbSDimitry Andric   SmallSetVector<CallBase *, 16> Calls;
390b57cec5SDimitry Andric   bool Changed = false;
40*0fca6ea1SDimitry Andric   SmallVector<Function *, 16> InlinedComdatFunctions;
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric   for (Function &F : make_early_inc_range(M)) {
43e8d8bef9SDimitry Andric     if (F.isPresplitCoroutine())
44e8d8bef9SDimitry Andric       continue;
45e8d8bef9SDimitry Andric 
46*0fca6ea1SDimitry Andric     if (F.isDeclaration() || !isInlineViable(F).isSuccess())
47*0fca6ea1SDimitry Andric       continue;
48*0fca6ea1SDimitry Andric 
490b57cec5SDimitry Andric     Calls.clear();
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric     for (User *U : F.users())
525ffd83dbSDimitry Andric       if (auto *CB = dyn_cast<CallBase>(U))
5304eeddc0SDimitry Andric         if (CB->getCalledFunction() == &F &&
5481ad6265SDimitry Andric             CB->hasFnAttr(Attribute::AlwaysInline) &&
5581ad6265SDimitry Andric             !CB->getAttributes().hasFnAttr(Attribute::NoInline))
565ffd83dbSDimitry Andric           Calls.insert(CB);
570b57cec5SDimitry Andric 
58e8d8bef9SDimitry Andric     for (CallBase *CB : Calls) {
59e8d8bef9SDimitry Andric       Function *Caller = CB->getCaller();
60e8d8bef9SDimitry Andric       OptimizationRemarkEmitter ORE(Caller);
6181ad6265SDimitry Andric       DebugLoc DLoc = CB->getDebugLoc();
6281ad6265SDimitry Andric       BasicBlock *Block = CB->getParent();
63e8d8bef9SDimitry Andric 
6406c3fb27SDimitry Andric       InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
6506c3fb27SDimitry Andric                              GetBFI ? &GetBFI(*Caller) : nullptr,
6606c3fb27SDimitry Andric                              GetBFI ? &GetBFI(F) : nullptr);
67e8d8bef9SDimitry Andric 
6806c3fb27SDimitry Andric       InlineResult Res = InlineFunction(*CB, IFI, /*MergeAttributes=*/true,
6906c3fb27SDimitry Andric                                         &GetAAR(F), InsertLifetime);
7081ad6265SDimitry Andric       if (!Res.isSuccess()) {
7181ad6265SDimitry Andric         ORE.emit([&]() {
72*0fca6ea1SDimitry Andric           return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
7381ad6265SDimitry Andric                  << "'" << ore::NV("Callee", &F) << "' is not inlined into '"
7481ad6265SDimitry Andric                  << ore::NV("Caller", Caller)
7581ad6265SDimitry Andric                  << "': " << ore::NV("Reason", Res.getFailureReason());
7681ad6265SDimitry Andric         });
7781ad6265SDimitry Andric         continue;
7881ad6265SDimitry Andric       }
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric       emitInlinedIntoBasedOnCost(
8181ad6265SDimitry Andric           ORE, DLoc, Block, F, *Caller,
8281ad6265SDimitry Andric           InlineCost::getAlways("always inline attribute"),
8381ad6265SDimitry Andric           /*ForProfileContext=*/false, DEBUG_TYPE);
84e8d8bef9SDimitry Andric 
85e8d8bef9SDimitry Andric       Changed = true;
86e8d8bef9SDimitry Andric     }
870b57cec5SDimitry Andric 
88*0fca6ea1SDimitry Andric     F.removeDeadConstantUsers();
89*0fca6ea1SDimitry Andric     if (F.hasFnAttribute(Attribute::AlwaysInline) && F.isDefTriviallyDead()) {
90*0fca6ea1SDimitry Andric       // Remember to try and delete this function afterward. This allows to call
91*0fca6ea1SDimitry Andric       // filterDeadComdatFunctions() only once.
92*0fca6ea1SDimitry Andric       if (F.hasComdat()) {
93*0fca6ea1SDimitry Andric         InlinedComdatFunctions.push_back(&F);
94*0fca6ea1SDimitry Andric       } else {
950b57cec5SDimitry Andric         M.getFunctionList().erase(F);
96349cc55cSDimitry Andric         Changed = true;
97349cc55cSDimitry Andric       }
98*0fca6ea1SDimitry Andric     }
99*0fca6ea1SDimitry Andric   }
1000b57cec5SDimitry Andric 
101*0fca6ea1SDimitry Andric   if (!InlinedComdatFunctions.empty()) {
1020b57cec5SDimitry Andric     // Now we just have the comdat functions. Filter out the ones whose comdats
1030b57cec5SDimitry Andric     // are not actually dead.
104*0fca6ea1SDimitry Andric     filterDeadComdatFunctions(InlinedComdatFunctions);
1050b57cec5SDimitry Andric     // The remaining functions are actually dead.
106*0fca6ea1SDimitry Andric     for (Function *F : InlinedComdatFunctions) {
1070b57cec5SDimitry Andric       M.getFunctionList().erase(F);
108349cc55cSDimitry Andric       Changed = true;
109349cc55cSDimitry Andric     }
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
11206c3fb27SDimitry Andric   return Changed;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
11506c3fb27SDimitry Andric struct AlwaysInlinerLegacyPass : public ModulePass {
11606c3fb27SDimitry Andric   bool InsertLifetime;
1170b57cec5SDimitry Andric 
11806c3fb27SDimitry Andric   AlwaysInlinerLegacyPass()
11906c3fb27SDimitry Andric       : AlwaysInlinerLegacyPass(/*InsertLifetime*/ true) {}
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   AlwaysInlinerLegacyPass(bool InsertLifetime)
12206c3fb27SDimitry Andric       : ModulePass(ID), InsertLifetime(InsertLifetime) {
1230b57cec5SDimitry Andric     initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   /// Main run interface method.  We override here to avoid calling skipSCC().
12706c3fb27SDimitry Andric   bool runOnModule(Module &M) override {
12806c3fb27SDimitry Andric 
12906c3fb27SDimitry Andric     auto &PSI = getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
13006c3fb27SDimitry Andric     auto GetAAR = [&](Function &F) -> AAResults & {
13106c3fb27SDimitry Andric       return getAnalysis<AAResultsWrapperPass>(F).getAAResults();
13206c3fb27SDimitry Andric     };
13306c3fb27SDimitry Andric     auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
13406c3fb27SDimitry Andric       return getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
13506c3fb27SDimitry Andric     };
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric     return AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache, GetAAR,
13806c3fb27SDimitry Andric                             /*GetBFI*/ nullptr);
13906c3fb27SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
1420b57cec5SDimitry Andric 
14306c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
14406c3fb27SDimitry Andric     AU.addRequired<AssumptionCacheTracker>();
14506c3fb27SDimitry Andric     AU.addRequired<AAResultsWrapperPass>();
14606c3fb27SDimitry Andric     AU.addRequired<ProfileSummaryInfoWrapperPass>();
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric };
14906c3fb27SDimitry Andric 
15006c3fb27SDimitry Andric } // namespace
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric char AlwaysInlinerLegacyPass::ID = 0;
1530b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline",
1540b57cec5SDimitry Andric                       "Inliner for always_inline functions", false, false)
15506c3fb27SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
1560b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
1570b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
1580b57cec5SDimitry Andric INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline",
1590b57cec5SDimitry Andric                     "Inliner for always_inline functions", false, false)
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric Pass *llvm::createAlwaysInlinerLegacyPass(bool InsertLifetime) {
1620b57cec5SDimitry Andric   return new AlwaysInlinerLegacyPass(InsertLifetime);
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
16506c3fb27SDimitry Andric PreservedAnalyses AlwaysInlinerPass::run(Module &M,
16606c3fb27SDimitry Andric                                          ModuleAnalysisManager &MAM) {
16706c3fb27SDimitry Andric   FunctionAnalysisManager &FAM =
16806c3fb27SDimitry Andric       MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
16906c3fb27SDimitry Andric   auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
17006c3fb27SDimitry Andric     return FAM.getResult<AssumptionAnalysis>(F);
17106c3fb27SDimitry Andric   };
17206c3fb27SDimitry Andric   auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & {
17306c3fb27SDimitry Andric     return FAM.getResult<BlockFrequencyAnalysis>(F);
17406c3fb27SDimitry Andric   };
17506c3fb27SDimitry Andric   auto GetAAR = [&](Function &F) -> AAResults & {
17606c3fb27SDimitry Andric     return FAM.getResult<AAManager>(F);
17706c3fb27SDimitry Andric   };
17806c3fb27SDimitry Andric   auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
1790b57cec5SDimitry Andric 
18006c3fb27SDimitry Andric   bool Changed = AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache,
18106c3fb27SDimitry Andric                                   GetAAR, GetBFI);
1820b57cec5SDimitry Andric 
18306c3fb27SDimitry Andric   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
1840b57cec5SDimitry Andric }
185