diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index de38d07f903..deceaa81b83 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -51,6 +51,7 @@ enum DiagnosticKind { DK_OptimizationRemark, DK_OptimizationRemarkMissed, DK_OptimizationRemarkAnalysis, + DK_OptimizationWarning, DK_FirstPluginKind }; @@ -239,7 +240,7 @@ private: }; /// Common features for diagnostics dealing with optimization remarks. -class DiagnosticInfoOptimizationRemarkBase : public DiagnosticInfo { +class DiagnosticInfoOptimizationBase : public DiagnosticInfo { public: /// \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 @@ -248,10 +249,11 @@ public: /// 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), + DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, + enum DiagnosticSeverity Severity, + const char *PassName, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg) + : DiagnosticInfo(Kind, Severity), PassName(PassName), Fn(Fn), DLoc(DLoc), Msg(Msg) {} /// \see DiagnosticInfo::print. @@ -302,8 +304,7 @@ private: }; /// Diagnostic information for applied optimization remarks. -class DiagnosticInfoOptimizationRemark - : public DiagnosticInfoOptimizationRemarkBase { +class DiagnosticInfoOptimizationRemark : public DiagnosticInfoOptimizationBase { public: /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass=, then the @@ -315,20 +316,20 @@ public: /// 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) {} + : DiagnosticInfoOptimizationBase(DK_OptimizationRemark, DS_Remark, + PassName, Fn, DLoc, Msg) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemark; } - /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled. + /// \see DiagnosticInfoOptimizationBase::isEnabled. virtual bool isEnabled() const override; }; /// Diagnostic information for missed-optimization remarks. class DiagnosticInfoOptimizationRemarkMissed - : public DiagnosticInfoOptimizationRemarkBase { + : public DiagnosticInfoOptimizationBase { 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 @@ -341,20 +342,20 @@ public: DiagnosticInfoOptimizationRemarkMissed(const char *PassName, const Function &Fn, const DebugLoc &DLoc, const Twine &Msg) - : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkMissed, - PassName, Fn, DLoc, Msg) {} + : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkMissed, DS_Remark, + PassName, Fn, DLoc, Msg) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkMissed; } - /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled. + /// \see DiagnosticInfoOptimizationBase::isEnabled. virtual bool isEnabled() const override; }; /// Diagnostic information for optimization analysis remarks. class DiagnosticInfoOptimizationRemarkAnalysis - : public DiagnosticInfoOptimizationRemarkBase { + : public DiagnosticInfoOptimizationBase { public: /// \p PassName is the name of the pass emitting this diagnostic. If /// this name matches the regular expression given in -Rpass-analysis=, then @@ -368,14 +369,14 @@ public: const Function &Fn, const DebugLoc &DLoc, const Twine &Msg) - : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkAnalysis, - PassName, Fn, DLoc, Msg) {} + : DiagnosticInfoOptimizationBase(DK_OptimizationRemarkAnalysis, DS_Remark, + PassName, Fn, DLoc, Msg) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysis; } - /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled. + /// \see DiagnosticInfoOptimizationBase::isEnabled. virtual bool isEnabled() const override; }; @@ -411,6 +412,41 @@ void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, const char *PassName, const Function &Fn, const DebugLoc &DLoc, const Twine &Msg); +/// Diagnostic information for optimization warnings. +class DiagnosticInfoOptimizationWarning + : public DiagnosticInfoOptimizationBase { +public: + /// \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. + DiagnosticInfoOptimizationWarning(const Function &Fn, const DebugLoc &DLoc, + const Twine &Msg) + : DiagnosticInfoOptimizationBase(DK_OptimizationWarning, DS_Warning, + nullptr, Fn, DLoc, Msg) {} + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_OptimizationWarning; + } + + /// \see DiagnosticInfoOptimizationBase::isEnabled. + virtual bool isEnabled() const override; +}; + +/// Emit a warning when loop vectorization is specified but fails. \p Fn is the +/// function triggering the warning, \p DLoc is the debug location where the +/// diagnostic is generated. \p Msg is the message string to use. +void emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg); + +/// Emit a warning when loop interleaving is specified but fails. \p Fn is the +/// function triggering the warning, \p DLoc is the debug location where the +/// diagnostic is generated. \p Msg is the message string to use. +void emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg); + } // End namespace llvm #endif diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index 27270636004..0518c1ba96e 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -127,20 +127,20 @@ void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const { DP << getMsg(); } -bool DiagnosticInfoOptimizationRemarkBase::isLocationAvailable() const { +bool DiagnosticInfoOptimizationBase::isLocationAvailable() const { return getDebugLoc().isUnknown() == false; } -void DiagnosticInfoOptimizationRemarkBase::getLocation(StringRef *Filename, - unsigned *Line, - unsigned *Column) const { +void DiagnosticInfoOptimizationBase::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 DiagnosticInfoOptimizationRemarkBase::getLocationStr() const { +const std::string DiagnosticInfoOptimizationBase::getLocationStr() const { StringRef Filename(""); unsigned Line = 0; unsigned Column = 0; @@ -149,7 +149,7 @@ const std::string DiagnosticInfoOptimizationRemarkBase::getLocationStr() const { return Twine(Filename + ":" + Twine(Line) + ":" + Twine(Column)).str(); } -void DiagnosticInfoOptimizationRemarkBase::print(DiagnosticPrinter &DP) const { +void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const { DP << getLocationStr() << ": " << getMsg(); } @@ -189,3 +189,20 @@ void llvm::emitOptimizationRemarkAnalysis(LLVMContext &Ctx, Ctx.diagnose( DiagnosticInfoOptimizationRemarkAnalysis(PassName, Fn, DLoc, Msg)); } + +bool DiagnosticInfoOptimizationWarning::isEnabled() const { + // Only print warnings. + return getSeverity() == DS_Warning; +} + +void llvm::emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg) { + Ctx.diagnose(DiagnosticInfoOptimizationWarning( + Fn, DLoc, Twine("loop not vectorized: " + Msg))); +} + +void llvm::emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, + const DebugLoc &DLoc, const Twine &Msg) { + Ctx.diagnose(DiagnosticInfoOptimizationWarning( + Fn, DLoc, Twine("loop not interleaved: " + Msg))); +} diff --git a/lib/Transforms/Vectorize/LoopVectorize.cpp b/lib/Transforms/Vectorize/LoopVectorize.cpp index cb8a41dbeab..6e82590ff1f 100644 --- a/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -1086,6 +1086,23 @@ private: MDNode *LoopID; }; +static void emitMissedWarning(Function *F, Loop *L, + const LoopVectorizeHints &LH) { + emitOptimizationRemarkMissed(F->getContext(), DEBUG_TYPE, *F, + L->getStartLoc(), LH.emitRemark()); + + if (LH.getForce() == LoopVectorizeHints::FK_Enabled) { + if (LH.getWidth() != 1) + emitLoopVectorizeWarning( + F->getContext(), *F, L->getStartLoc(), + "failed explicitly specified loop vectorization"); + else if (LH.getUnroll() != 1) + emitLoopInterleaveWarning( + F->getContext(), *F, L->getStartLoc(), + "failed explicitly specified loop interleaving"); + } +} + static void addInnerLoop(Loop &L, SmallVectorImpl &V) { if (L.empty()) return V.push_back(&L); @@ -1241,8 +1258,7 @@ struct LoopVectorize : public FunctionPass { LoopVectorizationLegality LVL(L, SE, DL, DT, TLI, F); if (!LVL.canVectorize()) { DEBUG(dbgs() << "LV: Not vectorizing: Cannot prove legality.\n"); - emitOptimizationRemarkMissed(F->getContext(), DEBUG_TYPE, *F, - L->getStartLoc(), Hints.emitRemark()); + emitMissedWarning(F, L, Hints); return false; } @@ -1276,8 +1292,7 @@ struct LoopVectorize : public FunctionPass { emitOptimizationRemarkAnalysis( F->getContext(), DEBUG_TYPE, *F, L->getStartLoc(), "loop not vectorized due to NoImplicitFloat attribute"); - emitOptimizationRemarkMissed(F->getContext(), DEBUG_TYPE, *F, - L->getStartLoc(), Hints.emitRemark()); + emitMissedWarning(F, L, Hints); return false; } diff --git a/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll b/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll index 6cdd29bda23..909dbf57cfb 100644 --- a/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll +++ b/test/Transforms/LoopVectorize/X86/vectorization-remarks-missed.ll @@ -28,6 +28,7 @@ ; CHECK: remark: source.cpp:13:5: loop not vectorized: vector width and interleave count are explicitly set to 1 ; CHECK: remark: source.cpp:19:5: loop not vectorized: cannot identify array bounds ; CHECK: remark: source.cpp:19:5: loop not vectorized: vectorization is explicitly enabled +; CHECK: warning: source.cpp:19:5: loop not vectorized: failed explicitly specified loop vectorization ; CHECK: _Z4testPii ; CHECK-NOT: x i32> diff --git a/test/Transforms/LoopVectorize/no_array_bounds.ll b/test/Transforms/LoopVectorize/no_array_bounds.ll new file mode 100644 index 00000000000..240b1b5d49d --- /dev/null +++ b/test/Transforms/LoopVectorize/no_array_bounds.ll @@ -0,0 +1,101 @@ +; RUN: opt < %s -loop-vectorize -S 2>&1 | FileCheck %s + +; Verify warning is generated when vectorization/ interleaving is explicitly specified and fails to occur. +; CHECK: warning: no_array_bounds.cpp:5:5: loop not vectorized: failed explicitly specified loop vectorization +; CHECK: warning: no_array_bounds.cpp:10:5: loop not interleaved: failed explicitly specified loop interleaving + +; #pragma clang loop vectorize(enable) +; for (int i = 0; i < number; i++) { +; A[B[i]]++; +; } + +; #pragma clang loop vectorize(disable) interleave(enable) +; for (int i = 0; i < number; i++) { +; B[A[i]]++; +; } + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +; Function Attrs: nounwind ssp uwtable +define void @_Z4testPiS_i(i32* nocapture %A, i32* nocapture %B, i32 %number) #0 { +entry: + %cmp25 = icmp sgt i32 %number, 0, !dbg !10 + br i1 %cmp25, label %for.body.preheader, label %for.end15, !dbg !10, !llvm.loop !12 + +for.body.preheader: ; preds = %entry + br label %for.body, !dbg !14 + +for.cond5.preheader: ; preds = %for.body + br i1 %cmp25, label %for.body7.preheader, label %for.end15, !dbg !16, !llvm.loop !18 + +for.body7.preheader: ; preds = %for.cond5.preheader + br label %for.body7, !dbg !20 + +for.body: ; preds = %for.body.preheader, %for.body + %indvars.iv27 = phi i64 [ %indvars.iv.next28, %for.body ], [ 0, %for.body.preheader ] + %arrayidx = getelementptr inbounds i32* %B, i64 %indvars.iv27, !dbg !14 + %0 = load i32* %arrayidx, align 4, !dbg !14, !tbaa !22 + %idxprom1 = sext i32 %0 to i64, !dbg !14 + %arrayidx2 = getelementptr inbounds i32* %A, i64 %idxprom1, !dbg !14 + %1 = load i32* %arrayidx2, align 4, !dbg !14, !tbaa !22 + %inc = add nsw i32 %1, 1, !dbg !14 + store i32 %inc, i32* %arrayidx2, align 4, !dbg !14, !tbaa !22 + %indvars.iv.next28 = add nuw nsw i64 %indvars.iv27, 1, !dbg !10 + %lftr.wideiv29 = trunc i64 %indvars.iv.next28 to i32, !dbg !10 + %exitcond30 = icmp eq i32 %lftr.wideiv29, %number, !dbg !10 + br i1 %exitcond30, label %for.cond5.preheader, label %for.body, !dbg !10, !llvm.loop !12 + +for.body7: ; preds = %for.body7.preheader, %for.body7 + %indvars.iv = phi i64 [ %indvars.iv.next, %for.body7 ], [ 0, %for.body7.preheader ] + %arrayidx9 = getelementptr inbounds i32* %A, i64 %indvars.iv, !dbg !20 + %2 = load i32* %arrayidx9, align 4, !dbg !20, !tbaa !22 + %idxprom10 = sext i32 %2 to i64, !dbg !20 + %arrayidx11 = getelementptr inbounds i32* %B, i64 %idxprom10, !dbg !20 + %3 = load i32* %arrayidx11, align 4, !dbg !20, !tbaa !22 + %inc12 = add nsw i32 %3, 1, !dbg !20 + store i32 %inc12, i32* %arrayidx11, align 4, !dbg !20, !tbaa !22 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !16 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32, !dbg !16 + %exitcond = icmp eq i32 %lftr.wideiv, %number, !dbg !16 + br i1 %exitcond, label %for.end15.loopexit, label %for.body7, !dbg !16, !llvm.loop !18 + +for.end15.loopexit: ; preds = %for.body7 + br label %for.end15 + +for.end15: ; preds = %for.end15.loopexit, %entry, %for.cond5.preheader + ret void, !dbg !26 +} + +attributes #0 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8} +!llvm.ident = !{!9} + +!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.5.0", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !"", i32 2} +!1 = metadata !{metadata !"no_array_bounds.cpp", metadata !"."} +!2 = metadata !{} +!3 = metadata !{metadata !4} +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"test", metadata !"test", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 true, void (i32*, i32*, i32)* @_Z4testPiS_i, null, null, metadata !2, i32 2} +!5 = metadata !{i32 786473, metadata !1} +!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} +!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 2} +!8 = metadata !{i32 2, metadata !"Debug Info Version", i32 1} +!9 = metadata !{metadata !"clang version 3.5.0"} +!10 = metadata !{i32 4, i32 8, metadata !11, null} +!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 4, i32 3, i32 0, i32 0} +!12 = metadata !{metadata !12, metadata !13} +!13 = metadata !{metadata !"llvm.loop.vectorize.enable", i1 true} +!14 = metadata !{i32 5, i32 5, metadata !15, null} +!15 = metadata !{i32 786443, metadata !1, metadata !11, i32 4, i32 36, i32 0, i32 1} +!16 = metadata !{i32 9, i32 8, metadata !17, null} +!17 = metadata !{i32 786443, metadata !1, metadata !4, i32 9, i32 3, i32 0, i32 2} +!18 = metadata !{metadata !18, metadata !13, metadata !19} +!19 = metadata !{metadata !"llvm.loop.vectorize.width", i32 1} +!20 = metadata !{i32 10, i32 5, metadata !21, null} +!21 = metadata !{i32 786443, metadata !1, metadata !17, i32 9, i32 36, i32 0, i32 3} +!22 = metadata !{metadata !23, metadata !23, i64 0} +!23 = metadata !{metadata !"int", metadata !24, i64 0} +!24 = metadata !{metadata !"omnipotent char", metadata !25, i64 0} +!25 = metadata !{metadata !"Simple C/C++ TBAA"} +!26 = metadata !{i32 12, i32 1, metadata !4, null} diff --git a/test/Transforms/LoopVectorize/no_switch.ll b/test/Transforms/LoopVectorize/no_switch.ll index 52b42850f44..8f654e41d4c 100644 --- a/test/Transforms/LoopVectorize/no_switch.ll +++ b/test/Transforms/LoopVectorize/no_switch.ll @@ -2,6 +2,7 @@ ; CHECK: remark: source.cpp:4:5: loop not vectorized: loop contains a switch statement ; CHECK: remark: source.cpp:4:5: loop not vectorized: vectorization is explicitly enabled with width 4 +; CHECK: warning: source.cpp:4:5: loop not vectorized: failed explicitly specified loop vectorization ; CHECK: _Z11test_switchPii ; CHECK-NOT: x i32>