Emit warnings if vectorization is forced and fails.

This patch modifies the existing DiagnosticInfo system to create a generic base
class that is inherited to produce diagnostic-based warnings. This is used by
the loop vectorizer to trigger a warning when vectorization is forced and
fails. Several tests have been added to verify this behavior.

Reviewed by: Arnold Schwaighofer


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213110 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tyler Nowicki 2014-07-16 00:36:00 +00:00
parent 7e752a311a
commit 77f03040d5
6 changed files with 199 additions and 28 deletions

View File

@ -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

View File

@ -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("<unknown>");
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)));
}

View File

@ -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<Loop *> &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;
}

View File

@ -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>

View File

@ -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}

View File

@ -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>