llvm.org GIT mirror llvm / b4d2672
Emit only A Single Opt Remark When Inlining Summary: This updates the Inliner to only add a single Optimization Remark when Inlining, rather than an Analysis Remark and an Optimization Remark. Fixes https://bugs.llvm.org/show_bug.cgi?id=33786 Reviewers: anemet, davidxl, chandlerc Reviewed By: anemet Subscribers: haicheng, fhahn, mehdi_amini, dblaikie, llvm-commits, eraman Differential Revision: https://reviews.llvm.org/D36054 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311349 91177308-0d34-0410-b5e6-96231b3b80d8 Sam Elliott 3 years ago
12 changed file(s) with 151 addition(s) and 54 deletion(s). Raw diff Collapse all Expand all
104104 return Cost;
105105 }
106106
107 /// \brief Get the threshold against which the cost was computed
108 int getThreshold() const {
109 assert(isVariable() && "Invalid access of InlineCost");
110 return Threshold;
111 }
112
107113 /// \brief Get the cost delta from the threshold for inlining.
108114 /// Only valid if the cost is of the variable kind. Returns a negative
109115 /// value if the cost is too high to inline.
334334 return false;
335335 }
336336
337 /// Return true if the inliner should attempt to inline at the given CallSite.
338 static bool shouldInline(CallSite CS,
339 function_ref GetInlineCost,
340 OptimizationRemarkEmitter &ORE) {
337 /// Return the cost only if the inliner should attempt to inline at the given
338 /// CallSite. If we return the cost, we will emit an optimisation remark later
339 /// using that cost, so we won't do so from this function.
340 static Optional
341 shouldInline(CallSite CS, function_ref GetInlineCost,
342 OptimizationRemarkEmitter &ORE) {
341343 using namespace ore;
342344 InlineCost IC = GetInlineCost(CS);
343345 Instruction *Call = CS.getInstruction();
347349 if (IC.isAlways()) {
348350 DEBUG(dbgs() << " Inlining: cost=always"
349351 << ", Call: " << *CS.getInstruction() << "\n");
350 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AlwaysInline", Call)
351 << NV("Callee", Callee)
352 << " should always be inlined (cost=always)");
353 return true;
352 return IC;
354353 }
355354
356355 if (IC.isNever()) {
360359 << NV("Callee", Callee) << " not inlined into "
361360 << NV("Caller", Caller)
362361 << " because it should never be inlined (cost=never)");
363 return false;
362 return None;
364363 }
365364
366365 if (!IC) {
367366 DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost()
368 << ", thres=" << (IC.getCostDelta() + IC.getCost())
367 << ", thres=" << IC.getThreshold()
369368 << ", Call: " << *CS.getInstruction() << "\n");
370369 ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, "TooCostly", Call)
371370 << NV("Callee", Callee) << " not inlined into "
372371 << NV("Caller", Caller) << " because too costly to inline (cost="
373 << NV("Cost", IC.getCost()) << ", threshold="
374 << NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")");
375 return false;
372 << NV("Cost", IC.getCost())
373 << ", threshold=" << NV("Threshold", IC.getThreshold()) << ")");
374 return None;
376375 }
377376
378377 int TotalSecondaryCost = 0;
385384 << "Not inlining. Cost of inlining " << NV("Callee", Callee)
386385 << " increases the cost of inlining " << NV("Caller", Caller)
387386 << " in other contexts");
388 return false;
387
388 // IC does not bool() to false, so get an InlineCost that will.
389 // This will not be inspected to make an error message.
390 return None;
389391 }
390392
391393 DEBUG(dbgs() << " Inlining: cost=" << IC.getCost()
392 << ", thres=" << (IC.getCostDelta() + IC.getCost())
394 << ", thres=" << IC.getThreshold()
393395 << ", Call: " << *CS.getInstruction() << '\n');
394 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "CanBeInlined", Call)
395 << NV("Callee", Callee) << " can be inlined into "
396 << NV("Caller", Caller) << " with cost=" << NV("Cost", IC.getCost())
397 << " (threshold="
398 << NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")");
399 return true;
396 return IC;
400397 }
401398
402399 /// Return true if the specified inline history ID
544541 // just become a regular analysis dependency.
545542 OptimizationRemarkEmitter ORE(Caller);
546543
544 Optional OIC = shouldInline(CS, GetInlineCost, ORE);
547545 // If the policy determines that we should inline this function,
548546 // delete the call instead.
549 if (!shouldInline(CS, GetInlineCost, ORE))
547 if (!OIC)
550548 continue;
551549
552550 // If this call site is dead and it is to a readonly function, we should
561559 ++NumCallsDeleted;
562560 } else {
563561 // Get DebugLoc to report. CS will be invalid after Inliner.
564 DebugLoc DLoc = Instr->getDebugLoc();
562 DebugLoc DLoc = CS->getDebugLoc();
565563 BasicBlock *Block = CS.getParent();
566564
567565 // Attempt to inline the function.
577575 }
578576 ++NumInlined;
579577
580 // Report the inline decision.
581 ORE.emit(OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block)
582 << NV("Callee", Callee) << " inlined into "
583 << NV("Caller", Caller));
578 if (OIC->isAlways())
579 ORE.emit(OptimizationRemark(DEBUG_TYPE, "AlwaysInline", DLoc, Block)
580 << NV("Callee", Callee) << " inlined into "
581 << NV("Caller", Caller) << " with cost=always");
582 else
583 ORE.emit(OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block)
584 << NV("Callee", Callee) << " inlined into "
585 << NV("Caller", Caller)
586 << " with cost=" << NV("Cost", OIC->getCost())
587 << " (threshold=" << NV("Threshold", OIC->getThreshold())
588 << ")");
584589
585590 // If inlining this function gave us any new call sites, throw them
586591 // onto our worklist to process. They are useful inline candidates.
884889 continue;
885890 }
886891
892 Optional OIC = shouldInline(CS, GetInlineCost, ORE);
887893 // Check whether we want to inline this callsite.
888 if (!shouldInline(CS, GetInlineCost, ORE))
894 if (!OIC)
889895 continue;
890896
891897 // Setup the data structure used to plumb customization into the
895901 &FAM.getResult(*(CS.getCaller())),
896902 &FAM.getResult(Callee));
897903
898 if (!InlineFunction(CS, IFI))
904 // Get DebugLoc to report. CS will be invalid after Inliner.
905 DebugLoc DLoc = CS->getDebugLoc();
906 BasicBlock *Block = CS.getParent();
907
908 using namespace ore;
909 if (!InlineFunction(CS, IFI)) {
910 ORE.emit(
911 OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
912 << NV("Callee", &Callee) << " will not be inlined into "
913 << NV("Caller", &F));
899914 continue;
915 }
900916 DidInline = true;
901917 InlinedCallees.insert(&Callee);
918
919 if (OIC->isAlways())
920 ORE.emit(OptimizationRemark(DEBUG_TYPE, "AlwaysInline", DLoc, Block)
921 << NV("Callee", &Callee) << " inlined into "
922 << NV("Caller", &F) << " with cost=always");
923 else
924 ORE.emit(
925 OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block)
926 << NV("Callee", &Callee) << " inlined into " << NV("Caller", &F)
927 << " with cost=" << NV("Cost", OIC->getCost())
928 << " (threshold=" << NV("Threshold", OIC->getThreshold()) << ")");
902929
903930 // Add any new callsites to defined functions to the worklist.
904931 if (!IFI.InlinedCallSites.empty()) {
1616 ; YAML-NEXT: - Callee: tinkywinky
1717 ; YAML-NEXT: - String: ' inlined into '
1818 ; YAML-NEXT: - Caller: main
19 ; YAML-NEXT: - String: ' with cost='
20 ; YAML-NEXT: - Cost: '-15000'
21 ; YAML-NEXT: - String: ' (threshold='
22 ; YAML-NEXT: - Threshold: '337'
23 ; YAML-NEXT: - String: ')'
1924 ; YAML-NEXT: ...
2025
2126 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1414 ; YAML-NEXT: - Callee: tinkywinky
1515 ; YAML-NEXT: - String: ' inlined into '
1616 ; YAML-NEXT: - Caller: main
17 ; YAML-NEXT: - String: ' with cost='
18 ; YAML-NEXT: - Cost: '-15000'
19 ; YAML-NEXT: - String: ' (threshold='
20 ; YAML-NEXT: - Threshold: '337'
21 ; YAML-NEXT: - String: ')'
1722 ; YAML-NEXT: ...
1823
1924 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1616 ; YAML-NEXT: - Callee: foo
1717 ; YAML-NEXT: - String: ' inlined into '
1818 ; YAML-NEXT: - Caller: main
19 ; YAML-NEXT: - String: ' with cost='
20 ; YAML-NEXT: - Cost: '-15000'
21 ; YAML-NEXT: - String: ' (threshold='
22 ; YAML-NEXT: - Threshold: '337'
23 ; YAML-NEXT: - String: ')'
1924 ; YAML-NEXT: ...
2025
2126 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
5252 ; YAML-NEXT: - Callee: foo
5353 ; YAML-NEXT: - String: ' inlined into '
5454 ; YAML-NEXT: - Caller: main
55 ; YAML-NEXT: - String: ' with cost='
56 ; YAML-NEXT: - Cost: '-15000'
57 ; YAML-NEXT: - String: ' (threshold='
58 ; YAML-NEXT: - Threshold: '337'
59 ; YAML-NEXT: - String: ')'
5560 ; YAML-NEXT: ...
5661
5762 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
2424 ; YAML1-NEXT: - Callee: foo
2525 ; YAML1-NEXT: - String: ' inlined into '
2626 ; YAML1-NEXT: - Caller: main
27 ; YAML1-NEXT: - String: ' with cost='
28 ; YAML1-NEXT: - Cost: '-30'
29 ; YAML1-NEXT: - String: ' (threshold='
30 ; YAML1-NEXT: - Threshold: '337'
31 ; YAML1-NEXT: - String: ')'
2732 ; YAML1-NEXT: ...
2833
2934
3742 ; YAML2-NEXT: - Callee: bar
3843 ; YAML2-NEXT: - String: ' inlined into '
3944 ; YAML2-NEXT: - Caller: foo
45 ; YAML2-NEXT: - String: ' with cost='
46 ; YAML2-NEXT: - Cost: '-30'
47 ; YAML2-NEXT: - String: ' (threshold='
48 ; YAML2-NEXT: - Threshold: '337'
49 ; YAML2-NEXT: - String: ')'
4050 ; YAML2-NEXT: ...
4151
4252
2121 ; YAML1-NEXT: - Callee: foo
2222 ; YAML1-NEXT: - String: ' inlined into '
2323 ; YAML1-NEXT: - Caller: main
24 ; YAML1-NEXT: - String: ' with cost='
25 ; YAML1-NEXT: - Cost: '-30'
26 ; YAML1-NEXT: - String: ' (threshold='
27 ; YAML1-NEXT: - Threshold: '337'
28 ; YAML1-NEXT: - String: ')'
2429 ; YAML1-NEXT: ...
2530
2631
3439 ; YAML2-NEXT: - Callee: bar
3540 ; YAML2-NEXT: - String: ' inlined into '
3641 ; YAML2-NEXT: - Caller: foo
42 ; YAML2-NEXT: - String: ' with cost='
43 ; YAML2-NEXT: - Cost: '-30'
44 ; YAML2-NEXT: - String: ' (threshold='
45 ; YAML2-NEXT: - Threshold: '337'
46 ; YAML2-NEXT: - String: ')'
3747 ; YAML2-NEXT: ...
3848
3949
0 ; RUN: opt < %s -S -inline -pass-remarks-output=%t -pass-remarks=inline \
1 ; RUN: -pass-remarks-missed=inline -pass-remarks-analysis=inline \
2 ; RUN: -pass-remarks-with-hotness 2>&1 | FileCheck %s
3 ; RUN: cat %t | FileCheck -check-prefix=YAML %s
4
5 ; RUN: opt < %s -S -passes=inline -pass-remarks-output=%t -pass-remarks=inline \
16 ; RUN: -pass-remarks-missed=inline -pass-remarks-analysis=inline \
27 ; RUN: -pass-remarks-with-hotness 2>&1 | FileCheck %s
38 ; RUN: cat %t | FileCheck -check-prefix=YAML %s
1116 ; 4 return foo();
1217 ; 5 }
1318
14 ; CHECK: remark: /tmp/s.c:4:10: foo can be inlined into bar with cost={{[0-9\-]+}} (threshold={{[0-9]+}}) (hotness: 30)
15 ; CHECK-NEXT: remark: /tmp/s.c:4:10: foo inlined into bar (hotness: 30)
19 ; CHECK: remark: /tmp/s.c:4:10: foo inlined into bar with cost={{[0-9\-]+}} (threshold={{[0-9]+}}) (hotness: 30)
1620
17 ; YAML: --- !Analysis
18 ; YAML-NEXT: Pass: inline
19 ; YAML-NEXT: Name: CanBeInlined
20 ; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 4, Column: 10 }
21 ; YAML-NEXT: Function: bar
22 ; YAML-NEXT: Hotness: 30
23 ; YAML-NEXT: Args:
24 ; YAML-NEXT: - Callee: foo
25 ; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 1, Column: 0 }
26 ; YAML-NEXT: - String: ' can be inlined into '
27 ; YAML-NEXT: - Caller: bar
28 ; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 3, Column: 0 }
29 ; YAML-NEXT: - String: ' with cost='
30 ; YAML-NEXT: - Cost: '{{[0-9\-]+}}'
31 ; YAML-NEXT: - String: ' (threshold='
32 ; YAML-NEXT: - Threshold: '{{[0-9]+}}'
33 ; YAML-NEXT: - String: ')'
34 ; YAML-NEXT: ...
35 ; YAML-NEXT: --- !Passed
21 ; YAML: --- !Passed
3622 ; YAML-NEXT: Pass: inline
3723 ; YAML-NEXT: Name: Inlined
3824 ; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 4, Column: 10 }
4430 ; YAML-NEXT: - String: ' inlined into '
4531 ; YAML-NEXT: - Caller: bar
4632 ; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 3, Column: 0 }
33 ; YAML-NEXT: - String: ' with cost='
34 ; YAML-NEXT: - Cost: '{{[0-9\-]+}}'
35 ; YAML-NEXT: - String: ' (threshold='
36 ; YAML-NEXT: - Threshold: '{{[0-9]+}}'
37 ; YAML-NEXT: - String: ')'
4738 ; YAML-NEXT: ...
4839
4940 ; ModuleID = '/tmp/s.c'
0 ; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline \
11 ; RUN: -pass-remarks-analysis=inline -pass-remarks-with-hotness -S 2>&1 \
22 ; RUN: | FileCheck %s
3 ; RUN: opt < %s -passes=inline -pass-remarks=inline -pass-remarks-missed=inline \
4 ; RUN: -pass-remarks-analysis=inline -pass-remarks-with-hotness -S 2>&1 \
5 ; RUN: | FileCheck %s
36
4 ; CHECK: foo should always be inlined (cost=always) (hotness: 30)
5 ; CHECK: foo inlined into bar (hotness: 30)
7 ; CHECK: foo inlined into bar with cost=always (hotness: 30)
68 ; CHECK: foz not inlined into bar because it should never be inlined (cost=never) (hotness: 30)
79
810 ; Function Attrs: alwaysinline nounwind uwtable
1111 ; RUN: FileCheck -check-prefix=THRESHOLD %s
1212 ; RUN: test ! -s %t.threshold
1313 ; RUN: opt < %s -S -inline \
14 ; RUN: -pass-remarks-with-hotness -pass-remarks-hotness-threshold 100 \
15 ; RUN: -pass-remarks-output=%t.threshold
16 ; The remarks output file should be empty.
17 ; RUN: test ! -s %t.threshold
18
19 ; NewPM:
20 ; RUN: opt < %s -S -passes=inline -pass-remarks-missed=inline \
21 ; RUN: -pass-remarks-with-hotness -pass-remarks-hotness-threshold 15 \
22 ; RUN: -pass-remarks-output=%t 2>&1 | FileCheck %s -check-prefix=CHECK_NEW
23 ; RUN: test ! -s %t
24 ; RUN: opt < %s -S -passes=inline -pass-remarks-with-hotness -pass-remarks-output=%t
25 ; RUN: test ! -s %t
26 ;
27 ; Verify that remarks that don't meet the hotness threshold are not output.
28 ; RUN: opt < %s -S -passes=inline -pass-remarks-missed=inline \
29 ; RUN: -pass-remarks-with-hotness -pass-remarks-hotness-threshold 100 \
30 ; RUN: -pass-remarks-output=%t.threshold 2>&1 | \
31 ; RUN: FileCheck -check-prefix=THRESHOLD %s
32 ; RUN: test ! -s %t.threshold
33 ; RUN: opt < %s -S -passes=inline \
1434 ; RUN: -pass-remarks-with-hotness -pass-remarks-hotness-threshold 100 \
1535 ; RUN: -pass-remarks-output=%t.threshold
1636 ; The remarks output file should be empty.
5878 ; No remarks should be output, since none meet the threshold.
5979 ; THRESHOLD-NOT: remark
6080
81 ; NewPM does not output this kind of "missed" remark.
82 ; CHECK_NEW-NOT: remark
83
6184 ; ModuleID = '/tmp/s.c'
6285 source_filename = "/tmp/s.c"
6386 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
44 ; RUN: -pass-remarks-analysis=inline -pass-remarks-with-hotness -S 2>&1 | \
55 ; RUN: FileCheck -check-prefix=CHECK -check-prefix=HOTNESS %s
66
7 ; RUN: opt < %s -passes=inline -pass-remarks=inline -pass-remarks-missed=inline \
8 ; RUN: -pass-remarks-analysis=inline -S 2>&1 | \
9 ; RUN: FileCheck -check-prefix=CHECK -check-prefix=NO_HOTNESS %s
10 ; RUN: opt < %s -passes=inline -pass-remarks=inline -pass-remarks-missed=inline \
11 ; RUN: -pass-remarks-analysis=inline -pass-remarks-with-hotness -S 2>&1 | \
12 ; RUN: FileCheck -check-prefix=CHECK -check-prefix=HOTNESS_NEW %s
13
714 ; HOTNESS: fox will not be inlined into bar because its definition is unavailable
815 ; NO_HOTNESS-NOT: fox will not be inlined into bar because its definition is unavailable
9 ; CHECK: foo should always be inlined (cost=always)
10 ; CHECK: foo inlined into bar
16 ; NewPM's inliner does not emit the following remark:
17 ; HOTNESS_NEW-NOT: fox will not be inlined into bar because its definition is unavailable
18 ; CHECK: foo inlined into bar with cost=always
1119 ; CHECK: foz not inlined into bar because it should never be inlined (cost=never)
1220
1321 ; Function Attrs: alwaysinline nounwind uwtable