| //===- InlineAlways.cpp - Code to inline always_inline functions ----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements a custom inliner that handles only functions that |
| // are marked as "always inline". |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Transforms/IPO/AlwaysInliner.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/Analysis/AssumptionCache.h" |
| #include "llvm/Analysis/InlineCost.h" |
| #include "llvm/Analysis/TargetLibraryInfo.h" |
| #include "llvm/IR/CallSite.h" |
| #include "llvm/IR/CallingConv.h" |
| #include "llvm/IR/DataLayout.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Type.h" |
| #include "llvm/Transforms/IPO.h" |
| #include "llvm/Transforms/IPO/Inliner.h" |
| #include "llvm/Transforms/Utils/Cloning.h" |
| #include "llvm/Transforms/Utils/ModuleUtils.h" |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "inline" |
| |
| PreservedAnalyses AlwaysInlinerPass::run(Module &M, ModuleAnalysisManager &) { |
| InlineFunctionInfo IFI; |
| SmallSetVector<CallSite, 16> Calls; |
| bool Changed = false; |
| SmallVector<Function *, 16> InlinedFunctions; |
| for (Function &F : M) |
| if (!F.isDeclaration() && F.hasFnAttribute(Attribute::AlwaysInline) && |
| isInlineViable(F)) { |
| Calls.clear(); |
| |
| for (User *U : F.users()) |
| if (auto CS = CallSite(U)) |
| if (CS.getCalledFunction() == &F) |
| Calls.insert(CS); |
| |
| for (CallSite CS : Calls) |
| // FIXME: We really shouldn't be able to fail to inline at this point! |
| // We should do something to log or check the inline failures here. |
| Changed |= |
| InlineFunction(CS, IFI, /*CalleeAAR=*/nullptr, InsertLifetime); |
| |
| // Remember to try and delete this function afterward. This both avoids |
| // re-walking the rest of the module and avoids dealing with any iterator |
| // invalidation issues while deleting functions. |
| InlinedFunctions.push_back(&F); |
| } |
| |
| // Remove any live functions. |
| erase_if(InlinedFunctions, [&](Function *F) { |
| F->removeDeadConstantUsers(); |
| return !F->isDefTriviallyDead(); |
| }); |
| |
| // Delete the non-comdat ones from the module and also from our vector. |
| auto NonComdatBegin = partition( |
| InlinedFunctions, [&](Function *F) { return F->hasComdat(); }); |
| for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end())) |
| M.getFunctionList().erase(F); |
| InlinedFunctions.erase(NonComdatBegin, InlinedFunctions.end()); |
| |
| if (!InlinedFunctions.empty()) { |
| // Now we just have the comdat functions. Filter out the ones whose comdats |
| // are not actually dead. |
| filterDeadComdatFunctions(M, InlinedFunctions); |
| // The remaining functions are actually dead. |
| for (Function *F : InlinedFunctions) |
| M.getFunctionList().erase(F); |
| } |
| |
| return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); |
| } |
| |
| namespace { |
| |
| /// Inliner pass which only handles "always inline" functions. |
| /// |
| /// Unlike the \c AlwaysInlinerPass, this uses the more heavyweight \c Inliner |
| /// base class to provide several facilities such as array alloca merging. |
| class AlwaysInlinerLegacyPass : public LegacyInlinerBase { |
| |
| public: |
| AlwaysInlinerLegacyPass() : LegacyInlinerBase(ID, /*InsertLifetime*/ true) { |
| initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry()); |
| } |
| |
| AlwaysInlinerLegacyPass(bool InsertLifetime) |
| : LegacyInlinerBase(ID, InsertLifetime) { |
| initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry()); |
| } |
| |
| /// Main run interface method. We override here to avoid calling skipSCC(). |
| bool runOnSCC(CallGraphSCC &SCC) override { return inlineCalls(SCC); } |
| |
| static char ID; // Pass identification, replacement for typeid |
| |
| InlineCost getInlineCost(CallSite CS) override; |
| |
| using llvm::Pass::doFinalization; |
| bool doFinalization(CallGraph &CG) override { |
| return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true); |
| } |
| }; |
| } |
| |
| char AlwaysInlinerLegacyPass::ID = 0; |
| INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline", |
| "Inliner for always_inline functions", false, false) |
| INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) |
| INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) |
| INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) |
| INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) |
| INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline", |
| "Inliner for always_inline functions", false, false) |
| |
| Pass *llvm::createAlwaysInlinerLegacyPass(bool InsertLifetime) { |
| return new AlwaysInlinerLegacyPass(InsertLifetime); |
| } |
| |
| /// Get the inline cost for the always-inliner. |
| /// |
| /// The always inliner *only* handles functions which are marked with the |
| /// attribute to force inlining. As such, it is dramatically simpler and avoids |
| /// using the powerful (but expensive) inline cost analysis. Instead it uses |
| /// a very simple and boring direct walk of the instructions looking for |
| /// impossible-to-inline constructs. |
| /// |
| /// Note, it would be possible to go to some lengths to cache the information |
| /// computed here, but as we only expect to do this for relatively few and |
| /// small functions which have the explicit attribute to force inlining, it is |
| /// likely not worth it in practice. |
| InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallSite CS) { |
| Function *Callee = CS.getCalledFunction(); |
| |
| // Only inline direct calls to functions with always-inline attributes |
| // that are viable for inlining. FIXME: We shouldn't even get here for |
| // declarations. |
| if (Callee && !Callee->isDeclaration() && |
| CS.hasFnAttr(Attribute::AlwaysInline) && isInlineViable(*Callee)) |
| return InlineCost::getAlways(); |
| |
| return InlineCost::getNever(); |
| } |