Index: llvm/lib/Analysis/InlineCost.cpp =================================================================== --- llvm/lib/Analysis/InlineCost.cpp +++ llvm/lib/Analysis/InlineCost.cpp @@ -152,12 +152,21 @@ cl::desc("Disables evaluation of GetElementPtr with constant operands")); namespace llvm { +Optional getStringFnAttrAsInt(const Attribute &Attr) { + if (Attr.isValid()) { + int AttrValue; + if (!Attr.getValueAsString().getAsInteger(10, AttrValue)) + return AttrValue; + } + return None; +} + Optional getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind) { - Attribute Attr = CB.getFnAttr(AttrKind); - int AttrValue; - if (Attr.getValueAsString().getAsInteger(10, AttrValue)) - return None; - return AttrValue; + return getStringFnAttrAsInt(CB.getFnAttr(AttrKind)); +} + +Optional getStringFnAttrAsInt(Function *F, StringRef AttrKind) { + return getStringFnAttrAsInt(F->getFnAttribute(AttrKind)); } } // namespace llvm @@ -2697,7 +2706,13 @@ // If the callee's stack size exceeds the user-specified threshold, // do not let it be inlined. - if (AllocatedSize > StackSizeThreshold) + // The command line option overrides a limit set in the function attributes. + size_t FinalStackSizeThreshold = StackSizeThreshold; + if (!StackSizeThreshold.getNumOccurrences()) + if (Optional AttrMaxStackSize = + getStringFnAttrAsInt(Caller, "inline-max-stacksize")) + FinalStackSizeThreshold = *AttrMaxStackSize; + if (AllocatedSize > FinalStackSizeThreshold) return InlineResult::failure("stacksize"); return finalizeAnalysis(); Index: llvm/test/Transforms/Inline/inline-stacksize.ll =================================================================== --- llvm/test/Transforms/Inline/inline-stacksize.ll +++ llvm/test/Transforms/Inline/inline-stacksize.ll @@ -12,22 +12,44 @@ ret i32 %3 } -define i32 @bar() { +define i32 @barNoAttr() { %1 = call i32 @foo() ret i32 %1 -; ALL: define {{.*}}@bar +; ALL: define {{.*}}@barNoAttr ; ALL-NOT: define ; UNLIMITED-NOT: call {{.*}}@foo ; LIMITED: call {{.*}}@foo } ; Check that, under the imposed limit, baz() inlines bar(), but not foo(). -define i32 @baz() { - %1 = call i32 @bar() +define i32 @bazNoAttr() { + %1 = call i32 @barNoAttr() ret i32 %1 ; ALL: define {{.*}}@baz -; UNLIMITED-NOT: call {{.*}}@bar +; UNLIMITED-NOT: call {{.*}}@barNoAttr ; UNLIMITED-NOT: call {{.*}}@foo -; LIMITED-NOT: call {{.*}}@bar +; LIMITED-NOT: call {{.*}}@barNoAttr ; LIMITED: call {{.*}}@foo } + +; Check that the function attribute prevents inlining of foo(). +define i32 @barAttr() #0 { + %1 = call i32 @foo() + ret i32 %1 +; ALL: define {{.*}}@barAttr +; ALL-NOT: define +; ALL: call {{.*}}@foo +} + +; Check that the commandline option overrides the function attribute. +define i32 @bazAttr() #1 { + %1 = call i32 @barAttr() + ret i32 %1 +; ALL: define {{.*}}@bazAttr +; UNLIMITED-NOT: call {{.*}}@barAttr +; UNLIMITED-NOT: call {{.*}}@foo +; LIMITED: call {{.*}}@foo +} + +attributes #0 = { "inline-max-stacksize"="256" } +attributes #1 = { "inline-max-stacksize"="512" }