Index: include/llvm/Analysis/OptimizationDiagnosticInfo.h =================================================================== --- include/llvm/Analysis/OptimizationDiagnosticInfo.h +++ include/llvm/Analysis/OptimizationDiagnosticInfo.h @@ -24,7 +24,6 @@ namespace llvm { class DebugLoc; -class LLVMContext; class Loop; class Pass; class Twine; @@ -71,6 +70,21 @@ /// the diagnostic handler if remarks are requested for the pass. void emit(DiagnosticInfoOptimizationBase &OptDiag); + /// \brief Take a lambda that returns a remark which will be emitted. Second + /// argument is only used to restrict this to functions. + template + void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { + // Avoid building the remark unless we know there are at least *some* + // remarks enabled. We can't currently check whether remarks are requested + // for the calling pass since that requires actually building the remark. + + if (F->getContext().getDiagnosticsOutputFile() || + F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) { + auto R = RemarkBuilder(); + emit(R); + } + } + /// \brief Whether we allow for extra compile-time budget to perform more /// analysis to produce fewer false positives. /// Index: include/llvm/IR/DiagnosticHandler.h =================================================================== --- include/llvm/IR/DiagnosticHandler.h +++ include/llvm/IR/DiagnosticHandler.h @@ -57,11 +57,14 @@ /// to provide different implementation. virtual bool isPassedOptRemarkEnabled(StringRef PassName) const; - /// Return true if any type of remarks are enabled. + /// Return true if any type of remarks are enabled for this pass. bool isAnyRemarkEnabled(StringRef PassName) const { return (isMissedOptRemarkEnabled(PassName) || isPassedOptRemarkEnabled(PassName) || isAnalysisRemarkEnabled(PassName)); } + + /// Return true if any type of remarks are enabled for any pass. + virtual bool isAnyRemarkEnabled() const; }; } Index: include/llvm/IR/DiagnosticInfo.h =================================================================== --- include/llvm/IR/DiagnosticInfo.h +++ include/llvm/IR/DiagnosticInfo.h @@ -438,10 +438,10 @@ : DiagnosticInfoWithLocationBase(Kind, Severity, Fn, Loc), PassName(PassName), RemarkName(RemarkName) {} - DiagnosticInfoOptimizationBase &operator<<(StringRef S); - DiagnosticInfoOptimizationBase &operator<<(Argument A); - DiagnosticInfoOptimizationBase &operator<<(setIsVerbose V); - DiagnosticInfoOptimizationBase &operator<<(setExtraArgs EA); + void insert(StringRef S); + void insert(Argument A); + void insert(setIsVerbose V); + void insert(setExtraArgs EA); /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; @@ -511,6 +511,81 @@ friend struct yaml::MappingTraits; }; +/// Allow the insertion operator to return the actual remark type rather than a +/// common base class. This allows returning the result of the insertion +/// directly by value, e.g. return OptimizationRemarkAnalysis(...) << "blah". +template +RemarkT & +operator<<(RemarkT &R, + typename std::enable_if< + std::is_base_of::value, + StringRef>::type S) { + R.insert(S); + return R; +} + +/// Also allow r-value for the remark to allow insertion into a +/// temporarily-constructed remark. +template +RemarkT & +operator<<(RemarkT &&R, + typename std::enable_if< + std::is_base_of::value, + StringRef>::type S) { + R.insert(S); + return R; +} + +template +RemarkT & +operator<<(RemarkT &R, + typename std::enable_if< + std::is_base_of::value, + DiagnosticInfoOptimizationBase::Argument>::type A) { + R.insert(A); + return R; +} + +template +RemarkT & +operator<<(RemarkT &&R, + typename std::enable_if< + std::is_base_of::value, + DiagnosticInfoOptimizationBase::Argument>::type A) { + R.insert(A); + return R; +} + +template +RemarkT & +operator<<(RemarkT &R, + typename std::enable_if< + std::is_base_of::value, + DiagnosticInfoOptimizationBase::setIsVerbose>::type V) { + R.insert(V); + return R; +} + +template +RemarkT & +operator<<(RemarkT &&R, + typename std::enable_if< + std::is_base_of::value, + DiagnosticInfoOptimizationBase::setIsVerbose>::type V) { + R.insert(V); + return R; +} + +template +RemarkT & +operator<<(RemarkT &R, + typename std::enable_if< + std::is_base_of::value, + DiagnosticInfoOptimizationBase::setExtraArgs>::type EA) { + R.insert(EA); + return R; +} + /// \brief Common features for diagnostics dealing with optimization remarks /// that are used by IR passes. class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase { Index: lib/IR/DiagnosticHandler.cpp =================================================================== --- lib/IR/DiagnosticHandler.cpp +++ lib/IR/DiagnosticHandler.cpp @@ -84,3 +84,8 @@ return (PassRemarksPassedOptLoc.Pattern && PassRemarksPassedOptLoc.Pattern->match(PassName)); } + +bool DiagnosticHandler::isAnyRemarkEnabled() const { + return (PassRemarksPassedOptLoc.Pattern || PassRemarksMissedOptLoc.Pattern || + PassRemarksAnalysisOptLoc.Pattern); +} Index: lib/IR/DiagnosticInfo.cpp =================================================================== --- lib/IR/DiagnosticInfo.cpp +++ lib/IR/DiagnosticInfo.cpp @@ -315,28 +315,20 @@ DP << "Instruction selection used fallback path for " << getFunction(); } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(StringRef S) { +void DiagnosticInfoOptimizationBase::insert(StringRef S) { Args.emplace_back(S); - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(Argument A) { +void DiagnosticInfoOptimizationBase::insert(Argument A) { Args.push_back(std::move(A)); - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(setIsVerbose V) { +void DiagnosticInfoOptimizationBase::insert(setIsVerbose V) { IsVerbose = true; - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(setExtraArgs EA) { +void DiagnosticInfoOptimizationBase::insert(setExtraArgs EA) { FirstExtraArgIndex = Args.size(); - return *this; } std::string DiagnosticInfoOptimizationBase::getMsg() const { Index: lib/Transforms/IPO/Inliner.cpp =================================================================== --- lib/Transforms/IPO/Inliner.cpp +++ lib/Transforms/IPO/Inliner.cpp @@ -356,10 +356,12 @@ if (IC.isNever()) { DEBUG(dbgs() << " NOT Inlining: cost=never" << ", Call: " << *CS.getInstruction() << "\n"); - ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, "NeverInline", Call) + ORE.emit([&]() { + return OptimizationRemarkMissed(DEBUG_TYPE, "NeverInline", Call) << NV("Callee", Callee) << " not inlined into " << NV("Caller", Caller) - << " because it should never be inlined (cost=never)"); + << " because it should never be inlined (cost=never)"; + }); return None; } @@ -367,11 +369,13 @@ DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost() << ", thres=" << IC.getThreshold() << ", Call: " << *CS.getInstruction() << "\n"); - ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, "TooCostly", Call) + ORE.emit([&]() { + return OptimizationRemarkMissed(DEBUG_TYPE, "TooCostly", Call) << NV("Callee", Callee) << " not inlined into " << NV("Caller", Caller) << " because too costly to inline (cost=" << NV("Cost", IC.getCost()) - << ", threshold=" << NV("Threshold", IC.getThreshold()) << ")"); + << ", threshold=" << NV("Threshold", IC.getThreshold()) << ")"; + }); return None; } @@ -581,12 +585,14 @@ << NV("Callee", Callee) << " inlined into " << NV("Caller", Caller) << " with cost=always"); else - ORE.emit(OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block) + ORE.emit([&]() { + return OptimizationRemark(DEBUG_TYPE, "Inlined", DLoc, Block) << NV("Callee", Callee) << " inlined into " << NV("Caller", Caller) << " with cost=" << NV("Cost", OIC->getCost()) << " (threshold=" << NV("Threshold", OIC->getThreshold()) - << ")"); + << ")"; + }); // If inlining this function gave us any new call sites, throw them // onto our worklist to process. They are useful inline candidates. Index: lib/Transforms/Utils/LoopUnroll.cpp =================================================================== --- lib/Transforms/Utils/LoopUnroll.cpp +++ lib/Transforms/Utils/LoopUnroll.cpp @@ -476,23 +476,30 @@ << " peeled loop by " << NV("PeelCount", PeelCount) << " iterations"); } else { - OptimizationRemark Diag(DEBUG_TYPE, "PartialUnrolled", L->getStartLoc(), - L->getHeader()); - Diag << "unrolled loop by a factor of " << NV("UnrollCount", Count); + auto DiagBuilder = [&]() { + OptimizationRemark Diag(DEBUG_TYPE, "PartialUnrolled", L->getStartLoc(), + L->getHeader()); + return Diag << "unrolled loop by a factor of " + << NV("UnrollCount", Count); + }; DEBUG(dbgs() << "UNROLLING loop %" << Header->getName() << " by " << Count); if (TripMultiple == 0 || BreakoutTrip != TripMultiple) { DEBUG(dbgs() << " with a breakout at trip " << BreakoutTrip); - ORE->emit(Diag << " with a breakout at trip " - << NV("BreakoutTrip", BreakoutTrip)); + ORE->emit([&]() { + return DiagBuilder() << " with a breakout at trip " + << NV("BreakoutTrip", BreakoutTrip); + }); } else if (TripMultiple != 1) { DEBUG(dbgs() << " with " << TripMultiple << " trips per branch"); - ORE->emit(Diag << " with " << NV("TripMultiple", TripMultiple) - << " trips per branch"); + ORE->emit([&]() { + return DiagBuilder() << " with " << NV("TripMultiple", TripMultiple) + << " trips per branch"; + }); } else if (RuntimeTripCount) { DEBUG(dbgs() << " with run-time trip count"); - ORE->emit(Diag << " with run-time trip count"); + ORE->emit([&]() { return DiagBuilder() << " with run-time trip count"; }); } DEBUG(dbgs() << "!\n"); } Index: lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- lib/Transforms/Vectorize/LoopVectorize.cpp +++ lib/Transforms/Vectorize/LoopVectorize.cpp @@ -1231,12 +1231,14 @@ // FIXME: Add interleave.disable metadata. This will allow // vectorize.disable to be used without disabling the pass and errors // to differentiate between disabled vectorization and a width of 1. - ORE.emit(OptimizationRemarkAnalysis(vectorizeAnalysisPassName(), + ORE.emit([&]() { + return OptimizationRemarkAnalysis(vectorizeAnalysisPassName(), "AllDisabled", L->getStartLoc(), L->getHeader()) << "loop not vectorized: vectorization and interleaving are " "explicitly disabled, or the loop has already been " - "vectorized"); + "vectorized"; + }); return false; }