Skip to content

Commit 3bb2850

Browse files
Daniil Suchkovmemfrob
authored andcommitted
[InlineCost] Introduce attributes to override InlineCost for inliner testing
This patch introduces four new string attributes: function-inline-cost, function-inline-threshold, call-inline-cost and call-threshold-bonus. These attributes allow you to selectively override some aspects of InlineCost analysis. That would allow us to test inliner separately from the InlineCost analysis. That could be useful when you're trying to write tests for inliner and you need to test some very specific situation, like "the inline cost has to be this high", or "the threshold has to be this low". Right now every time someone does that, they have get creative to come up with a way to make the InlineCost give them the number they need (like adding ~30 load/add pairs for a trivial test). This process can be somewhat tedious which can discourage some people from writing enough tests for their changes. Also, that results in tests that are fragile and can be easily broken without anyone noticing it because the test writer can't explicitly control what input the inliner will get from the inline cost analysis. These new attributes will alleviate those problems to an extent. Reviewed By: mtrofin Differential Revision: https://reviews.llvm.org/D109033
1 parent ee69ca1 commit 3bb2850

File tree

8 files changed

+142
-222
lines changed

8 files changed

+142
-222
lines changed

llvm/lib/Analysis/InlineCost.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,31 @@ static cl::opt<bool> DisableGEPConstOperand(
135135
namespace {
136136
class InlineCostCallAnalyzer;
137137

138+
/// This function behaves more like CallBase::hasFnAttr: when it looks for the
139+
/// requested attribute, it check both the call instruction and the called
140+
/// function (if it's available and operand bundles don't prohibit that).
141+
Attribute getFnAttr(CallBase &CB, StringRef AttrKind) {
142+
Attribute CallAttr = CB.getFnAttr(AttrKind);
143+
if (CallAttr.isValid())
144+
return CallAttr;
145+
146+
// Operand bundles override attributes on the called function, but don't
147+
// override attributes directly present on the call instruction.
148+
if (!CB.isFnAttrDisallowedByOpBundle(AttrKind))
149+
if (const Function *F = CB.getCalledFunction())
150+
return F->getFnAttribute(AttrKind);
151+
152+
return {};
153+
}
154+
155+
Optional<int> getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind) {
156+
Attribute Attr = getFnAttr(CB, AttrKind);
157+
int AttrValue;
158+
if (Attr.getValueAsString().getAsInteger(10, AttrValue))
159+
return None;
160+
return AttrValue;
161+
}
162+
138163
// This struct is used to store information about inline cost of a
139164
// particular instruction
140165
struct InstructionCostDetail {
@@ -235,6 +260,10 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
235260
/// Called the analysis engine determines load elimination won't happen.
236261
virtual void onDisableLoadElimination() {}
237262

263+
/// Called when we visit a CallBase, before the analysis starts. Return false
264+
/// to stop further processing of the instruction.
265+
virtual bool onCallBaseVisitStart(CallBase &Call) { return true; }
266+
238267
/// Called to account for a call.
239268
virtual void onCallPenalty() {}
240269

@@ -558,6 +587,22 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
558587
addCost(LoadEliminationCost);
559588
LoadEliminationCost = 0;
560589
}
590+
591+
bool onCallBaseVisitStart(CallBase &Call) override {
592+
if (Optional<int> AttrCallThresholdBonus =
593+
getStringFnAttrAsInt(Call, "call-threshold-bonus"))
594+
Threshold += *AttrCallThresholdBonus;
595+
596+
if (Optional<int> AttrCallCost =
597+
getStringFnAttrAsInt(Call, "call-inline-cost")) {
598+
addCost(*AttrCallCost);
599+
// Prevent further processing of the call since we want to override its
600+
// inline cost, not just add to it.
601+
return false;
602+
}
603+
return true;
604+
}
605+
561606
void onCallPenalty() override { addCost(CallPenalty); }
562607
void onCallArgumentSetup(const CallBase &Call) override {
563608
// Pay the price of the argument setup. We account for the average 1
@@ -847,6 +892,14 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
847892
else if (NumVectorInstructions <= NumInstructions / 2)
848893
Threshold -= VectorBonus / 2;
849894

895+
if (Optional<int> AttrCost =
896+
getStringFnAttrAsInt(CandidateCall, "function-inline-cost"))
897+
Cost = *AttrCost;
898+
899+
if (Optional<int> AttrThreshold =
900+
getStringFnAttrAsInt(CandidateCall, "function-inline-threshold"))
901+
Threshold = *AttrThreshold;
902+
850903
if (auto Result = costBenefitAnalysis()) {
851904
DecidedByCostBenefit = true;
852905
if (Result.getValue())
@@ -2029,6 +2082,9 @@ bool CallAnalyzer::simplifyCallSite(Function *F, CallBase &Call) {
20292082
}
20302083

20312084
bool CallAnalyzer::visitCallBase(CallBase &Call) {
2085+
if (!onCallBaseVisitStart(Call))
2086+
return true;
2087+
20322088
if (Call.hasFnAttr(Attribute::ReturnsTwice) &&
20332089
!F.hasFnAttribute(Attribute::ReturnsTwice)) {
20342090
// This aborts the entire analysis.

llvm/test/Transforms/Inline/inline-call-penalty-option.ll

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,20 @@
44
; RUN: opt < %s -inline --inline-call-penalty=0 --inline-threshold=5 -S | FileCheck %s
55
; RUN: opt < %s -inline --inline-threshold=5 -S | FileCheck %s -check-prefix=DEFAULT_CALL_PENALTY
66

7-
define i32 @X9(i32 %x) nounwind {
8-
%x2 = add i32 %x, %x
9-
%x3 = add i32 %x2, %x
10-
%x4 = add i32 %x3, %x
11-
%x5 = add i32 %x4, %x
12-
%x6 = add i32 %x5, %x
13-
%x7 = add i32 %x6, %x
14-
%x8 = add i32 %x7, %x
15-
%x9 = add i32 %x8, %x
7+
declare void @extern()
168

17-
ret i32 %x9
9+
define void @X9() nounwind {
10+
call void @extern() "call-inline-cost"="30"
11+
ret void
1812
}
1913

20-
define i32 @f1(i32 %x) nounwind {
21-
%res = call i32 @X9(i32 %x)
22-
ret i32 %res
14+
define void @f1() nounwind {
15+
call void @X9()
16+
ret void
2317
; CHECK-LABEL: @f1(
24-
; CHECK: %res = call i32 @X9
18+
; CHECK: call void @X9
2519

2620
; DEFAULT_CALL_PENALTY-LABEL: @f1(
27-
; DEFAULT_CALL_PENALTY-NOT: call
21+
; DEFAULT_CALL_PENALTY: call void @extern
22+
; DEFAULT_CALL_PENALTY-NOT: call void @X9
2823
}

llvm/test/Transforms/Inline/inline-cold-callee.ll

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,25 @@
77

88
define i32 @callee1(i32 %x) !prof !21 {
99
%x1 = add i32 %x, 1
10-
%x2 = add i32 %x1, 1
11-
%x3 = add i32 %x2, 1
12-
call void @extern()
13-
ret i32 %x3
10+
ret i32 %x1
1411
}
1512

1613
define i32 @callee2(i32 %x) !prof !22 {
1714
; CHECK-LABEL: @callee2(
1815
%x1 = add i32 %x, 1
19-
%x2 = add i32 %x1, 1
20-
%x3 = add i32 %x2, 1
21-
call void @extern()
22-
ret i32 %x3
16+
ret i32 %x1
2317
}
2418

2519
define i32 @caller2(i32 %y1) !prof !22 {
2620
; CHECK-LABEL: @caller2(
2721
; CHECK: call i32 @callee2
2822
; CHECK-NOT: call i32 @callee1
29-
; CHECK: ret i32 %x3.i
30-
%y2 = call i32 @callee2(i32 %y1)
31-
%y3 = call i32 @callee1(i32 %y2)
23+
; CHECK: ret i32 %x1.i
24+
%y2 = call i32 @callee2(i32 %y1) "function-inline-cost"="10"
25+
%y3 = call i32 @callee1(i32 %y2) "function-inline-cost"="10"
3226
ret i32 %y3
3327
}
3428

35-
declare void @extern()
36-
3729
!llvm.module.flags = !{!1}
3830
!21 = !{!"function_entry_count", i64 100}
3931
!22 = !{!"function_entry_count", i64 1}

llvm/test/Transforms/Inline/inline-cold-callsite-pgo.ll

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
; and does not get inlined. Another callsite to an identical callee that
55
; is not cold gets inlined because cost is below the inline-threshold.
66

7-
define i32 @callee1(i32 %x) !prof !21 {
7+
define i32 @callee1(i32 %x) "function-inline-cost"="30" !prof !21 {
88
%x1 = add i32 %x, 1
9-
%x2 = add i32 %x1, 1
10-
%x3 = add i32 %x2, 1
119
call void @extern()
12-
ret i32 %x3
10+
ret i32 %x1
1311
}
1412

1513
define i32 @caller(i32 %n) !prof !22 {
@@ -20,7 +18,7 @@ define i32 @caller(i32 %n) !prof !22 {
2018
cond_true:
2119
; CHECK-LABEL: cond_true:
2220
; CHECK-NOT: call i32 @callee1
23-
; CHECK: ret i32 %x3.i
21+
; CHECK: ret i32 %x1.i
2422
%i = call i32 @callee1(i32 %n)
2523
ret i32 %i
2624
cond_false:

llvm/test/Transforms/Inline/inline-cold-callsite.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
; and does not get inlined. Another callsite to an identical callee that
66
; is not cold gets inlined because cost is below the inline-threshold.
77

8-
define void @callee() {
9-
call void @extern()
8+
define void @callee() "function-inline-cost"="10" {
109
call void @extern()
1110
ret void
1211
}

llvm/test/Transforms/Inline/inline-cold.ll

Lines changed: 6 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -18,146 +18,33 @@
1818
; This function should be larger than the cold threshold (75), but smaller
1919
; than the regular threshold.
2020
; Function Attrs: nounwind readnone uwtable
21-
define i32 @simpleFunction(i32 %a) #0 {
21+
define i32 @simpleFunction(i32 %a) #0 "function-inline-cost"="80" {
2222
entry:
23-
call void @extern()
24-
%a1 = load volatile i32, i32* @a
25-
%x1 = add i32 %a1, %a1
26-
%a2 = load volatile i32, i32* @a
27-
%x2 = add i32 %x1, %a2
28-
%a3 = load volatile i32, i32* @a
29-
%x3 = add i32 %x2, %a3
30-
%a4 = load volatile i32, i32* @a
31-
%x4 = add i32 %x3, %a4
32-
%a5 = load volatile i32, i32* @a
33-
%x5 = add i32 %x4, %a5
34-
%a6 = load volatile i32, i32* @a
35-
%x6 = add i32 %x5, %a6
36-
%a7 = load volatile i32, i32* @a
37-
%x7 = add i32 %x6, %a6
38-
%a8 = load volatile i32, i32* @a
39-
%x8 = add i32 %x7, %a8
40-
%a9 = load volatile i32, i32* @a
41-
%x9 = add i32 %x8, %a9
42-
%a10 = load volatile i32, i32* @a
43-
%x10 = add i32 %x9, %a10
44-
%a11 = load volatile i32, i32* @a
45-
%x11 = add i32 %x10, %a11
46-
%a12 = load volatile i32, i32* @a
47-
%x12 = add i32 %x11, %a12
48-
%add = add i32 %x12, %a
49-
ret i32 %add
23+
ret i32 %a
5024
}
5125

5226
; Function Attrs: nounwind cold readnone uwtable
53-
define i32 @ColdFunction(i32 %a) #1 {
27+
define i32 @ColdFunction(i32 %a) #1 "function-inline-cost"="30" {
5428
; CHECK-LABEL: @ColdFunction
5529
; CHECK: ret
5630
; OVERRIDE-LABEL: @ColdFunction
5731
; OVERRIDE: ret
5832
; DEFAULT-LABEL: @ColdFunction
5933
; DEFAULT: ret
6034
entry:
61-
call void @extern()
62-
%a1 = load volatile i32, i32* @a
63-
%x1 = add i32 %a1, %a1
64-
%a2 = load volatile i32, i32* @a
65-
%x2 = add i32 %x1, %a2
66-
%a3 = load volatile i32, i32* @a
67-
%x3 = add i32 %x2, %a3
68-
%a4 = load volatile i32, i32* @a
69-
%x4 = add i32 %x3, %a4
70-
%add = add i32 %x4, %a
71-
ret i32 %add
35+
ret i32 %a
7236
}
7337

7438
; This function should be larger than the default cold threshold (225).
75-
define i32 @ColdFunction2(i32 %a) #1 {
39+
define i32 @ColdFunction2(i32 %a) #1 "function-inline-cost"="250" {
7640
; CHECK-LABEL: @ColdFunction2
7741
; CHECK: ret
7842
; OVERRIDE-LABEL: @ColdFunction2
7943
; OVERRIDE: ret
8044
; DEFAULT-LABEL: @ColdFunction2
8145
; DEFAULT: ret
8246
entry:
83-
call void @extern()
84-
%a1 = load volatile i32, i32* @a
85-
%x1 = add i32 %a1, %a1
86-
%a2 = load volatile i32, i32* @a
87-
%x2 = add i32 %x1, %a2
88-
%a3 = load volatile i32, i32* @a
89-
%x3 = add i32 %x2, %a3
90-
%a4 = load volatile i32, i32* @a
91-
%x4 = add i32 %x3, %a4
92-
%a5 = load volatile i32, i32* @a
93-
%x5 = add i32 %x4, %a5
94-
%a6 = load volatile i32, i32* @a
95-
%x6 = add i32 %x5, %a6
96-
%a7 = load volatile i32, i32* @a
97-
%x7 = add i32 %x6, %a7
98-
%a8 = load volatile i32, i32* @a
99-
%x8 = add i32 %x7, %a8
100-
%a9 = load volatile i32, i32* @a
101-
%x9 = add i32 %x8, %a9
102-
%a10 = load volatile i32, i32* @a
103-
%x10 = add i32 %x9, %a10
104-
%a11 = load volatile i32, i32* @a
105-
%x11 = add i32 %x10, %a11
106-
%a12 = load volatile i32, i32* @a
107-
%x12 = add i32 %x11, %a12
108-
109-
%a21 = load volatile i32, i32* @a
110-
%x21 = add i32 %x12, %a21
111-
%a22 = load volatile i32, i32* @a
112-
%x22 = add i32 %x21, %a22
113-
%a23 = load volatile i32, i32* @a
114-
%x23 = add i32 %x22, %a23
115-
%a24 = load volatile i32, i32* @a
116-
%x24 = add i32 %x23, %a24
117-
%a25 = load volatile i32, i32* @a
118-
%x25 = add i32 %x24, %a25
119-
%a26 = load volatile i32, i32* @a
120-
%x26 = add i32 %x25, %a26
121-
%a27 = load volatile i32, i32* @a
122-
%x27 = add i32 %x26, %a27
123-
%a28 = load volatile i32, i32* @a
124-
%x28 = add i32 %x27, %a28
125-
%a29 = load volatile i32, i32* @a
126-
%x29 = add i32 %x28, %a29
127-
%a30 = load volatile i32, i32* @a
128-
%x30 = add i32 %x29, %a30
129-
%a31 = load volatile i32, i32* @a
130-
%x31 = add i32 %x30, %a31
131-
%a32 = load volatile i32, i32* @a
132-
%x32 = add i32 %x31, %a32
133-
134-
%a41 = load volatile i32, i32* @a
135-
%x41 = add i32 %x32, %a41
136-
%a42 = load volatile i32, i32* @a
137-
%x42 = add i32 %x41, %a42
138-
%a43 = load volatile i32, i32* @a
139-
%x43 = add i32 %x42, %a43
140-
%a44 = load volatile i32, i32* @a
141-
%x44 = add i32 %x43, %a44
142-
%a45 = load volatile i32, i32* @a
143-
%x45 = add i32 %x44, %a45
144-
%a46 = load volatile i32, i32* @a
145-
%x46 = add i32 %x45, %a46
146-
%a47 = load volatile i32, i32* @a
147-
%x47 = add i32 %x46, %a47
148-
%a48 = load volatile i32, i32* @a
149-
%x48 = add i32 %x47, %a48
150-
%a49 = load volatile i32, i32* @a
151-
%x49 = add i32 %x48, %a49
152-
%a50 = load volatile i32, i32* @a
153-
%x50 = add i32 %x49, %a50
154-
%a51 = load volatile i32, i32* @a
155-
%x51 = add i32 %x50, %a51
156-
%a52 = load volatile i32, i32* @a
157-
%x52 = add i32 %x51, %a52
158-
159-
%add = add i32 %x52, %a
160-
ret i32 %add
47+
ret i32 %a
16148
}
16249

16350
; Function Attrs: nounwind readnone uwtable

0 commit comments

Comments
 (0)