From cef33141560c42cf81b4284cef25777bb7e2f11e Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Fri, 26 Aug 2016 20:21:05 +0000 Subject: [PATCH] [Inliner] Report when inlining fails because callee's def is unavailable Summary: This is obviously an interesting case because it may motivate code restructuring or LTO. Reporting this requires instantiation of ORE in the loop where the call sites are first gathered. I've checked compile-time overhead *with* -Rpass-with-hotness and the worst slow-down was 6% in mcf and quickly tailing off. As before without -Rpass-with-hotness there is no overhead. Because this could be a pretty noisy diagnostics, it is currently qualified as 'verbose'. As of this patch, 'verbose' diagnostics are only emitted with -Rpass-with-hotness, i.e. when the output is expected to be filtered. Reviewers: eraman, chandlerc, davidxl, hfinkel Subscribers: tejohnson, Prazek, davide, llvm-commits Differential Revision: https://reviews.llvm.org/D23415 llvm-svn: 279860 --- .../llvm/Analysis/OptimizationDiagnosticInfo.h | 51 +++++++++++++++++----- llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp | 23 +++++----- llvm/lib/Transforms/IPO/Inliner.cpp | 13 +++++- .../test/Transforms/Inline/optimization-remarks.ll | 17 +++++++- 4 files changed, 80 insertions(+), 24 deletions(-) diff --git a/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h b/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h index 2d0ff4e..5890ad7 100644 --- a/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h +++ b/llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h @@ -91,21 +91,24 @@ public: /// -Rpass-missed= is given and the name matches the regular expression in /// -Rpass, then the remark will be emitted. \p DLoc is the debug location /// where the diagnostic is generated. \p V is the IR Value that identifies - /// the code region. \p Msg is the message string to use. + /// the code region. \p Msg is the message string to use. If \p IsVerbose is + /// true, the message is considered verbose and will only be emitted when + /// verbose output is turned on. void emitOptimizationRemarkMissed(const char *PassName, const DebugLoc &DLoc, - const Value *V, const Twine &Msg); + const Value *V, const Twine &Msg, + bool IsVerbose = false); /// \brief Same as above but derives the IR Value for the code region and the /// debug location from the Loop parameter \p L. void emitOptimizationRemarkMissed(const char *PassName, Loop *L, - const Twine &Msg); + const Twine &Msg, bool IsVerbose = false); /// \brief Same as above but derives the debug location and the code region /// from the debug location and the basic block of \p Inst, respectively. void emitOptimizationRemarkMissed(const char *PassName, Instruction *Inst, - const Twine &Msg) { + const Twine &Msg, bool IsVerbose = false) { emitOptimizationRemarkMissed(PassName, Inst->getDebugLoc(), - Inst->getParent(), Msg); + Inst->getParent(), Msg, IsVerbose); } /// Emit an optimization analysis remark message. @@ -114,22 +117,46 @@ public: /// -Rpass-analysis= is given and \p PassName matches the regular expression /// in -Rpass, then the remark will be emitted. \p DLoc is the debug location /// where the diagnostic is generated. \p V is the IR Value that identifies - /// the code region. \p Msg is the message string to use. + /// the code region. \p Msg is the message string to use. If \p IsVerbose is + /// true, the message is considered verbose and will only be emitted when + /// verbose output is turned on. void emitOptimizationRemarkAnalysis(const char *PassName, const DebugLoc &DLoc, const Value *V, - const Twine &Msg); + const Twine &Msg, bool IsVerbose = false); /// \brief Same as above but derives the IR Value for the code region and the /// debug location from the Loop parameter \p L. void emitOptimizationRemarkAnalysis(const char *PassName, Loop *L, - const Twine &Msg); + const Twine &Msg, bool IsVerbose = false); /// \brief Same as above but derives the debug location and the code region /// from the debug location and the basic block of \p Inst, respectively. void emitOptimizationRemarkAnalysis(const char *PassName, Instruction *Inst, - const Twine &Msg) { + const Twine &Msg, + bool IsVerbose = false) { emitOptimizationRemarkAnalysis(PassName, Inst->getDebugLoc(), - Inst->getParent(), Msg); + Inst->getParent(), Msg, IsVerbose); + } + + /// \brief This variant allows specifying what should be emitted for missed + /// and analysis remarks in one call. + /// + /// \p PassName is the name of the pass emitting the message. If + /// -Rpass-missed= is given and \p PassName matches the regular expression, \p + /// MsgForMissedRemark is emitted. + /// + /// If -Rpass-analysis= is given and \p PassName matches the regular + /// expression, \p MsgForAnalysisRemark is emitted. + /// + /// The debug location and the code region is derived from \p Inst. If \p + /// IsVerbose is true, the message is considered verbose and will only be + /// emitted when verbose output is turned on. + void emitOptimizationRemarkMissedAndAnalysis( + const char *PassName, Instruction *Inst, const Twine &MsgForMissedRemark, + const Twine &MsgForAnalysisRemark, bool IsVerbose = false) { + emitOptimizationRemarkAnalysis(PassName, Inst, MsgForAnalysisRemark, + IsVerbose); + emitOptimizationRemarkMissed(PassName, Inst, MsgForMissedRemark, IsVerbose); } /// \brief Emit an optimization analysis remark related to floating-point @@ -173,6 +200,10 @@ private: Optional computeHotness(const Value *V); + /// \brief Only allow verbose messages if we know we're filtering by hotness + /// (BFI is only set in this case). + bool shouldEmitVerbose() { return BFI != nullptr; } + OptimizationRemarkEmitter(const OptimizationRemarkEmitter &) = delete; void operator=(const OptimizationRemarkEmitter &) = delete; }; diff --git a/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp b/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp index e150d9d..09a4ce5 100644 --- a/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp +++ b/llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp @@ -68,29 +68,32 @@ void OptimizationRemarkEmitter::emitOptimizationRemark(const char *PassName, void OptimizationRemarkEmitter::emitOptimizationRemarkMissed( const char *PassName, const DebugLoc &DLoc, const Value *V, - const Twine &Msg) { + const Twine &Msg, bool IsVerbose) { LLVMContext &Ctx = F->getContext(); - Ctx.diagnose(DiagnosticInfoOptimizationRemarkMissed(PassName, *F, DLoc, Msg, - computeHotness(V))); + if (!IsVerbose || shouldEmitVerbose()) + Ctx.diagnose(DiagnosticInfoOptimizationRemarkMissed(PassName, *F, DLoc, Msg, + computeHotness(V))); } void OptimizationRemarkEmitter::emitOptimizationRemarkMissed( - const char *PassName, Loop *L, const Twine &Msg) { - emitOptimizationRemarkMissed(PassName, L->getStartLoc(), L->getHeader(), Msg); + const char *PassName, Loop *L, const Twine &Msg, bool IsVerbose) { + emitOptimizationRemarkMissed(PassName, L->getStartLoc(), L->getHeader(), Msg, + IsVerbose); } void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysis( const char *PassName, const DebugLoc &DLoc, const Value *V, - const Twine &Msg) { + const Twine &Msg, bool IsVerbose) { LLVMContext &Ctx = F->getContext(); - Ctx.diagnose(DiagnosticInfoOptimizationRemarkAnalysis(PassName, *F, DLoc, Msg, - computeHotness(V))); + if (!IsVerbose || shouldEmitVerbose()) + Ctx.diagnose(DiagnosticInfoOptimizationRemarkAnalysis( + PassName, *F, DLoc, Msg, computeHotness(V))); } void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysis( - const char *PassName, Loop *L, const Twine &Msg) { + const char *PassName, Loop *L, const Twine &Msg, bool IsVerbose) { emitOptimizationRemarkAnalysis(PassName, L->getStartLoc(), L->getHeader(), - Msg); + Msg, IsVerbose); } void OptimizationRemarkEmitter::emitOptimizationRemarkAnalysisFPCommute( diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp index 86781b3..befadb6 100644 --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -452,9 +452,10 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, for (CallGraphNode *Node : SCC) { Function *F = Node->getFunction(); - if (!F) + if (!F || F->isDeclaration()) continue; + OptimizationRemarkEmitter ORE(F); for (BasicBlock &BB : *F) for (Instruction &I : BB) { CallSite CS(cast(&I)); @@ -467,8 +468,16 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, // it. If it is an indirect call, inlining may resolve it to be a // direct call, so we keep it. if (Function *Callee = CS.getCalledFunction()) - if (Callee->isDeclaration()) + if (Callee->isDeclaration()) { + ORE.emitOptimizationRemarkMissedAndAnalysis( + DEBUG_TYPE, &I, + Twine(Callee->getName()) + " will not be inlined into " + + CS.getCaller()->getName(), + Twine("definition of ") + Callee->getName() + + " is not available", + /*Verbose=*/true); continue; + } CallSites.push_back(std::make_pair(CS, -1)); } diff --git a/llvm/test/Transforms/Inline/optimization-remarks.ll b/llvm/test/Transforms/Inline/optimization-remarks.ll index 8a3e4d1..d8be0c0 100644 --- a/llvm/test/Transforms/Inline/optimization-remarks.ll +++ b/llvm/test/Transforms/Inline/optimization-remarks.ll @@ -1,5 +1,14 @@ -; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline -pass-remarks-analysis=inline -S 2>&1 | FileCheck %s +; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline \ +; RUN: -pass-remarks-analysis=inline -S 2>&1 | \ +; RUN: FileCheck -check-prefix=CHECK -check-prefix=NO_HOTNESS %s +; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline \ +; RUN: -pass-remarks-analysis=inline -pass-remarks-with-hotness -S 2>&1 | \ +; RUN: FileCheck -check-prefix=CHECK -check-prefix=HOTNESS %s +; HOTNESS: definition of fox is not available +; HOTNESS: fox will not be inlined into bar +; NO_HOTNESS-NOT: definition of fox is not available +; NO_HOTNESS-NOT: fox will not be inlined into bar ; CHECK: foo should always be inlined (cost=always) ; CHECK: foo inlined into bar ; CHECK: foz should never be inlined (cost=never) @@ -32,6 +41,8 @@ entry: ret float %conv } +declare i32 @fox() + ; Function Attrs: nounwind uwtable define i32 @bar(i32 %j) #2 { entry: @@ -48,7 +59,9 @@ entry: %call2 = call float @foz(i32 %sub1, i32 %3) %mul = fmul float %conv, %call2 %conv3 = fptosi float %mul to i32 - ret i32 %conv3 + %call3 = call i32 @fox() + %add = add i32 %conv3, %call + ret i32 %add } attributes #0 = { alwaysinline nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -- 2.7.4