diff --git a/llvm/include/llvm/Analysis/InlineCost.h b/llvm/include/llvm/Analysis/InlineCost.h --- a/llvm/include/llvm/Analysis/InlineCost.h +++ b/llvm/include/llvm/Analysis/InlineCost.h @@ -236,6 +236,16 @@ function_ref GetTLI, ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE); +/// Returns InlineResult::success() if the call site should be always inlined +/// because of user directives, and the inlining is viable. Returns +/// InlineResult::failure() if the inlining may never happen because of user +/// directives or incompatibilities detectable without needing callee traversal. +/// Otherwise returns None, meaning that inlining should be decided based on +/// other criteria (e.g. cost modeling). +Optional getAttributeBasedInliningDecision( + CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI, + function_ref GetTLI); + /// Minimal filter to detect invalid constructs for inlining. InlineResult isInlineViable(Function &Callee); } // namespace llvm diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -2215,17 +2215,13 @@ GetAssumptionCache, GetBFI, GetTLI, PSI, ORE); } -InlineCost llvm::getInlineCost( - CallBase &Call, Function *Callee, const InlineParams &Params, - TargetTransformInfo &CalleeTTI, - std::function &GetAssumptionCache, - Optional> GetBFI, - function_ref GetTLI, - ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { +Optional llvm::getAttributeBasedInliningDecision( + CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI, + function_ref GetTLI) { // Cannot inline indirect calls. if (!Callee) - return llvm::InlineCost::getNever("indirect call"); + return InlineResult::failure("indirect call"); // Never inline calls with byval arguments that does not have the alloca // address space. Since byval arguments can be replaced with a copy to an @@ -2237,8 +2233,8 @@ if (Call.isByValArgument(I)) { PointerType *PTy = cast(Call.getArgOperand(I)->getType()); if (PTy->getAddressSpace() != AllocaAS) - return llvm::InlineCost::getNever("byval arguments without alloca" - " address space"); + return InlineResult::failure("byval arguments without alloca" + " address space"); } // Calls to functions with always-inline attributes should be inlined @@ -2246,39 +2242,60 @@ if (Call.hasFnAttr(Attribute::AlwaysInline)) { auto IsViable = isInlineViable(*Callee); if (IsViable.isSuccess()) - return llvm::InlineCost::getAlways("always inline attribute"); - return llvm::InlineCost::getNever(IsViable.getFailureReason()); + return InlineResult::success(); + return InlineResult::failure(IsViable.getFailureReason()); } // Never inline functions with conflicting attributes (unless callee has // always-inline attribute). Function *Caller = Call.getCaller(); if (!functionsHaveCompatibleAttributes(Caller, Callee, CalleeTTI, GetTLI)) - return llvm::InlineCost::getNever("conflicting attributes"); + return InlineResult::failure("conflicting attributes"); // Don't inline this call if the caller has the optnone attribute. if (Caller->hasOptNone()) - return llvm::InlineCost::getNever("optnone attribute"); + return InlineResult::failure("optnone attribute"); // Don't inline a function that treats null pointer as valid into a caller // that does not have this attribute. if (!Caller->nullPointerIsDefined() && Callee->nullPointerIsDefined()) - return llvm::InlineCost::getNever("nullptr definitions incompatible"); + return InlineResult::failure("nullptr definitions incompatible"); // Don't inline functions which can be interposed at link-time. if (Callee->isInterposable()) - return llvm::InlineCost::getNever("interposable"); + return InlineResult::failure("interposable"); // Don't inline functions marked noinline. if (Callee->hasFnAttribute(Attribute::NoInline)) - return llvm::InlineCost::getNever("noinline function attribute"); + return InlineResult::failure("noinline function attribute"); // Don't inline call sites marked noinline. if (Call.isNoInline()) - return llvm::InlineCost::getNever("noinline call site attribute"); + return InlineResult::failure("noinline call site attribute"); + + return None; +} + +InlineCost llvm::getInlineCost( + CallBase &Call, Function *Callee, const InlineParams &Params, + TargetTransformInfo &CalleeTTI, + std::function &GetAssumptionCache, + Optional> GetBFI, + function_ref GetTLI, + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { + + auto UserDecision = + llvm::getAttributeBasedInliningDecision(Call, Callee, CalleeTTI, GetTLI); + + if (UserDecision.hasValue()) { + if (UserDecision->isSuccess()) + return llvm::InlineCost::getAlways("always inline attribute"); + return llvm::InlineCost::getNever(UserDecision->getFailureReason()); + } LLVM_DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName() - << "... (caller:" << Caller->getName() << ")\n"); + << "... (caller:" << Call.getCaller()->getName() + << ")\n"); InlineCostCallAnalyzer CA(CalleeTTI, GetAssumptionCache, GetBFI, PSI, ORE, *Callee, Call, Params);