diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index f7914f864fb8..18d2c9cfb522 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -941,9 +941,10 @@ example: attribute; this attribute is also incompatible with the ``minsize`` attribute and the ``optsize`` attribute. - The inliner should never inline this function in any situation. + This attribute requires the ``noinline`` attribute to be specified on + the function as well, so the function is never inlined into any caller. Only functions with the ``alwaysinline`` attribute are valid - candidates for inlining inside the body of this function. + candidates for inlining into the body of this function. ``optsize`` This attribute suggests that optimization passes and code generator passes make choices that keep the code size of this function low, diff --git a/llvm/lib/Analysis/IPA/InlineCost.cpp b/llvm/lib/Analysis/IPA/InlineCost.cpp index 89dcd819ee2c..013691b668b2 100644 --- a/llvm/lib/Analysis/IPA/InlineCost.cpp +++ b/llvm/lib/Analysis/IPA/InlineCost.cpp @@ -1206,6 +1206,10 @@ InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee, if (!functionsHaveCompatibleAttributes(CS.getCaller(), Callee)) return llvm::InlineCost::getNever(); + // Don't inline this call if the caller has the optnone attribute. + if (CS.getCaller()->hasFnAttribute(Attribute::OptimizeNone)) + return llvm::InlineCost::getNever(); + // Don't inline functions which can be redefined at link-time to mean // something else. Don't inline functions marked noinline or call sites // marked noinline. diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 0bcb118ecad6..da6b573a0c3c 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -927,9 +927,9 @@ void Verifier::VerifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs, if (Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::OptimizeNone)) { - Assert1(!Attrs.hasAttribute(AttributeSet::FunctionIndex, - Attribute::AlwaysInline), - "Attributes 'alwaysinline and optnone' are incompatible!", V); + Assert1(Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::NoInline), + "Attribute 'optnone' requires 'noinline'!", V); Assert1(!Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::OptimizeForSize), diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index 2ff87d68ebcb..1789878e9f50 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -207,7 +207,7 @@ define void @f34() ret void; } -define void @f35() optnone +define void @f35() optnone noinline ; CHECK: define void @f35() #23 { ret void; @@ -236,6 +236,6 @@ define void @f35() optnone ; CHECK: attributes #20 = { "cpu"="cortex-a8" } ; CHECK: attributes #21 = { sspstrong } ; CHECK: attributes #22 = { minsize } -; CHECK: attributes #23 = { optnone } +; CHECK: attributes #23 = { noinline optnone } ; CHECK: attributes #24 = { nobuiltin } diff --git a/llvm/test/Feature/optnone.ll b/llvm/test/Feature/optnone.ll index ec1d7232b363..7d8afd4b773e 100644 --- a/llvm/test/Feature/optnone.ll +++ b/llvm/test/Feature/optnone.ll @@ -1,12 +1,12 @@ ; RUN: llvm-as < %s | llvm-dis | FileCheck %s -; Check for the presence of attribute noopt in the disassembly. +; Check for the presence of attribute optnone in the disassembly. ; CHECK: @foo() #0 define void @foo() #0 { ret void } -; CHECK: attributes #0 = { optnone } -attributes #0 = { optnone } +; CHECK: attributes #0 = { noinline optnone } +attributes #0 = { optnone noinline } diff --git a/llvm/test/Transforms/Inline/inline-optnone.ll b/llvm/test/Transforms/Inline/inline-optnone.ll new file mode 100644 index 000000000000..9b99c4558ea0 --- /dev/null +++ b/llvm/test/Transforms/Inline/inline-optnone.ll @@ -0,0 +1,52 @@ +; RUN: opt < %s -inline -S | FileCheck %s + +; Test that functions with attribute optnone are not inlined. +; Also test that only functions with attribute alwaysinline are +; valid candidates for inlining if the caller has the optnone attribute. + +; Function Attrs: alwaysinline nounwind readnone uwtable +define i32 @alwaysInlineFunction(i32 %a) #0 { +entry: + %mul = mul i32 %a, %a + ret i32 %mul +} + +; Function Attrs: nounwind readnone uwtable +define i32 @simpleFunction(i32 %a) #1 { +entry: + %add = add i32 %a, %a + ret i32 %add +} + +; Function Attrs: nounwind noinline optnone readnone uwtable +define i32 @OptnoneFunction(i32 %a) #2 { +entry: + %0 = tail call i32 @alwaysInlineFunction(i32 %a) + %1 = tail call i32 @simpleFunction(i32 %a) + %add = add i32 %0, %1 + ret i32 %add +} + +; CHECK-LABEL: @OptnoneFunction +; CHECK-NOT: call i32 @alwaysInlineFunction(i32 %a) +; CHECK: call i32 @simpleFunction(i32 %a) +; CHECK: ret + +; Function Attrs: nounwind readnone uwtable +define i32 @bar(i32 %a) #1 { +entry: + %0 = tail call i32 @OptnoneFunction(i32 5) + %1 = tail call i32 @simpleFunction(i32 6) + %add = add i32 %0, %1 + ret i32 %add +} + +; CHECK-LABEL: @bar +; CHECK: call i32 @OptnoneFunction(i32 5) +; CHECK-NOT: call i32 @simpleFunction(i32 6) +; CHECK: ret + + +attributes #0 = { alwaysinline nounwind readnone uwtable } +attributes #1 = { nounwind readnone uwtable } +attributes #2 = { nounwind noinline optnone readnone uwtable }