[Inliner] Port all opt remarks to new streaming API

llvm-svn: 282559
This commit is contained in:
Adam Nemet 2016-09-27 23:47:03 +00:00
parent 0427909434
commit c507ac96f5
5 changed files with 170 additions and 36 deletions

View File

@ -497,6 +497,14 @@ public:
: DiagnosticInfoOptimizationBase(DK_OptimizationRemark, DS_Remark,
PassName, Fn, DLoc, Msg, Hotness) {}
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass=, then the diagnostic will
/// be emitted. \p RemarkName is a textual identifier for the remark. \p
/// DLoc is the debug location and \p CodeRegion is the region that the
/// optimization operates on (currently on block is supported).
OptimizationRemark(const char *PassName, StringRef RemarkName,
const DebugLoc &DLoc, Value *CodeRegion);
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_OptimizationRemark;
}
@ -525,7 +533,13 @@ public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-missed=, then the
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
/// remark. \p Inst is the instruction that the optimization operates on.
/// remark. \p DLoc is the debug location and \p CodeRegion is the region
/// that the optimization operates on (currently on block is supported).
OptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
const DebugLoc &DLoc, Value *CodeRegion);
/// \brief Same as above but \p Inst is used to derive code region and debug
/// location.
OptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
Instruction *Inst);
@ -554,6 +568,13 @@ public:
: DiagnosticInfoOptimizationBase(DK_OptimizationRemarkAnalysis, DS_Remark,
PassName, Fn, DLoc, Msg, Hotness) {}
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-analysis=, then the
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
/// remark. \p Inst is the instruction that the optimization operates on.
OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
Instruction *Inst);
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_OptimizationRemarkAnalysis;
}

View File

