diff --git a/include/llvm/Analysis/LoopAccessAnalysis.h b/include/llvm/Analysis/LoopAccessAnalysis.h index 0aa09aa5d6d..81515337711 100644 --- a/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/include/llvm/Analysis/LoopAccessAnalysis.h @@ -22,6 +22,7 @@ #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" @@ -595,7 +596,7 @@ public: /// \brief The diagnostics report generated for the analysis. E.g. why we /// couldn't analyze the loop. - const Optional &getReport() const { return Report; } + const OptimizationRemarkAnalysis *getReport() const { return Report.get(); } /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. @@ -646,7 +647,8 @@ private: /// LAA does not directly emits the remarks. Instead it stores it which the /// client can retrieve and presents as its own analysis /// (e.g. -Rpass-analysis=loop-vectorize). - void recordAnalysis(LoopAccessReport &Message); + OptimizationRemarkAnalysis &recordAnalysis(StringRef RemarkName, + Instruction *Instr = nullptr); /// \brief Collect memory access with loop invariant strides. /// @@ -680,7 +682,7 @@ private: /// \brief The diagnostics report generated for the analysis. E.g. why we /// couldn't analyze the loop. - Optional Report; + std::unique_ptr Report; /// \brief If an access has a symbolic strides, this maps the pointer value to /// the stride symbol. diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index 015f3042a13..d8c73b5653a 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -409,6 +409,24 @@ public: PassName(PassName), RemarkName(RemarkName), CodeRegion(CodeRegion), IsVerbose(false) {} + /// \brief This is ctor variant allows a pass to build an optimization remark + /// from an existing remark. + /// + /// This is useful when a transformation pass (e.g LV) wants to emit a remark + /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis + /// remark. The string \p Prepend will be emitted before the original + /// message. + DiagnosticInfoOptimizationBase(const char *PassName, StringRef Prepend, + const DiagnosticInfoOptimizationBase &Orig) + : DiagnosticInfoWithDebugLocBase((DiagnosticKind)Orig.getKind(), + Orig.getSeverity(), Orig.getFunction(), + Orig.getDebugLoc()), + PassName(PassName), RemarkName(Orig.RemarkName), + CodeRegion(Orig.getCodeRegion()) { + *this << Prepend; + std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); + } + /// Legacy interface. /// \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 @@ -578,6 +596,17 @@ public: OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, const DebugLoc &DLoc, Value *CodeRegion); + /// \brief This is ctor variant allows a pass to build an optimization remark + /// from an existing remark. + /// + /// This is useful when a transformation pass (e.g LV) wants to emit a remark + /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis + /// remark. The string \p Prepend will be emitted before the original + /// message. + OptimizationRemarkAnalysis(const char *PassName, StringRef Prepend, + const OptimizationRemarkAnalysis &Orig) + : DiagnosticInfoOptimizationBase(PassName, Prepend, Orig) {} + /// \brief Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, diff --git a/lib/Analysis/LoopAccessAnalysis.cpp b/lib/Analysis/LoopAccessAnalysis.cpp index e17ff6f51cb..428d63960f0 100644 --- a/lib/Analysis/LoopAccessAnalysis.cpp +++ b/lib/Analysis/LoopAccessAnalysis.cpp @@ -1482,23 +1482,23 @@ bool LoopAccessInfo::canAnalyzeLoop() { // We can only analyze innermost loops. if (!TheLoop->empty()) { DEBUG(dbgs() << "LAA: loop is not the innermost loop\n"); - recordAnalysis(LoopAccessReport() << "loop is not the innermost loop"); + recordAnalysis("NotInnerMostLoop") << "loop is not the innermost loop"; return false; } // We must have a single backedge. if (TheLoop->getNumBackEdges() != 1) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); - recordAnalysis(LoopAccessReport() - << "loop control flow is not understood by analyzer"); + recordAnalysis("CFGNotUnderstood") + << "loop control flow is not understood by analyzer"; return false; } // We must have a single exiting block. if (!TheLoop->getExitingBlock()) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); - recordAnalysis(LoopAccessReport() - << "loop control flow is not understood by analyzer"); + recordAnalysis("CFGNotUnderstood") + << "loop control flow is not understood by analyzer"; return false; } @@ -1507,16 +1507,16 @@ bool LoopAccessInfo::canAnalyzeLoop() { // instructions in the loop are executed the same number of times. if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); - recordAnalysis(LoopAccessReport() - << "loop control flow is not understood by analyzer"); + recordAnalysis("CFGNotUnderstood") + << "loop control flow is not understood by analyzer"; return false; } // ScalarEvolution needs to be able to find the exit count. const SCEV *ExitCount = PSE->getBackedgeTakenCount(); if (ExitCount == PSE->getSE()->getCouldNotCompute()) { - recordAnalysis(LoopAccessReport() - << "could not determine number of loop iterations"); + recordAnalysis("CantComputeNumberOfIterations") + << "could not determine number of loop iterations"; DEBUG(dbgs() << "LAA: SCEV could not compute the loop exit count.\n"); return false; } @@ -1565,8 +1565,8 @@ void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, auto *Ld = dyn_cast(&I); if (!Ld || (!Ld->isSimple() && !IsAnnotatedParallel)) { - recordAnalysis(LoopAccessReport(Ld) - << "read with atomic ordering or volatile read"); + recordAnalysis("NonSimpleLoad", Ld) + << "read with atomic ordering or volatile read"; DEBUG(dbgs() << "LAA: Found a non-simple load.\n"); CanVecMem = false; return; @@ -1583,14 +1583,14 @@ void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, if (I.mayWriteToMemory()) { auto *St = dyn_cast(&I); if (!St) { - recordAnalysis(LoopAccessReport(St) - << "instruction cannot be vectorized"); + recordAnalysis("CantVectorizeInstruction", St) + << "instruction cannot be vectorized"; CanVecMem = false; return; } if (!St->isSimple() && !IsAnnotatedParallel) { - recordAnalysis(LoopAccessReport(St) - << "write with atomic ordering or volatile write"); + recordAnalysis("NonSimpleStore", St) + << "write with atomic ordering or volatile write"; DEBUG(dbgs() << "LAA: Found a non-simple store.\n"); CanVecMem = false; return; @@ -1698,7 +1698,7 @@ void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, bool CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, PSE->getSE(), TheLoop, SymbolicStrides); if (!CanDoRTIfNeeded) { - recordAnalysis(LoopAccessReport() << "cannot identify array bounds"); + recordAnalysis("CantIdentifyArrayBounds") << "cannot identify array bounds"; DEBUG(dbgs() << "LAA: We can't vectorize because we can't find " << "the array bounds.\n"); CanVecMem = false; @@ -1729,8 +1729,8 @@ void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, // Check that we found the bounds for the pointer. if (!CanDoRTIfNeeded) { - recordAnalysis(LoopAccessReport() - << "cannot check memory dependencies at runtime"); + recordAnalysis("CantCheckMemDepsAtRunTime") + << "cannot check memory dependencies at runtime"; DEBUG(dbgs() << "LAA: Can't vectorize with memory checks\n"); CanVecMem = false; return; @@ -1745,12 +1745,11 @@ void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, << (PtrRtChecking->Need ? "" : " don't") << " need runtime memory checks.\n"); else { - recordAnalysis( - LoopAccessReport() + recordAnalysis("UnsafeMemDep") << "unsafe dependent memory operations in loop. Use " "#pragma loop distribute(enable) to allow loop distribution " "to attempt to isolate the offending operations into a separate " - "loop"); + "loop"; DEBUG(dbgs() << "LAA: unsafe dependent memory operations in loop\n"); } } @@ -1764,9 +1763,24 @@ bool LoopAccessInfo::blockNeedsPredication(BasicBlock *BB, Loop *TheLoop, return !DT->dominates(BB, Latch); } -void LoopAccessInfo::recordAnalysis(LoopAccessReport &Message) { +OptimizationRemarkAnalysis &LoopAccessInfo::recordAnalysis(StringRef RemarkName, + Instruction *I) { assert(!Report && "Multiple reports generated"); - Report = Message; + + Value *CodeRegion = TheLoop->getHeader(); + DebugLoc DL = TheLoop->getStartLoc(); + + if (I) { + CodeRegion = I->getParent(); + // If there is no debug location attached to the instruction, revert back to + // using the loop's. + if (I->getDebugLoc()) + DL = I->getDebugLoc(); + } + + Report = make_unique(DEBUG_TYPE, RemarkName, DL, + CodeRegion); + return *Report; } bool LoopAccessInfo::isUniform(Value *V) const { @@ -1974,7 +1988,7 @@ void LoopAccessInfo::print(raw_ostream &OS, unsigned Depth) const { } if (Report) - OS.indent(Depth) << "Report: " << Report->str() << "\n"; + OS.indent(Depth) << "Report: " << Report->getMsg() << "\n"; if (auto *Dependences = DepChecker->getDependences()) { OS.indent(Depth) << "Dependences:\n"; diff --git a/lib/Transforms/Vectorize/LoopVectorize.cpp b/lib/Transforms/Vectorize/LoopVectorize.cpp index bc92441250f..fe37c19c230 100644 --- a/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -5505,9 +5505,12 @@ void LoopVectorizationLegality::collectLoopUniforms() { bool LoopVectorizationLegality::canVectorizeMemory() { LAI = &(*GetLAA)(*TheLoop); InterleaveInfo.setLAI(LAI); - auto &OptionalReport = LAI->getReport(); - if (OptionalReport) - emitAnalysis(VectorizationReport(*OptionalReport)); + const OptimizationRemarkAnalysis *LAR = LAI->getReport(); + if (LAR) { + OptimizationRemarkAnalysis VR(Hints->vectorizeAnalysisPassName(), + "loop not vectorized: ", *LAR); + ORE->emit(VR); + } if (!LAI->canVectorizeMemory()) return false;