diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index 49eb1b0c144..589291a1280 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -26,6 +26,7 @@ class Function; class Instruction; class Twine; class Value; +class DebugLoc; /// \brief Defines the different supported severity of a diagnostic. enum DiagnosticSeverity { @@ -44,6 +45,7 @@ enum DiagnosticKind { DK_StackSize, DK_DebugMetadataVersion, DK_SampleProfile, + DK_OptimizationRemark, DK_FirstPluginKind }; @@ -235,6 +237,63 @@ private: const Twine &Msg; }; +/// Diagnostic information for optimization remarks. +class DiagnosticInfoOptimizationRemark : public DiagnosticInfo { +public: + /// \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 Fn is the function where the diagnostic + /// is being emitted. \p DLoc is the location information to use in the + /// diagnostic. If line table information is available, the diagnostic + /// will include the source code location. \p Msg is the message to show. + /// Note that this class does not copy this message, so this reference + /// must be valid for the whole life time of the diagnostic. + DiagnosticInfoOptimizationRemark(const char *PassName, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg) + : DiagnosticInfo(DK_OptimizationRemark, DS_Remark), PassName(PassName), + Fn(Fn), DLoc(DLoc), Msg(Msg) {} + + /// \see DiagnosticInfo::print. + void print(DiagnosticPrinter &DP) const override; + + /// Hand rolled RTTI. + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_OptimizationRemark; + } + + /// Return true if location information is available for this diagnostic. + bool isLocationAvailable() const; + + /// Return a string with the location information for this diagnostic + /// in the format "file:line:col". If location information is not available, + /// it returns ":0:0". + const StringRef getLocationStr() const; + + /// Return location information for this diagnostic in three parts: + /// the source file name, line number and column. + void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const; + + const char *getPassName() const { return PassName; } + const Function &getFunction() const { return Fn; } + const DebugLoc &getDebugLoc() const { return DLoc; } + const Twine &getMsg() const { return Msg; } + +private: + /// Name of the pass that triggers this report. If this matches the + /// regular expression given in -Rpass=regexp, then the remark will + /// be emitted. + const char *PassName; + + /// Function where this diagnostic is triggered. + const Function &Fn; + + /// Debug location where this diagnostic is triggered. + const DebugLoc &DLoc; + + /// Message to report. + const Twine &Msg; +}; + } // End namespace llvm #endif diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index ae4859aaccf..5c698f81de4 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -29,6 +29,8 @@ class Module; class SMDiagnostic; class DiagnosticInfo; template class SmallVectorImpl; +class Function; +class DebugLoc; /// This is an important class for using LLVM in a threaded context. It /// (opaquely) owns and manages the core "global" data of LLVM's core @@ -125,6 +127,15 @@ public: void emitError(const Instruction *I, const Twine &ErrorStr); void emitError(const Twine &ErrorStr); + /// emitOptimizationRemark - Emit an optimization remark message. \p PassName + /// is the name of the pass emitting the message. If -Rpass= is given + /// and \p PassName matches the regular expression in -Rpass, then the + /// remark will be emitted. \p Fn is the function triggering the remark, + /// \p DLoc is the debug location where the diagnostic is generated. + /// \p Msg is the message string to use. + void emitOptimizationRemark(const char *PassName, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg); + private: LLVMContext(LLVMContext&) LLVM_DELETED_FUNCTION; void operator=(LLVMContext&) LLVM_DELETED_FUNCTION; diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index d59d4cf0b50..fe289af1113 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -14,11 +14,13 @@ #include "llvm/ADT/Twine.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Atomic.h" #include @@ -64,3 +66,29 @@ void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const { DP << getFileName() << ": "; DP << getMsg(); } + +bool DiagnosticInfoOptimizationRemark::isLocationAvailable() const { + return getFunction().getParent()->getNamedMetadata("llvm.dbg.cu") != 0; +} + +void DiagnosticInfoOptimizationRemark::getLocation(StringRef *Filename, + unsigned *Line, + unsigned *Column) const { + DILocation DIL(getDebugLoc().getAsMDNode(getFunction().getContext())); + *Filename = DIL.getFilename(); + *Line = DIL.getLineNumber(); + *Column = DIL.getColumnNumber(); +} + +const StringRef DiagnosticInfoOptimizationRemark::getLocationStr() const { + StringRef Filename(""); + unsigned Line = 0; + unsigned Column = 0; + if (isLocationAvailable()) + getLocation(&Filename, &Line, &Column); + return Twine(Filename + ":" + Twine(Line) + ":" + Twine(Column)).str(); +} + +void DiagnosticInfoOptimizationRemark::print(DiagnosticPrinter &DP) const { + DP << getLocationStr() << ": " << getMsg(); +} diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index 1bfc5152773..3f05561a2cb 100644 --- a/lib/IR/LLVMContext.cpp +++ b/lib/IR/LLVMContext.cpp @@ -15,6 +15,7 @@ #include "llvm/IR/LLVMContext.h" #include "LLVMContextImpl.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugLoc.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Instruction.h" @@ -155,6 +156,13 @@ void LLVMContext::emitError(unsigned LocCookie, const Twine &ErrorStr) { diagnose(DiagnosticInfoInlineAsm(LocCookie, ErrorStr)); } +void LLVMContext::emitOptimizationRemark(const char *PassName, + const Function &Fn, + const DebugLoc &DLoc, + const Twine &Msg) { + diagnose(DiagnosticInfoOptimizationRemark(PassName, Fn, DLoc, Msg)); +} + //===----------------------------------------------------------------------===// // Metadata Kind Uniquing //===----------------------------------------------------------------------===// diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index e97fb834f8d..17be3b2b447 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/InlineCost.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" @@ -522,7 +523,12 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) { InlineHistoryID, InsertLifetime, DL)) continue; ++NumInlined; - + + // Report the inline decision. + Caller->getContext().emitOptimizationRemark( + DEBUG_TYPE, *Caller, CS.getInstruction()->getDebugLoc(), + Twine(Callee->getName() + " inlined into " + Caller->getName())); + // If inlining this function gave us any new call sites, throw them // onto our worklist to process. They are useful inline candidates. if (!InlineInfo.InlinedCalls.empty()) {