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