Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 192fe4c

Browse files
[Inliner] Attribute callsites with inline remarks
Summary: Sometimes reading an output *.ll file it is not easy to understand why some callsites are not inlined. We can read output of inline remarks (option --pass-remarks-missed=inline) and try correlating its messages with the callsites. An easier way proposed by this patch is to add to every callsite processed by Inliner an attribute with the latest message that describes the cause of not inlining this callsite. The attribute is called //inline-remark//. By default this feature is off. It can be switched on by the option //-inline-remark-attribute//. For example in the provided test the result method //@test1// has two callsites //@bar// and inline remarks report different inlining missed reasons: remark: <unknown>:0:0: bar not inlined into test1 because too costly to inline (cost=-5, threshold=-6) remark: <unknown>:0:0: bar not inlined into test1 because it should never be inlined (cost=never): recursive It is not clear which remark correspond to which callsite. With the inline remark attribute enabled we get the reasons attached to their callsites: define void @test1() { call void @bar(i1 true) #0 call void @bar(i1 false) #2 ret void } attributes #0 = { "inline-remark"="(cost=-5, threshold=-6)" } .. attributes #2 = { "inline-remark"="(cost=never): recursive" } Patch by: yrouban (Yevgeny Rouban) Reviewers: xbolva00, tejohnson, apilipenko Reviewed By: xbolva00, tejohnson Subscribers: eraman, llvm-commits Differential Revision: https://reviews.llvm.org/D50435 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@340618 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent ef0538f commit 192fe4c

File tree

2 files changed

+147
-8
lines changed

2 files changed

+147
-8
lines changed

lib/Transforms/IPO/Inliner.cpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ static cl::opt<InlinerFunctionImportStatsOpts> InlinerFunctionImportStats(
113113
"printing of statistics for each inlined function")),
114114
cl::Hidden, cl::desc("Enable inliner stats for imported functions"));
115115

116+
/// Flag to add inline messages as callsite attributes 'inline-remark'.
117+
static cl::opt<bool>
118+
InlineRemarkAttribute("inline-remark-attribute", cl::init(false),
119+
cl::Hidden,
120+
cl::desc("Enable adding inline-remark attribute to"
121+
" callsites processed by inliner but decided"
122+
" to be not inlined"));
123+
116124
LegacyInlinerBase::LegacyInlinerBase(char &ID) : CallGraphSCCPass(ID) {}
117125

