[Inlining] Introduce the function attribute "inline-max-stacksize"

The value of the attribute is a size in bytes. It has the effect of
suppressing inlining of functions whose stacksizes exceed the given value.

Reviewed By: mtrofin

Differential Revision: https://reviews.llvm.org/D129904
This commit is contained in:
Wolfgang Pieb 2022-07-15 13:19:21 -07:00
parent 2f025e0e78
commit 7ddfb4dfeb
3 changed files with 51 additions and 12 deletions

View File

@ -58,6 +58,8 @@ const uint64_t MaxSimplifiedDynamicAllocaToInline = 65536;
const char FunctionInlineCostMultiplierAttributeName[] =
"function-inline-cost-multiplier";
const char MaxInlineStackSizeAttributeName[] = "inline-max-stacksize";
} // namespace InlineConstants
// The cost-benefit pair computed by cost-benefit analysis.

View File

@ -161,12 +161,21 @@ static cl::opt<bool> DisableGEPConstOperand(
cl::desc("Disables evaluation of GetElementPtr with constant operands"));
namespace llvm {
Optional<int> getStringFnAttrAsInt(const Attribute &Attr) {
if (Attr.isValid()) {
int AttrValue = 0;
if (!Attr.getValueAsString().getAsInteger(10, AttrValue))
return AttrValue;
}
return None;
}
Optional<int> 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<int> getStringFnAttrAsInt(Function *F, StringRef AttrKind) {
return getStringFnAttrAsInt(F->getFnAttribute(AttrKind));
}
namespace InlineConstants {
@ -2713,7 +2722,13 @@ InlineResult CallAnalyzer::analyze() {
// 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<int> AttrMaxStackSize = getStringFnAttrAsInt(
Caller, InlineConstants::MaxInlineStackSizeAttributeName))
FinalStackSizeThreshold = *AttrMaxStackSize;
if (AllocatedSize > FinalStackSizeThreshold)
return InlineResult::failure("stacksize");
return finalizeAnalysis();

View File

@ -12,22 +12,44 @@ define internal i32 @foo() {
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" }