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

Commit 6f1d64e

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@340834 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent fd5fafb commit 6f1d64e

File tree

2 files changed

+99
-10
lines changed

2 files changed

+99
-10
lines changed

lib/Transforms/IPO/Inliner.cpp

Lines changed: 51 additions & 10 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,
@@ -367,12 +375,10 @@ shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC,
367375
return false;
368376
}
369377

370-
#ifndef NDEBUG
371378
static std::basic_ostream<char> &operator<<(std::basic_ostream<char> &R,
372379
const ore::NV &Arg) {
373380
return R << Arg.Val;
374381
}
375-
#endif
376382

377383
template <class RemarkT>
378384
RemarkT &operator<<(RemarkT &&R, const InlineCost &IC) {
@@ -390,13 +396,11 @@ RemarkT &operator<<(RemarkT &&R, const InlineCost &IC) {
390396
return R;
391397
}
392398

393-
#ifndef NDEBUG
394399
static std::string inlineCostStr(const InlineCost &IC) {
395400
std::stringstream Remark;
396401
Remark << IC;
397402
return Remark.str();
398403
}
399-
#endif
400404

401405
/// Return the cost only if the inliner should attempt to inline at the given
402406
/// CallSite. If we return the cost, we will emit an optimisation remark later
@@ -502,6 +506,14 @@ static void emit_inlined_into(OptimizationRemarkEmitter &ORE, DebugLoc &DLoc,
502506
});
503507
}
504508

509+
static void setInlineRemark(CallSite &CS, StringRef message) {
510+
if (!InlineRemarkAttribute)
511+
return;
512+
513+
Attribute attr = Attribute::get(CS->getContext(), "inline-remark", message);
514+
CS.addAttribute(AttributeList::FunctionIndex, attr);
515+
}
516+
505517
static bool
506518
inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
507519
std::function<AssumptionCache &(Function &)> GetAssumptionCache,
@@ -551,6 +563,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
551563
if (Callee->isDeclaration()) {
552564
using namespace ore;
553565

566+
setInlineRemark(CS, "unavailable definition");
554567
ORE.emit([&]() {
555568
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
556569
<< NV("Callee", Callee) << " will not be inlined into "
@@ -614,8 +627,10 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
614627
// infinitely inline.
615628
InlineHistoryID = CallSites[CSi].second;
616629
if (InlineHistoryID != -1 &&
617-
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory))
630+
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) {
631+
setInlineRemark(CS, "recursive");
618632
continue;
633+
}
619634
}
620635

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

@@ -637,6 +660,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
637660
if (IsTriviallyDead) {
638661
LLVM_DEBUG(dbgs() << " -> Deleting dead call: " << *Instr << "\n");
639662
// Update the call graph by deleting the edge from Callee to Caller.
663+
setInlineRemark(CS, "trivially dead");
640664
CG[Caller]->removeCallEdgeFor(CS);
641665
Instr->eraseFromParent();
642666
++NumCallsDeleted;
@@ -652,6 +676,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
652676
CS, InlineInfo, InlinedArrayAllocas, InlineHistoryID,
653677
InsertLifetime, AARGetter, ImportedFunctionsStats);
654678
if (!IR) {
679+
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
655680
ORE.emit([&]() {
656681
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc,
657682
Block)
@@ -894,6 +919,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
894919
Calls.push_back({CS, -1});
895920
else if (!isa<IntrinsicInst>(I)) {
896921
using namespace ore;
922+
setInlineRemark(CS, "unavailable definition");
897923
ORE.emit([&]() {
898924
return OptimizationRemarkMissed(DEBUG_TYPE, "NoDefinition", &I)
899925
<< NV("Callee", Callee) << " will not be inlined into "
@@ -937,8 +963,10 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
937963
LazyCallGraph::Node &N = *CG.lookup(F);
938964
if (CG.lookupSCC(N) != C)
939965
continue;
940-
if (F.hasFnAttribute(Attribute::OptimizeNone))
966+
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
967+
setInlineRemark(Calls[i].first, "optnone attribute");
941968
continue;
969+
}
942970

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

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

9841012
if (InlineHistoryID != -1 &&
985-
InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory))
1013+
InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) {
1014+
setInlineRemark(CS, "recursive");
9861015
continue;
1016+
}
9871017

9881018
// Check if this inlining may repeat breaking an SCC apart that has
9891019
// already been split once before. In that case, inlining here may
@@ -995,13 +1025,23 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
9951025
LLVM_DEBUG(dbgs() << "Skipping inlining internal SCC edge from a node "
9961026
"previously split out of this SCC by inlining: "
9971027
<< F.getName() << " -> " << Callee.getName() << "\n");
1028+
setInlineRemark(CS, "recursive SCC split");
9981029
continue;
9991030
}
10001031

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

10061046
// Setup the data structure used to plumb customization into the
10071047
// `InlineFunction` routine.
@@ -1018,6 +1058,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
10181058

10191059
InlineResult IR = InlineFunction(CS, IFI);
10201060
if (!IR) {
1061+
setInlineRemark(CS, std::string(IR) + "; " + inlineCostStr(*OIC));
10211062
ORE.emit([&]() {
10221063
return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
10231064
<< NV("Callee", &Callee) << " will not be inlined into "
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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={{.*}})" }

0 commit comments

Comments
 (0)