diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp --- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp +++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp @@ -1,4 +1,4 @@ -//===- InlineAlways.cpp - Code to inline always_inline functions ----------===// +//===- AlwaysInliner.cpp - Code to inline always_inline functions ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -59,9 +59,16 @@ for (User *U : F.users()) if (auto *CB = dyn_cast(U)) - if (CB->getCalledFunction() == &F && - CB->hasFnAttr(Attribute::AlwaysInline)) - Calls.insert(CB); + if (CB->getCalledFunction() == &F) { + if (F.hasFnAttribute(Attribute::AlwaysInline)) { + // Avoid inlining if noinline call site attribute. + if (!CB->isNoInline()) + Calls.insert(CB); + } else if (CB->hasFnAttr(Attribute::AlwaysInline)) { + // Ok, alwaysinline call site attribute. + Calls.insert(CB); + } + } for (CallBase *CB : Calls) { Function *Caller = CB->getCaller(); @@ -210,6 +217,9 @@ if (!CB.hasFnAttr(Attribute::AlwaysInline)) return InlineCost::getNever("no alwaysinline attribute"); + if (Callee->hasFnAttribute(Attribute::AlwaysInline) && CB.isNoInline()) + return InlineCost::getNever("noinline call site attribute"); + auto IsViable = isInlineViable(*Callee); if (!IsViable.isSuccess()) return InlineCost::getNever(IsViable.getFailureReason()); diff --git a/llvm/test/Transforms/Inline/always-inline.ll b/llvm/test/Transforms/Inline/always-inline.ll --- a/llvm/test/Transforms/Inline/always-inline.ll +++ b/llvm/test/Transforms/Inline/always-inline.ll @@ -314,3 +314,57 @@ call void @inner14() ret void } + +define internal i32 @inner15() { +; CHECK: @inner15( + ret i32 1 +} + +define i32 @outer15() { +; CHECK-LABEL: @outer15( +; CHECK: call + + %r = call i32 @inner15() noinline + ret i32 %r +} + +define internal i32 @inner16() alwaysinline { +; CHECK: @inner16( + ret i32 1 +} + +define i32 @outer16() { +; CHECK-LABEL: @outer16( +; CHECK: call + + %r = call i32 @inner16() noinline + ret i32 %r +} + +define i32 @inner17() alwaysinline { +; CHECK: @inner17( + ret i32 1 +} + +define i32 @outer17() { +; CHECK-LABEL: @outer17( +; CHECK: call + + %r = call i32 @inner17() noinline + ret i32 %r +} + +define i32 @inner18() noinline { +; CHECK: @inner18( + ret i32 1 +} + +define i32 @outer18() { +; CHECK-LABEL: @outer18( +; CHECK-NOT: call +; CHECK: ret + + %r = call i32 @inner18() alwaysinline + + ret i32 %r +}