Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions llvm/include/llvm/Analysis/InlineAdvisor.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class InlineAdvisor;
class InlineAdvice {
public:
InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
OptimizationRemarkEmitter &ORE, bool IsInliningRecommended);
OptimizationRemarkEmitter &ORE, bool IsInliningRecommended,
std::optional<int> InliningCost = std::nullopt);

InlineAdvice(InlineAdvice &&) = delete;
InlineAdvice(const InlineAdvice &) = delete;
Expand Down Expand Up @@ -108,6 +109,7 @@ class InlineAdvice {

/// Get the inlining recommendation.
bool isInliningRecommended() const { return IsInliningRecommended; }
std::optional<int> inliningCost() const { return InliningCost; }
const DebugLoc &getOriginalCallSiteDebugLoc() const { return DLoc; }
const BasicBlock *getOriginalCallSiteBasicBlock() const { return Block; }

Expand All @@ -129,6 +131,7 @@ class InlineAdvice {
const BasicBlock *const Block;
OptimizationRemarkEmitter &ORE;
const bool IsInliningRecommended;
const std::optional<int> InliningCost;

private:
void markRecorded() {
Expand All @@ -145,8 +148,11 @@ class DefaultInlineAdvice : public InlineAdvice {
DefaultInlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
std::optional<InlineCost> OIC,
OptimizationRemarkEmitter &ORE, bool EmitRemarks = true)
: InlineAdvice(Advisor, CB, ORE, OIC.has_value()), OriginalCB(&CB),
OIC(OIC), EmitRemarks(EmitRemarks) {}
: InlineAdvice(Advisor, CB, ORE, OIC.has_value(),
OIC && OIC->isVariable()
? std::optional<int>(OIC->getCost())
: std::nullopt),
OriginalCB(&CB), OIC(OIC), EmitRemarks(EmitRemarks) {}

private:
void recordUnsuccessfulInliningImpl(const InlineResult &Result) override;
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Analysis/InlineCost.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ const uint64_t MaxSimplifiedDynamicAllocaToInline = 65536;

const char FunctionInlineCostMultiplierAttributeName[] =
"function-inline-cost-multiplier";
/// Cost of call site accumulation added after inlining.
const char FunctionInlineAdditionalCostAttributeName[] =
"function-inline-additional-cost";

const char MaxInlineStackSizeAttributeName[] = "inline-max-stacksize";
} // namespace InlineConstants
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Analysis/InlineAdvisor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,12 @@ DefaultInlineAdvisor::getAdviceImpl(CallBase &CB) {

InlineAdvice::InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
OptimizationRemarkEmitter &ORE,
bool IsInliningRecommended)
bool IsInliningRecommended,
std::optional<int> InliningCost)
: Advisor(Advisor), Caller(CB.getCaller()), Callee(CB.getCalledFunction()),
DLoc(CB.getDebugLoc()), Block(CB.getParent()), ORE(ORE),
IsInliningRecommended(IsInliningRecommended) {}
IsInliningRecommended(IsInliningRecommended), InliningCost(InliningCost) {
}

void InlineAdvice::recordInlineStatsIfNeeded() {
if (Advisor->ImportedFunctionsStats)
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Analysis/InlineCost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,11 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
InlineConstants::FunctionInlineCostMultiplierAttributeName))
Cost *= *AttrCostMult;

if (std::optional<int> AttrAdditonalCost = getStringFnAttrAsInt(
CandidateCall,
InlineConstants::FunctionInlineAdditionalCostAttributeName))
Cost += *AttrAdditonalCost;

if (std::optional<int> AttrThreshold =
getStringFnAttrAsInt(CandidateCall, "function-inline-threshold"))
Threshold = *AttrThreshold;
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Transforms/IPO/Inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
getStringFnAttrAsInt(
*CB, InlineConstants::FunctionInlineCostMultiplierAttributeName)
.value_or(1);
int CBInliningAdditionalCost =
getStringFnAttrAsInt(
*CB, InlineConstants::FunctionInlineAdditionalCostAttributeName)
.value_or(0);
std::optional<int> InliningCost = Advice->inliningCost();