118126
LegacyInlinerBase::LegacyInlinerBase(char &ID, bool InsertLifetime)
@@ -264,7 +272,7 @@ static void mergeInlinedArrayAllocas(
264272
/// available from other functions inlined into the caller. If we are able to
265273
/// inline this call site we attempt to reuse already available allocas or add
266274
/// any new allocas to the set if not possible.
267-
static bool InlineCallIfPossible(
275+
static InlineResult InlineCallIfPossible(
268276
CallSite CS, InlineFunctionInfo &IFI,
269277
InlinedArrayAllocasTy &InlinedArrayAllocas, int InlineHistory,
270278
bool InsertLifetime, function_ref<AAResults &(Function &)> &AARGetter,
@@ -390,13 +398,11 @@ RemarkT &operator<<(RemarkT &&R, const InlineCost &IC) {
390398
return R;
391399
}
392400

393-
#ifndef NDEBUG
394401
static std::string inlineCostStr(const InlineCost &IC) {
395402
std::stringstream Remark;
396403
Remark << IC;
397404
return Remark.str();
398405
}
399-
#endif
400406

401407
/// Return the cost only if the inliner should attempt to inline at the given
402408
/// CallSite. If we return the cost, we will emit an optimisation remark later
@@ -502,6 +508,14 @@ static void emit_inlined_into(OptimizationRemarkEmitter &ORE, DebugLoc &DLoc,
502508
});
503509
}
504510

511+
static void setInlineRemark(CallSite &CS, StringRef message) {
512+
if (!InlineRemarkAttribute)
513+
return;
514+
515+
Attribute attr = Attribute::get(CS->getContext(), "inline-remark", message);
516+
CS.addAttribute(AttributeList::FunctionIndex, attr);
517+
}
518+
505519
static bool
506520
inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
507521
std::function<AssumptionCache &(Function &)> GetAssumptionCache,
@@ -551,6 +565,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
551565
if (Callee->isDeclaration()) {
552566
using namespace ore;
553567

568+
setInlineRemark(CS, "unavailable definition");
554569
ORE.emit([&]() {
555570
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
556571
<< NV("Callee", Callee) << " will not be inlined into "
@@ -614,8 +629,10 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
614629
// infinitely inline.
615630
InlineHistoryID = CallSites[CSi].second;
616631
if (InlineHistoryID != -1 &&
617-
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory))
632+
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) {
633+
setInlineRemark(CS, "recursive");
618634
continue;
635+
}
619636
}
620637

621638
// FIXME for new PM: because of the old PM we currently generate ORE and
@@ -626,7 +643,15 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
626643
Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE);
627644
// If the policy determines that we should inline this function,
628645
// delete the call instead.
629-
if (!OIC || !*OIC) {
646+
if (!OIC.hasValue()) {
647+
setInlineRemark(CS, "deferred");
648+
continue;
649+
}
650+
651+
if (!OIC.getValue()) {
652+
// shouldInline() call returned a negative inline cost that explains
653+
// why this callsite should not be inlined.
654+
setInlineRemark(CS, inlineCostStr(*OIC));
630655
continue;
631656
}
632657

@@ -637,6 +662,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
637662
if (IsTriviallyDead) {
638663
LLVM_DEBUG(dbgs() << " -> Deleting dead call: " << *Instr << "\n");
639664
// Update the call graph by deleting the edge from Callee to Caller.
665+
setInlineRemark(CS, "trivially dead");
640666
CG[Caller]->removeCallEdgeFor(CS);
641667
Instr->eraseFromParent();
642668
++NumCallsDeleted;
@@ -652,6 +678,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
652678
CS, InlineInfo, InlinedArrayAllocas, InlineHistoryID,
653679
InsertLifetime, AARGetter, ImportedFunctionsStats);
654680
if (!IR) {
681+
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
655682
ORE.emit([&]() {
656683
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc,
657684
Block)
@@ -894,6 +921,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
894921
Calls.push_back({CS, -1});
895922
else if (!isa<IntrinsicInst>(I)) {
896923
using namespace ore;
924+
setInlineRemark(CS, "unavailable definition");
897925
ORE.emit([&]() {
898926
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
899927
<< NV("Callee", Callee) << " will not be inlined into "
@@ -937,8 +965,10 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
937965
LazyCallGraph::Node &N = *CG.lookup(F);
938966
if (CG.lookupSCC(N) != C)
939967
continue;
940-
if (F.hasFnAttribute(Attribute::OptimizeNone))
968+
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
969+
setInlineRemark(Calls[i].first, "optnone attribute");
941970
continue;
971+
}
942972

943973
LLVM_DEBUG(dbgs() << "Inlining calls in: " << F.getName() << "\n");
944974

@@ -982,8 +1012,10 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
9821012
Function &Callee = *CS.getCalledFunction();
9831013

9841014
if (InlineHistoryID != -1 &&
985-
InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory))
1015+
InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) {
1016+
setInlineRemark(CS, "recursive");
9861017
continue;
1018+
}
9871019

9881020
// Check if this inlining may repeat breaking an SCC apart that has
9891021
// already been split once before. In that case, inlining here may
@@ -995,13 +1027,23 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
9951027
LLVM_DEBUG(dbgs() << "Skipping inlining internal SCC edge from a node "
9961028
"previously split out of this SCC by inlining: "
9971029
<< F.getName() << " -> " << Callee.getName() << "\n");
1030+
setInlineRemark(CS, "recursive SCC split");
9981031
continue;
9991032
}
10001033

10011034
Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE);
10021035
// Check whether we want to inline this callsite.
1003-
if (!OIC || !*OIC)
1036+
if (!OIC.hasValue()) {
1037+
setInlineRemark(CS, "deferred");
10041038
continue;
1039+
}
1040+
1041+
if (!OIC.getValue()) {
1042+
// shouldInline() call returned a negative inline cost that explains
1043+
// why this callsite should not be inlined.
1044+
setInlineRemark(CS, inlineCostStr(*OIC));
1045+
continue;
1046+
}
10051047

10061048
// Setup the data structure used to plumb customization into the
10071049
// `InlineFunction` routine.
@@ -1018,6 +1060,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
10181060

10191061
InlineResult IR = InlineFunction(CS, IFI);
10201062
if (!IR) {
1063+
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
10211064
ORE.emit([&]() {
10221065
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
10231066
<< NV("Callee", &Callee) << " will not be inlined into "
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
; RUN: opt < %s -inline -inline-remark-attribute --inline-threshold=-2 -S | FileCheck %s
2+
3+
; Test that the inliner adds inline remark attributes to non-inlined callsites.
4+
5+
define void @foo() {
6+
call void @bar(i1 true)
7+
ret void
8+
}
9+
10+
define void @bar(i1 %p) {
11+
br i1 %p, label %bb1, label %bb2
12+
13+
bb1:
14+
call void @foo()
15+
ret void
16+
17+
bb2:
18+
call void @bar(i1 true)
19+
ret void
20+
}
21+
22+
;; Test 1 - Add different inline remarks to similar callsites.
23+
define void @test1() {
24+
; CHECK-LABEL: @test1
25+
; CHECK-NEXT: call void @bar(i1 true) [[ATTR1:#[0-9]+]]
26+
; CHECK-NEXT: call void @bar(i1 false) [[ATTR2:#[0-9]+]]
27+
call void @bar(i1 true)
28+
call void @bar(i1 false)
29+
ret void
30+
}
31+
32+
define void @noop() {
33+
ret void
34+
}
35+
36+
;; Test 2 - Printed InlineResult messages are followed by InlineCost.
37+
define void @test2(i8*) {
38+
; CHECK-LABEL: @test2
39+
; CHECK-NEXT: call void @noop() [[ATTR3:#[0-9]+]] [ "CUSTOM_OPERAND_BUNDLE"() ]
40+
; CHECK-NEXT: ret void
41+
call void @noop() ; extepected to be inlined
42+
call void @noop() [ "CUSTOM_OPERAND_BUNDLE"() ] ; cannot be inlined because of unsupported operand bundle
43+
ret void
44+
}
45+
46+
; CHECK: attributes [[ATTR1]] = { "inline-remark"="(cost=-5, threshold=-6)" }
47+
; CHECK: attributes [[ATTR2]] = { "inline-remark"="(cost=never): recursive" }
48+
; CHECK: attributes [[ATTR3]] = { "inline-remark"="unsupported operand bundle; (cost={{.*}}, threshold={{.*}})" }
49+
; RUN: opt < %s -inline -inline-remark-attribute --inline-threshold=-2 -S | FileCheck %s
50+
51+
; Test that the inliner adds inline remark attributes to non-inlined callsites.
52+
53+
define void @foo() {
54+
call void @bar(i1 true)
55+
ret void
56+
}
57+
58+
define void @bar(i1 %p) {
59+
br i1 %p, label %bb1, label %bb2
60+
61+
bb1:
62+
call void @foo()
63+
ret void
64+
65+
bb2:
66+
call void @bar(i1 true)
67+
ret void
68+
}
69+
70+
;; Test 1 - Add different inline remarks to similar callsites.
71+
define void @test1() {
72+
; CHECK-LABEL: @test1
73+
; CHECK-NEXT: call void @bar(i1 true) [[ATTR1:#[0-9]+]]
74+
; CHECK-NEXT: call void @bar(i1 false) [[ATTR2:#[0-9]+]]
75+
call void @bar(i1 true)
76+
call void @bar(i1 false)
77+
ret void
78+
}
79+
80+
define void @noop() {
81+
ret void
82+
}
83+
84+
;; Test 2 - Printed InlineResult messages are followed by InlineCost.
85+
define void @test2(i8*) {
86+
; CHECK-LABEL: @test2
87+
; CHECK-NEXT: call void @noop() [[ATTR3:#[0-9]+]] [ "CUSTOM_OPERAND_BUNDLE"() ]
88+
; CHECK-NEXT: ret void
89+
call void @noop() ; extepected to be inlined
90+
call void @noop() [ "CUSTOM_OPERAND_BUNDLE"() ] ; cannot be inlined because of unsupported operand bundle
91+
ret void
92+
}
93+
94+
; CHECK: attributes [[ATTR1]] = { "inline-remark"="(cost=-5, threshold=-6)" }
95+
; CHECK: attributes [[ATTR2]] = { "inline-remark"="(cost=never): recursive" }
96+
; CHECK: attributes [[ATTR3]] = { "inline-remark"="unsupported operand bundle; (cost={{.*}}, threshold={{.*}})" }

0 commit comments

Comments
 (0)