From 695f82f13af34c2eb672aeb17a177ce855b0074b Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Tue, 27 Sep 2016 23:47:03 +0000 Subject: [PATCH] [Inliner] Port all opt remarks to new streaming API git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282559 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/DiagnosticInfo.h | 23 ++++- lib/Analysis/OptimizationDiagnosticInfo.cpp | 8 +- lib/IR/DiagnosticInfo.cpp | 23 +++++ lib/Transforms/IPO/Inliner.cpp | 69 +++++++-------- .../optimization-remarks-passed-yaml.ll | 83 +++++++++++++++++++ 5 files changed, 170 insertions(+), 36 deletions(-) create mode 100644 test/Transforms/Inline/optimization-remarks-passed-yaml.ll diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index 9e09b0b56f8..ac4c4bdce2a 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -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; } diff --git a/lib/Analysis/OptimizationDiagnosticInfo.cpp b/lib/Analysis/OptimizationDiagnosticInfo.cpp index 5c0a81f60e5..181e375ad65 100644 --- a/lib/Analysis/OptimizationDiagnosticInfo.cpp +++ b/lib/Analysis/OptimizationDiagnosticInfo.cpp @@ -59,7 +59,13 @@ template <> struct MappingTraits { 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"); diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index 181958a1f73..301a1d53fad 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -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(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(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 && diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index 3ffb7544310..7aa1e187d31 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -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 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. diff --git a/test/Transforms/Inline/optimization-remarks-passed-yaml.ll b/test/Transforms/Inline/optimization-remarks-passed-yaml.ll new file mode 100644 index 00000000000..dff73430b12 --- /dev/null +++ b/test/Transforms/Inline/optimization-remarks-passed-yaml.ll @@ -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}