// Setup the data structure used to plumb customization into the
// `InlineFunction` routine.
Expand Down Expand Up @@ -435,6 +440,16 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
InlineConstants::FunctionInlineCostMultiplierAttributeName,
itostr(CBCostMult * IntraSCCCostMultiplier));
ICB->addFnAttr(NewCBCostMult);
} else if (InliningCost && *InliningCost > 0) {
// Similar to hot call site thresholds that can cause Inliner to
// inline numerous functions causing compile time issues, a
// linear accumulator was created to mitigate the problem.
Attribute NewCBAdditionalCost = Attribute::get(
M.getContext(),
InlineConstants::FunctionInlineAdditionalCostAttributeName,
itostr(CBInliningAdditionalCost +
(*InliningCost - CBInliningAdditionalCost) / 16));
ICB->addFnAttr(NewCBAdditionalCost);
}
}
}
Expand Down
19 changes: 18 additions & 1 deletion llvm/lib/Transforms/IPO/ModuleInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
Advice->recordUnattemptedInlining();
continue;
}
int CBInliningAdditionalCost =
getStringFnAttrAsInt(
*CB, InlineConstants::FunctionInlineAdditionalCostAttributeName)
.value_or(0);
std::optional<int> InliningCost = Advice->inliningCost();

// Setup the data structure used to plumb customization into the
// `InlineFunction` routine.
Expand Down Expand Up @@ -265,8 +270,20 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
NewCallee = ICB->getCalledFunction();
}
if (NewCallee)
if (!NewCallee->isDeclaration())
if (!NewCallee->isDeclaration()) {
Calls->push({ICB, NewHistoryID});
if (InliningCost && *InliningCost > 0) {
// Similar to hot call site thresholds that can cause Inliner to
// inline numerous functions causing compile time issues, a linear
// accumulator was created to mitigate the problem.
Attribute NewCBAdditionalCost = Attribute::get(
M.getContext(),
InlineConstants::FunctionInlineAdditionalCostAttributeName,
itostr(CBInliningAdditionalCost +
(*InliningCost - CBInliningAdditionalCost) / 16));
ICB->addFnAttr(NewCBAdditionalCost);
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/Inline/inline-history-noinline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ define internal void @a() {
ret void
}

; CHECK: [[NOINLINE]] = { noinline }
; CHECK: [[NOINLINE]] = { noinline {{.*}}}
109 changes: 109 additions & 0 deletions llvm/test/Transforms/Inline/inline-hot-callsite-limit.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; This tests that a hot callsite gets the (higher) inlinehint-threshold even without
; without inline hints and gets inlined because the cost is less than
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
; without inline hints and gets inlined because the cost is less than
; inline hints and gets inlined because the cost is less than ???

; RUN: opt < %s -passes=inline -inline-threshold=0 -locally-hot-callsite-threshold=30 -S | FileCheck %s
; RUN: opt < %s -passes=module-inline -inline-threshold=0 -locally-hot-callsite-threshold=30 -S | FileCheck %s

; Due to the hot call site, foo0 inlined foo1, foo2, and foo3,
; but foo4 is not inlined due to the accumulated cost.

declare void @bar(ptr)

define void @foo0(ptr %p) {
; CHECK-LABEL: define void @foo0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[HEADER:.*:]]
; CHECK-NEXT: [[I_I2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[I_I1:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[I_I:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I_I]])
; CHECK-NEXT: call void @bar(ptr [[I_I]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I_I1]])
; CHECK-NEXT: call void @bar(ptr [[I_I1]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I_I2]])
; CHECK-NEXT: call void @bar(ptr [[I_I2]])
; CHECK-NEXT: call void @foo4(ptr [[P]]) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[I_I2]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[I_I1]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[I_I]])
; CHECK-NEXT: br label %[[LOOP]]
;
header:
br label %loop

loop:
call void @foo1(ptr %p)
br label %loop
}

define void @foo1(ptr %p) {
; CHECK-LABEL: define void @foo1(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: call void @foo2(ptr [[P]])
; CHECK-NEXT: ret void
;
%i = alloca i32
call void @bar(ptr %i)
call void @foo2(ptr %p)
ret void
}

define void @foo2(ptr %p) {
; CHECK-LABEL: define void @foo2(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: call void @foo3(ptr [[P]])
; CHECK-NEXT: ret void
;
%i = alloca i32
call void @bar(ptr %i)
call void @foo3(ptr %p)
ret void
}

define void @foo3(ptr %p) {
; CHECK-LABEL: define void @foo3(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: call void @foo4(ptr [[P]])
; CHECK-NEXT: ret void
;
%i = alloca i32
call void @bar(ptr %i)
call void @foo4(ptr %p)
ret void
}

define void @foo4(ptr %p) {
; CHECK-LABEL: define void @foo4(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: call void @foo5(ptr [[P]])
; CHECK-NEXT: ret void
;
%i = alloca i32
call void @bar(ptr %i)
call void @foo5(ptr %p)
ret void
}

define void @foo5(ptr %p) {
; CHECK-LABEL: define void @foo5(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: call void @bar(ptr [[I]])
; CHECK-NEXT: ret void
;
%i = alloca i32
call void @bar(ptr %i)
call void @bar(ptr %i)
ret void
}
Loading