@ -59,7 +59,13 @@ template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> {
static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag) {
assert(io.outputting() && "input not yet implemented");
if (io.mapTag("!Missed", OptDiag->getKind() == DK_OptimizationRemarkMissed))
if (io.mapTag("!Passed", OptDiag->getKind() == DK_OptimizationRemark))
;
else if (io.mapTag("!Missed",
OptDiag->getKind() == DK_OptimizationRemarkMissed))
;
else if (io.mapTag("!Analysis",
OptDiag->getKind() == DK_OptimizationRemarkAnalysis))
;
else
llvm_unreachable("todo");

View File

@ -180,11 +180,26 @@ void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const {
DP << " (hotness: " << *Hotness << ")";
}
OptimizationRemark::OptimizationRemark(const char *PassName,
StringRef RemarkName,
const DebugLoc &DLoc, Value *CodeRegion)
: DiagnosticInfoOptimizationBase(
DK_OptimizationRemark, DS_Remark, PassName, RemarkName,
*cast<BasicBlock>(CodeRegion)->getParent(), DLoc, CodeRegion) {}
bool OptimizationRemark::isEnabled() const {
return PassRemarksOptLoc.Pattern &&
PassRemarksOptLoc.Pattern->match(getPassName());
}
OptimizationRemarkMissed::OptimizationRemarkMissed(const char *PassName,
StringRef RemarkName,
const DebugLoc &DLoc,
Value *CodeRegion)
: DiagnosticInfoOptimizationBase(
DK_OptimizationRemarkMissed, DS_Remark, PassName, RemarkName,
*cast<BasicBlock>(CodeRegion)->getParent(), DLoc, CodeRegion) {}
OptimizationRemarkMissed::OptimizationRemarkMissed(const char *PassName,
StringRef RemarkName,
Instruction *Inst)
@ -198,6 +213,14 @@ bool OptimizationRemarkMissed::isEnabled() const {
PassRemarksMissedOptLoc.Pattern->match(getPassName());
}
OptimizationRemarkAnalysis::OptimizationRemarkAnalysis(const char *PassName,
StringRef RemarkName,
Instruction *Inst)
: DiagnosticInfoOptimizationBase(DK_OptimizationRemarkAnalysis, DS_Remark,
PassName, RemarkName,
*Inst->getParent()->getParent(),
Inst->getDebugLoc(), Inst->getParent()) {}
bool OptimizationRemarkAnalysis::isEnabled() const {
return shouldAlwaysPrint() ||
(PassRemarksAnalysisOptLoc.Pattern &&

View File

@ -255,11 +255,6 @@ static bool InlineCallIfPossible(
return true;
}
static void emitAnalysis(CallSite CS, OptimizationRemarkEmitter &ORE,
const Twine &Msg) {
ORE.emitOptimizationRemarkAnalysis(DEBUG_TYPE, CS.getInstruction(), Msg);
}
/// Return true if inlining of CS can block the caller from being
/// inlined which is proved to be more beneficial. \p IC is the
/// estimated inline cost associated with callsite \p CS.
@ -341,21 +336,26 @@ shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC,
static bool shouldInline(CallSite CS,
function_ref<InlineCost(CallSite CS)> GetInlineCost,
OptimizationRemarkEmitter &ORE) {
using namespace ore;
InlineCost IC = GetInlineCost(CS);
Instruction *Call = CS.getInstruction();
Function *Callee = CS.getCalledFunction();
if (IC.isAlways()) {
DEBUG(dbgs() << " Inlining: cost=always"
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, ORE, Twine(CS.getCalledFunction()->getName()) +
" should always be inlined (cost=always)");
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AlwaysInline", Call)
<< NV("Callee", Callee)
<< " should always be inlined (cost=always)");
return true;
}
if (IC.isNever()) {
DEBUG(dbgs() << " NOT Inlining: cost=never"
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, ORE, Twine(CS.getCalledFunction()->getName() +
" should never be inlined (cost=never)"));
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "NeverInline", Call)
<< NV("Callee", Callee)
<< " should never be inlined (cost=never)");
return false;
}
@ -364,10 +364,10 @@ static bool shouldInline(CallSite CS,
DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, ORE, Twine(CS.getCalledFunction()->getName() +
" too costly to inline (cost=") +
Twine(IC.getCost()) + ", threshold=" +
Twine(IC.getCostDelta() + IC.getCost()) + ")");
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "TooCostly", Call)
<< NV("Callee", Callee) << " too costly to inline (cost="
<< NV("Cost", IC.getCost()) << ", threshold="
<< NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")");
return false;
}
@ -376,22 +376,22 @@ static bool shouldInline(CallSite CS,
DEBUG(dbgs() << " NOT Inlining: " << *CS.getInstruction()
<< " Cost = " << IC.getCost()
<< ", outer Cost = " << TotalSecondaryCost << '\n');
emitAnalysis(CS, ORE,
Twine("Not inlining. Cost of inlining " +
CS.getCalledFunction()->getName() +
" increases the cost of inlining " +
CS.getCaller()->getName() + " in other contexts"));
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE,
"IncreaseCostInOtherContexts", Call)
<< "Not inlining. Cost of inlining " << NV("Callee", Callee)
<< " increases the cost of inlining " << NV("Caller", Caller)
<< " in other contexts");
return false;
}
DEBUG(dbgs() << " Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << '\n');
emitAnalysis(CS, ORE, CS.getCalledFunction()->getName() +
Twine(" can be inlined into ") +
CS.getCaller()->getName() + " with cost=" +
Twine(IC.getCost()) + " (threshold=" +
Twine(IC.getCostDelta() + IC.getCost()) + ")");
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "CanBeInlined", Call)
<< NV("Callee", Callee) << " can be inlined into "
<< NV("Caller", Caller) << " with cost=" << NV("Cost", IC.getCost())
<< " (threshold="
<< NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")");
return true;
}
@ -550,11 +550,12 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
// If the policy determines that we should inline this function,
// try to do so.
using namespace ore;
if (!shouldInline(CS, GetInlineCost, ORE)) {
ORE.emitOptimizationRemarkMissed(DEBUG_TYPE, DLoc, Block,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
ORE.emit(
OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", Caller));
continue;
}
@ -562,18 +563,18 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,
InlineHistoryID, InsertLifetime, AARGetter,
ImportedFunctionsStats)) {
ORE.emitOptimizationRemarkMissed(DEBUG_TYPE, DLoc, Block,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
ORE.emit(
OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
<< NV("Callee", Callee) << " will not be inlined into "
<< NV("Caller", Caller));
continue;
}
++NumInlined;
// Report the inline decision.
ORE.emitOptimizationRemark(
DEBUG_TYPE, DLoc, Block,
Twine(Callee->getName() + " inlined into " + Caller->getName()));
ORE.emit(OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block)
<< NV("Callee", Callee) << " inlined into "
<< NV("Caller", Caller));
// If inlining this function gave us any new call sites, throw them
// onto our worklist to process. They are useful inline candidates.

