summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/IR/DiagnosticInfo.h151
-rw-r--r--include/llvm/IR/LLVMContext.h9
-rw-r--r--lib/IR/DiagnosticInfo.cpp50
-rw-r--r--lib/IR/LLVMContext.cpp35
-rw-r--r--lib/IR/LLVMContextImpl.cpp68
-rw-r--r--lib/IR/LLVMContextImpl.h10
-rw-r--r--lib/Transforms/IPO/Inliner.cpp51
-rw-r--r--lib/Transforms/Scalar/TailRecursionElimination.cpp16
-rw-r--r--lib/Transforms/Utils/LoopUnroll.cpp9
-rw-r--r--lib/Transforms/Utils/SimplifyLibCalls.cpp7
-rw-r--r--lib/Transforms/Vectorize/LoopVectorize.cpp13
-rw-r--r--test/Transforms/Inline/optimization-remarks.ll60
12 files changed, 387 insertions, 92 deletions
diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h
index 604de1fed9..8e334c996d 100644
--- a/include/llvm/IR/DiagnosticInfo.h
+++ b/include/llvm/IR/DiagnosticInfo.h
@@ -26,6 +26,7 @@ namespace llvm {
class DiagnosticPrinter;
class Function;
class Instruction;
+class LLVMContextImpl;
class Twine;
class Value;
class DebugLoc;
@@ -48,6 +49,8 @@ enum DiagnosticKind {
DK_DebugMetadataVersion,
DK_SampleProfile,
DK_OptimizationRemark,
+ DK_OptimizationRemarkMissed,
+ DK_OptimizationRemarkAnalysis,
DK_FirstPluginKind
};
@@ -239,21 +242,21 @@ private:
const Twine &Msg;
};
-/// Diagnostic information for optimization remarks.
-class DiagnosticInfoOptimizationRemark : public DiagnosticInfo {
+/// Common features for diagnostics dealing with optimization remarks.
+class DiagnosticInfoOptimizationRemarkBase : 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) {}
+ /// \p PassName is the name of the pass emitting this diagnostic.
+ /// \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.
+ DiagnosticInfoOptimizationRemarkBase(enum DiagnosticKind Kind,
+ const char *PassName, const Function &Fn,
+ const DebugLoc &DLoc, const Twine &Msg)
+ : DiagnosticInfo(Kind, DS_Remark), PassName(PassName), Fn(Fn), DLoc(DLoc),
+ Msg(Msg) {}
/// \see DiagnosticInfo::print.
void print(DiagnosticPrinter &DP) const override;
@@ -263,6 +266,16 @@ public:
return DI->getKind() == DK_OptimizationRemark;
}
+ /// Return true if this optimization remark is enabled by one of
+ /// of the LLVM command line flags (-pass-remarks, -pass-remarks-missed,
+ /// or -pass-remarks-analysis). Note that this only handles the LLVM
+ /// flags. We cannot access Clang flags from here (they are handled
+ /// in BackendConsumer::OptimizationRemarkHandler).
+ ///
+ /// \p pImpl points to the current LLVM context. It is needed to query the
+ /// value of the command line flag associated with this remark.
+ virtual bool isEnabled(LLVMContextImpl *pImpl) const = 0;
+
/// Return true if location information is available for this diagnostic.
bool isLocationAvailable() const;
@@ -296,9 +309,119 @@ private:
const Twine &Msg;
};
+/// Diagnostic information for applied optimization remarks.
+class DiagnosticInfoOptimizationRemark
+ : public DiagnosticInfoOptimizationRemarkBase {
+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)
+ : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemark, PassName,
+ Fn, DLoc, Msg) {}
+
+ /// Hand rolled RTTI
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_OptimizationRemark;
+ }
+
+ /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
+ virtual bool isEnabled(LLVMContextImpl *pImpl) const override;
+};
+
+/// Diagnostic information for missed-optimization remarks.
+class DiagnosticInfoOptimizationRemarkMissed
+ : public DiagnosticInfoOptimizationRemarkBase {
+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 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.
+ DiagnosticInfoOptimizationRemarkMissed(const char *PassName,
+ const Function &Fn,
+ const DebugLoc &DLoc, const Twine &Msg)
+ : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkMissed,
+ PassName, Fn, DLoc, Msg) {}
+
+ /// Hand rolled RTTI
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_OptimizationRemarkMissed;
+ }
+
+ /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
+ virtual bool isEnabled(LLVMContextImpl *pImpl) const override;
+};
+
+/// Diagnostic information for optimization analysis remarks.
+class DiagnosticInfoOptimizationRemarkAnalysis
+ : public DiagnosticInfoOptimizationRemarkBase {
+public:
+ /// \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 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.
+ DiagnosticInfoOptimizationRemarkAnalysis(const char *PassName,
+ const Function &Fn,
+ const DebugLoc &DLoc,
+ const Twine &Msg)
+ : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkAnalysis,
+ PassName, Fn, DLoc, Msg) {}
+
+ /// Hand rolled RTTI
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_OptimizationRemarkAnalysis;
+ }
+
+ /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
+ virtual bool isEnabled(LLVMContextImpl *pImpl) const override;
+};
+
// Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef)
+/// Emit an optimization-applied 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(LLVMContext &Ctx, const char *PassName,
+ const Function &Fn, const DebugLoc &DLoc,
+ const Twine &Msg);
+
+/// Emit an optimization-missed message. \p PassName is the name of the
+/// pass emitting the message. If -Rpass-missed= 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 emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName,
+ const Function &Fn, const DebugLoc &DLoc,
+ const Twine &Msg);
+
+/// Emit an optimization analysis remark message. \p PassName is the name of
+/// the pass emitting the message. If -Rpass-analysis= 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 emitOptimizationRemarkAnalysis(LLVMContext &Ctx, const char *PassName,
+ const Function &Fn, const DebugLoc &DLoc,
+ const Twine &Msg);
+
} // End namespace llvm
#endif
diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h
index f9644aca6b..4d940d599b 100644
--- a/include/llvm/IR/LLVMContext.h
+++ b/include/llvm/IR/LLVMContext.h
@@ -157,15 +157,6 @@ 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 3f8100f985..68a69183af 100644
--- a/lib/IR/DiagnosticInfo.cpp
+++ b/lib/IR/DiagnosticInfo.cpp
@@ -12,6 +12,7 @@
// Diagnostics reporting is still done as part of the LLVMContext.
//===----------------------------------------------------------------------===//
+#include "LLVMContextImpl.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
@@ -67,20 +68,20 @@ void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
DP << getMsg();
}
-bool DiagnosticInfoOptimizationRemark::isLocationAvailable() const {
+bool DiagnosticInfoOptimizationRemarkBase::isLocationAvailable() const {
return getFunction().getParent()->getNamedMetadata("llvm.dbg.cu") != nullptr;
}
-void DiagnosticInfoOptimizationRemark::getLocation(StringRef *Filename,
- unsigned *Line,
- unsigned *Column) const {
+void DiagnosticInfoOptimizationRemarkBase::getLocation(StringRef *Filename,
+ unsigned *Line,
+ unsigned *Column) const {
DILocation DIL(getDebugLoc().getAsMDNode(getFunction().getContext()));
*Filename = DIL.getFilename();
*Line = DIL.getLineNumber();
*Column = DIL.getColumnNumber();
}
-const std::string DiagnosticInfoOptimizationRemark::getLocationStr() const {
+const std::string DiagnosticInfoOptimizationRemarkBase::getLocationStr() const {
StringRef Filename("<unknown>");
unsigned Line = 0;
unsigned Column = 0;
@@ -89,6 +90,43 @@ const std::string DiagnosticInfoOptimizationRemark::getLocationStr() const {
return Twine(Filename + ":" + Twine(Line) + ":" + Twine(Column)).str();
}
-void DiagnosticInfoOptimizationRemark::print(DiagnosticPrinter &DP) const {
+void DiagnosticInfoOptimizationRemarkBase::print(DiagnosticPrinter &DP) const {
DP << getLocationStr() << ": " << getMsg();
}
+
+bool
+DiagnosticInfoOptimizationRemark::isEnabled(LLVMContextImpl *pImpl) const {
+ return pImpl->optimizationRemarkEnabledFor(this);
+}
+
+bool DiagnosticInfoOptimizationRemarkMissed::isEnabled(
+ LLVMContextImpl *pImpl) const {
+ return pImpl->optimizationRemarkEnabledFor(this);
+}
+
+bool DiagnosticInfoOptimizationRemarkAnalysis::isEnabled(
+ LLVMContextImpl *pImpl) const {
+ return pImpl->optimizationRemarkEnabledFor(this);
+}
+
+void llvm::emitOptimizationRemark(LLVMContext &Ctx, const char *PassName,
+ const Function &Fn, const DebugLoc &DLoc,
+ const Twine &Msg) {
+ Ctx.diagnose(DiagnosticInfoOptimizationRemark(PassName, Fn, DLoc, Msg));
+}
+
+void llvm::emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName,
+ const Function &Fn,
+ const DebugLoc &DLoc,
+ const Twine &Msg) {
+ Ctx.diagnose(DiagnosticInfoOptimizationRemarkMissed(PassName, Fn, DLoc, Msg));
+}
+
+void llvm::emitOptimizationRemarkAnalysis(LLVMContext &Ctx,
+ const char *PassName,
+ const Function &Fn,
+ const DebugLoc &DLoc,
+ const Twine &Msg) {
+ Ctx.diagnose(
+ DiagnosticInfoOptimizationRemarkAnalysis(PassName, Fn, DLoc, Msg));
+}
diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp
index 5f94dca1eb..7b75d42b85 100644
--- a/lib/IR/LLVMContext.cpp
+++ b/lib/IR/LLVMContext.cpp
@@ -142,14 +142,26 @@ void LLVMContext::diagnose(const DiagnosticInfo &DI) {
return;
}
- // Optimization remarks are selective. They need to check whether
- // the regexp pattern, passed via -pass-remarks, matches the name
- // of the pass that is emitting the diagnostic. If there is no match,
- // ignore the diagnostic and return.
- if (DI.getKind() == llvm::DK_OptimizationRemark &&
- !pImpl->optimizationRemarksEnabledFor(
- cast<DiagnosticInfoOptimizationRemark>(DI).getPassName()))
- return;
+ // Optimization remarks are selective. They need to check whether the regexp
+ // pattern, passed via one of the -pass-remarks* flags, matches the name of
+ // the pass that is emitting the diagnostic. If there is no match, ignore the
+ // diagnostic and return.
+ switch (DI.getKind()) {
+ case llvm::DK_OptimizationRemark:
+ if (!cast<DiagnosticInfoOptimizationRemark>(DI).isEnabled(pImpl))
+ return;
+ break;
+ case llvm::DK_OptimizationRemarkMissed:
+ if (!cast<DiagnosticInfoOptimizationRemarkMissed>(DI).isEnabled(pImpl))
+ return;
+ break;
+ case llvm::DK_OptimizationRemarkAnalysis:
+ if (!cast<DiagnosticInfoOptimizationRemarkAnalysis>(DI).isEnabled(pImpl))
+ return;
+ break;
+ default:
+ break;
+ }
// Otherwise, print the message with a prefix based on the severity.
std::string MsgStorage;
@@ -177,13 +189,6 @@ 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/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp
index 2042374647..24d325246d 100644
--- a/lib/IR/LLVMContextImpl.cpp
+++ b/lib/IR/LLVMContextImpl.cpp
@@ -14,6 +14,7 @@
#include "LLVMContextImpl.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Regex.h"
@@ -48,20 +49,20 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
namespace {
-/// \brief Regular expression corresponding to the value given in the
-/// command line flag -pass-remarks. Passes whose name matches this
-/// regexp will emit a diagnostic when calling
-/// LLVMContext::emitOptimizationRemark.
-static Regex *OptimizationRemarkPattern = nullptr;
-
+/// \brief Regular expression corresponding to the value given in one of the
+/// -pass-remarks* command line flags. Passes whose name matches this regexp
+/// will emit a diagnostic when calling the associated diagnostic function
+/// (emitOptimizationRemark, emitOptimizationRemarkMissed or
+/// emitOptimizationRemarkAnalysis).
struct PassRemarksOpt {
- void operator=(const std::string &Val) const {
+ std::shared_ptr<Regex> Pattern;
+
+ void operator=(const std::string &Val) {
// Create a regexp object to match pass names for emitOptimizationRemark.
if (!Val.empty()) {
- delete OptimizationRemarkPattern;
- OptimizationRemarkPattern = new Regex(Val);
+ Pattern = std::make_shared<Regex>(Val);
std::string RegexError;
- if (!OptimizationRemarkPattern->isValid(RegexError))
+ if (!Pattern->isValid(RegexError))
report_fatal_error("Invalid regular expression '" + Val +
"' in -pass-remarks: " + RegexError,
false);
@@ -70,31 +71,62 @@ struct PassRemarksOpt {
};
static PassRemarksOpt PassRemarksOptLoc;
+static PassRemarksOpt PassRemarksMissedOptLoc;
+static PassRemarksOpt PassRemarksAnalysisOptLoc;
// -pass-remarks
-// Command line flag to enable LLVMContext::emitOptimizationRemark()
-// and LLVMContext::emitOptimizationNote() calls.
+// Command line flag to enable emitOptimizationRemark()
static cl::opt<PassRemarksOpt, true, cl::parser<std::string>>
PassRemarks("pass-remarks", cl::value_desc("pattern"),
cl::desc("Enable optimization remarks from passes whose name match "
"the given regular expression"),
cl::Hidden, cl::location(PassRemarksOptLoc), cl::ValueRequired,
cl::ZeroOrMore);
+
+// -pass-remarks-missed
+// Command line flag to enable emitOptimizationRemarkMissed()
+static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> PassRemarksMissed(
+ "pass-remarks-missed", cl::value_desc("pattern"),
+ cl::desc("Enable missed optimization remarks from passes whose name match "
+ "the given regular expression"),
+ cl::Hidden, cl::location(PassRemarksMissedOptLoc), cl::ValueRequired,
+ cl::ZeroOrMore);
+
+// -pass-remarks-analysis
+// Command line flag to enable emitOptimizationRemarkAnalysis()
+static cl::opt<PassRemarksOpt, true, cl::parser<std::string>>
+PassRemarksAnalysis(
+ "pass-remarks-analysis", cl::value_desc("pattern"),
+ cl::desc(
+ "Enable optimization analysis remarks from passes whose name match "
+ "the given regular expression"),
+ cl::Hidden, cl::location(PassRemarksAnalysisOptLoc), cl::ValueRequired,
+ cl::ZeroOrMore);
}
-bool
-LLVMContextImpl::optimizationRemarksEnabledFor(const char *PassName) const {
- return OptimizationRemarkPattern &&
- OptimizationRemarkPattern->match(PassName);
+bool LLVMContextImpl::optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemark *DI) const {
+ return PassRemarksOptLoc.Pattern &&
+ PassRemarksOptLoc.Pattern->match(DI->getPassName());
}
+bool LLVMContextImpl::optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemarkMissed *DI) const {
+ return PassRemarksMissedOptLoc.Pattern &&
+ PassRemarksMissedOptLoc.Pattern->match(DI->getPassName());
+}
+
+bool LLVMContextImpl::optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemarkAnalysis *DI) const {
+ return PassRemarksAnalysisOptLoc.Pattern &&
+ PassRemarksAnalysisOptLoc.Pattern->match(DI->getPassName());
+}
namespace {
struct DropReferences {
// Takes the value_type of a ConstantUniqueMap's internal map, whose 'second'
// is a Constant*.
- template<typename PairT>
- void operator()(const PairT &P) {
+ template <typename PairT> void operator()(const PairT &P) {
P.second->dropAllReferences();
}
};
diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h
index b1ad9ff4a5..6ad9b8a70a 100644
--- a/lib/IR/LLVMContextImpl.h
+++ b/lib/IR/LLVMContextImpl.h
@@ -37,6 +37,9 @@ namespace llvm {
class ConstantInt;
class ConstantFP;
+class DiagnosticInfoOptimizationRemark;
+class DiagnosticInfoOptimizationRemarkMissed;
+class DiagnosticInfoOptimizationRemarkAnalysis;
class LLVMContext;
class Type;
class Value;
@@ -373,7 +376,12 @@ public:
/// \brief Return true if the given pass name should emit optimization
/// remarks.
- bool optimizationRemarksEnabledFor(const char *PassName) const;
+ bool optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemark *DI) const;
+ bool optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemarkMissed *DI) const;
+ bool optimizationRemarkEnabledFor(
+ const DiagnosticInfoOptimizationRemarkAnalysis *DI) const;
int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx);
int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx);
diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp
index 10b20cfc91..9087ab23bb 100644
--- a/lib/Transforms/IPO/Inliner.cpp
+++ b/lib/Transforms/IPO/Inliner.cpp
@@ -301,6 +301,13 @@ unsigned Inliner::getInlineThreshold(CallSite CS) const {
return thres;
}
+static void emitAnalysis(CallSite CS, const Twine &Msg) {
+ Function *Caller = CS.getCaller();
+ LLVMContext &Ctx = Caller->getContext();
+ DebugLoc DLoc = CS.getInstruction()->getDebugLoc();
+ emitOptimizationRemarkAnalysis(Ctx, DEBUG_TYPE, *Caller, DLoc, Msg);
+}
+
/// shouldInline - Return true if the inliner should attempt to inline
/// at the given CallSite.
bool Inliner::shouldInline(CallSite CS) {
@@ -309,12 +316,16 @@ bool Inliner::shouldInline(CallSite CS) {
if (IC.isAlways()) {
DEBUG(dbgs() << " Inlining: cost=always"
<< ", Call: " << *CS.getInstruction() << "\n");
+ emitAnalysis(CS, Twine(CS.getCalledFunction()->getName()) +
+ " should always be inlined (cost=always)");
return true;
}
if (IC.isNever()) {
DEBUG(dbgs() << " NOT Inlining: cost=never"
<< ", Call: " << *CS.getInstruction() << "\n");
+ emitAnalysis(CS, Twine(CS.getCalledFunction()->getName() +
+ " should never be inlined (cost=never)"));
return false;
}
@@ -323,6 +334,10 @@ bool Inliner::shouldInline(CallSite CS) {
DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << "\n");
+ emitAnalysis(CS, Twine(CS.getCalledFunction()->getName() +
+ " too costly to inline (cost=") +
+ Twine(IC.getCost()) + ", threshold=" +
+ Twine(IC.getCostDelta() + IC.getCost()) + ")");
return false;
}
@@ -390,6 +405,11 @@ bool Inliner::shouldInline(CallSite CS) {
DEBUG(dbgs() << " NOT Inlining: " << *CS.getInstruction() <<
" Cost = " << IC.getCost() <<
", outer Cost = " << TotalSecondaryCost << '\n');
+ emitAnalysis(
+ CS, Twine("Not inlining. Cost of inlining " +
+ CS.getCalledFunction()->getName() +
+ " increases the cost of inlining " +
+ CS.getCaller()->getName() + " in other contexts"));
return false;
}
}
@@ -397,6 +417,10 @@ bool Inliner::shouldInline(CallSite CS) {
DEBUG(dbgs() << " Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << '\n');
+ emitAnalysis(
+ CS, CS.getCalledFunction()->getName() + Twine(" can be inlined into ") +
+ CS.getCaller()->getName() + " with cost=" + Twine(IC.getCost()) +
+ " (threshold=" + Twine(IC.getCostDelta() + IC.getCost()) + ")");
return true;
}
@@ -518,24 +542,35 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) {
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory))
continue;
-
- // If the policy determines that we should inline this function,
- // try to do so.
- if (!shouldInline(CS))
- continue;
+ LLVMContext &CallerCtx = Caller->getContext();
// Get DebugLoc to report. CS will be invalid after Inliner.
DebugLoc DLoc = CS.getInstruction()->getDebugLoc();
+ // If the policy determines that we should inline this function,
+ // try to do so.
+ if (!shouldInline(CS)) {
+ emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
+ Twine(Callee->getName() +
+ " will not be inlined into " +
+ Caller->getName()));
+ continue;
+ }
+
// Attempt to inline the function.
if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,
- InlineHistoryID, InsertLifetime, DL))
+ InlineHistoryID, InsertLifetime, DL)) {
+ emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
+ Twine(Callee->getName() +
+ " will not be inlined into " +
+ Caller->getName()));
continue;
+ }
++NumInlined;
// Report the inline decision.
- Caller->getContext().emitOptimizationRemark(
- DEBUG_TYPE, *Caller, DLoc,
+ emitOptimizationRemark(
+ CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() + " inlined into " + Caller->getName()));
// If inlining this function gave us any new call sites, throw them
diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp
index 946af80077..05b9892470 100644
--- a/lib/Transforms/Scalar/TailRecursionElimination.cpp
+++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp
@@ -64,6 +64,7 @@
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -318,8 +319,8 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) {
break;
}
if (SafeToTail) {
- F.getContext().emitOptimizationRemark(
- "tailcallelim", F, CI->getDebugLoc(),
+ emitOptimizationRemark(
+ F.getContext(), "tailcallelim", F, CI->getDebugLoc(),
"marked this readnone call a tail call candidate");
CI->setTailCall();
Modified = true;
@@ -365,9 +366,9 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) {
if (Visited[CI->getParent()] != ESCAPED) {
// If the escape point was part way through the block, calls after the
// escape point wouldn't have been put into DeferredTails.
- F.getContext().emitOptimizationRemark(
- "tailcallelim", F, CI->getDebugLoc(),
- "marked this call a tail call candidate");
+ emitOptimizationRemark(F.getContext(), "tailcallelim", F,
+ CI->getDebugLoc(),
+ "marked this call a tail call candidate");
CI->setTailCall();
Modified = true;
} else {
@@ -678,9 +679,8 @@ bool TailCallElim::EliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret,
BasicBlock *BB = Ret->getParent();
Function *F = BB->getParent();
- F->getContext().emitOptimizationRemark(
- "tailcallelim", *F, CI->getDebugLoc(),
- "transforming tail recursion to loop");
+ emitOptimizationRemark(F->getContext(), "tailcallelim", *F, CI->getDebugLoc(),
+ "transforming tail recursion to loop");
// OK! We can transform this tail call. If this is the first one found,
// create the new entry block, allowing us to branch back to the old entry.
diff --git a/lib/Transforms/Utils/LoopUnroll.cpp b/lib/Transforms/Utils/LoopUnroll.cpp
index faaab5c12e..d953e30731 100644
--- a/lib/Transforms/Utils/LoopUnroll.cpp
+++ b/lib/Transforms/Utils/LoopUnroll.cpp
@@ -24,6 +24,7 @@
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -237,9 +238,9 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, unsigned TripCount,
if (CompletelyUnroll) {
DEBUG(dbgs() << "COMPLETELY UNROLLING loop %" << Header->getName()
<< " with trip count " << TripCount << "!\n");
- Ctx.emitOptimizationRemark(DEBUG_TYPE, *F, LoopLoc,
- Twine("completely unrolled loop with ") +
- Twine(TripCount) + " iterations");
+ emitOptimizationRemark(Ctx, DEBUG_TYPE, *F, LoopLoc,
+ Twine("completely unrolled loop with ") +
+ Twine(TripCount) + " iterations");
} else {
DEBUG(dbgs() << "UNROLLING loop %" << Header->getName()
<< " by " << Count);
@@ -255,7 +256,7 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, unsigned TripCount,
DiagMsg.concat(" with run-time trip count");
}
DEBUG(dbgs() << "!\n");
- Ctx.emitOptimizationRemark(DEBUG_TYPE, *F, LoopLoc, DiagMsg);
+ emitOptimizationRemark(Ctx, DEBUG_TYPE, *F, LoopLoc, DiagMsg);
}
bool ContinueOnTrue = L->contains(BI->getSuccessor(0));
diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 0fd185816f..3b61bb575a 100644
--- a/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -789,9 +790,9 @@ struct StrLenOpt : public LibCallOptimization {
uint64_t LenTrue = GetStringLength(SI->getTrueValue());
uint64_t LenFalse = GetStringLength(SI->getFalseValue());
if (LenTrue && LenFalse) {
- Context->emitOptimizationRemark(
- "simplify-libcalls", *Caller, SI->getDebugLoc(),
- "folded strlen(select) to select of constants");
+ emitOptimizationRemark(*Context, "simplify-libcalls", *Caller,
+ SI->getDebugLoc(),
+ "folded strlen(select) to select of constants");
return B.CreateSelect(SI->getCondition(),
ConstantInt::get(CI->getType(), LenTrue-1),
ConstantInt::get(CI->getType(), LenFalse-1));
diff --git a/lib/Transforms/Vectorize/LoopVectorize.cpp b/lib/Transforms/Vectorize/LoopVectorize.cpp
index d57fae34dd..34d8a1053f 100644
--- a/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -67,6 +67,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
@@ -1213,10 +1214,10 @@ struct LoopVectorize : public FunctionPass {
DEBUG(dbgs() << "LV: Trying to at least unroll the loops.\n");
// Report the unrolling decision.
- F->getContext().emitOptimizationRemark(
- DEBUG_TYPE, *F, L->getStartLoc(),
- Twine("unrolled with interleaving factor " + Twine(UF) +
- " (vectorization not beneficial)"));
+ emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, L->getStartLoc(),
+ Twine("unrolled with interleaving factor " +
+ Twine(UF) +
+ " (vectorization not beneficial)"));
// We decided not to vectorize, but we may want to unroll.
InnerLoopUnroller Unroller(L, SE, LI, DT, DL, TLI, UF);
@@ -1228,8 +1229,8 @@ struct LoopVectorize : public FunctionPass {
++LoopsVectorized;
// Report the vectorization decision.
- F->getContext().emitOptimizationRemark(
- DEBUG_TYPE, *F, L->getStartLoc(),
+ emitOptimizationRemark(
+ F->getContext(), DEBUG_TYPE, *F, L->getStartLoc(),
Twine("vectorized loop (vectorization factor: ") + Twine(VF.Width) +
", unrolling interleave factor: " + Twine(UF) + ")");
}
diff --git a/test/Transforms/Inline/optimization-remarks.ll b/test/Transforms/Inline/optimization-remarks.ll
new file mode 100644
index 0000000000..9108f3ab14
--- /dev/null
+++ b/test/Transforms/Inline/optimization-remarks.ll
@@ -0,0 +1,60 @@
+; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline -pass-remarks-analysis=inline -S 2>&1 | FileCheck %s
+
+; CHECK: foo should always be inlined (cost=always)
+; CHECK: foo inlined into bar
+; CHECK: foz should never be inlined (cost=never)
+; CHECK: foz will not be inlined into bar
+
+; Function Attrs: alwaysinline nounwind uwtable
+define i32 @foo(i32 %x, i32 %y) #0 {
+entry:
+ %x.addr = alloca i32, align 4
+ %y.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ store i32 %y, i32* %y.addr, align 4
+ %0 = load i32* %x.addr, align 4
+ %1 = load i32* %y.addr, align 4
+ %add = add nsw i32 %0, %1
+ ret i32 %add
+}
+
+; Function Attrs: noinline nounwind uwtable
+define float @foz(i32 %x, i32 %y) #1 {
+entry:
+ %x.addr = alloca i32, align 4
+ %y.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ store i32 %y, i32* %y.addr, align 4
+ %0 = load i32* %x.addr, align 4
+ %1 = load i32* %y.addr, align 4
+ %mul = mul nsw i32 %0, %1
+ %conv = sitofp i32 %mul to float
+ ret float %conv
+}
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %j) #2 {
+entry:
+ %j.addr = alloca i32, align 4
+ store i32 %j, i32* %j.addr, align 4
+ %0 = load i32* %j.addr, align 4
+ %1 = load i32* %j.addr, align 4
+ %sub = sub nsw i32 %1, 2
+ %call = call i32 @foo(i32 %0, i32 %sub)
+ %conv = sitofp i32 %call to float
+ %2 = load i32* %j.addr, align 4
+ %sub1 = sub nsw i32 %2, 2
+ %3 = load i32* %j.addr, align 4
+ %call2 = call float @foz(i32 %sub1, i32 %3)
+ %mul = fmul float %conv, %call2
+ %conv3 = fptosi float %mul to i32
+ ret i32 %conv3
+}
+
+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" }
+attributes #1 = { noinline 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" }
+attributes #2 = { 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" }
+
+!llvm.ident = !{!0}
+
+!0 = metadata !{metadata !"clang version 3.5.0 "}