View File

@ -0,0 +1,83 @@
; RUN: opt < %s -S -inline -pass-remarks-output=%t -pass-remarks=inline \
; RUN: -pass-remarks-missed=inline -pass-remarks-analysis=inline \
; RUN: -pass-remarks-with-hotness 2>&1 | FileCheck %s
; RUN: cat %t | FileCheck -check-prefix=YAML %s
; Check the YAML file for inliner-generated passed and analysis remarks. This
; is the input:
; 1 int foo() { return 1; }
; 2
; 3 int bar() {
; 4 return foo();
; 5 }
; CHECK: remark: /tmp/s.c:4:10: foo can be inlined into bar with cost={{[0-9]+}} (threshold={{[0-9]+}}) (hotness: 30)
; CHECK-NEXT: remark: /tmp/s.c:4:10: foo inlined into bar (hotness: 30)
; YAML: --- !Analysis
; YAML-NEXT: Pass: inline
; YAML-NEXT: Name: CanBeInlined
; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 4, Column: 10 }
; YAML-NEXT: Function: bar
; YAML-NEXT: Hotness: 30
; YAML-NEXT: Args:
; YAML-NEXT: - Callee: foo
; YAML-NEXT: - String: can be inlined into
; YAML-NEXT: - Caller: bar
; YAML-NEXT: - String: with cost=
; YAML-NEXT: - Cost: {{[0-9]+}}
; YAML-NEXT: - String: (threshold=
; YAML-NEXT: - Threshold: {{[0-9]+}}
; YAML-NEXT: - String: )
; YAML-NEXT: ...
; YAML-NEXT: --- !Passed
; YAML-NEXT: Pass: inline
; YAML-NEXT: Name: Inlined
; YAML-NEXT: DebugLoc: { File: /tmp/s.c, Line: 4, Column: 10 }
; YAML-NEXT: Function: bar
; YAML-NEXT: Hotness: 30
; YAML-NEXT: Args:
; YAML-NEXT: - Callee: foo
; YAML-NEXT: - String: inlined into
; YAML-NEXT: - Caller: bar
; YAML-NEXT: ...
; ModuleID = '/tmp/s.c'
source_filename = "/tmp/s.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
; Function Attrs: nounwind ssp uwtable
define i32 @foo() #0 !dbg !7 {
entry:
ret i32 1, !dbg !9
}
; Function Attrs: nounwind ssp uwtable
define i32 @bar() #0 !dbg !10 !prof !13 {
entry:
%call = call i32 @foo(), !dbg !11
ret i32 %call, !dbg !12
}
attributes #0 = { nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
!1 = !DIFile(filename: "/tmp/s.c", directory: "/tmp")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"PIC Level", i32 2}
!6 = !{!"clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)"}
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, variables: !2)
!8 = !DISubroutineType(types: !2)
!9 = !DILocation(line: 1, column: 13, scope: !7)
!10 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !2)
!11 = !DILocation(line: 4, column: 10, scope: !10)
!12 = !DILocation(line: 4, column: 3, scope: !10)
!13 = !{!"function_entry_count", i64 30}