r210095 - [OPENMP] Loop canonical form analysis (Sema)
Alexander Musman
alexander.musman at gmail.com
Tue Jun 3 03:16:48 PDT 2014
Author: amusman
Date: Tue Jun 3 05:16:47 2014
New Revision: 210095
URL: http://llvm.org/viewvc/llvm-project?rev=210095&view=rev
Log:
[OPENMP] Loop canonical form analysis (Sema)
This patch implements semantic analysis to make sure that the loop is in OpenMP canonical form.
This is the form required for 'omp simd', 'omp for' and other loop pragmas.
Differential revision: http://reviews.llvm.org/D3778
Added:
cfe/trunk/test/OpenMP/simd_loop_messages.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Scope.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseOpenMP.cpp
cfe/trunk/lib/Sema/Scope.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOpenMP.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/OpenMP/simd_misc_messages.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Jun 3 05:16:47 2014
@@ -678,6 +678,7 @@ def ASM : DiagGroup<"asm", [
// OpenMP warnings.
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
def OpenMPClauses : DiagGroup<"openmp-clauses">;
+def OpenMPLoopForm : DiagGroup<"openmp-loop-form">;
// Backend warnings.
def BackendInlineAsm : DiagGroup<"inline-asm">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jun 3 05:16:47 2014
@@ -6937,6 +6937,8 @@ def note_omp_explicit_dsa : Note<
"defined as %0">;
def note_omp_predetermined_dsa : Note<
"predetermined as %0">;
+def err_omp_loop_var_dsa : Error<
+ "loop iteration variable may not be %0">;
def err_omp_not_for : Error<
"statement after '#pragma omp %0' must be a for loop">;
def err_omp_negative_expression_in_clause : Error<
@@ -6973,6 +6975,29 @@ def err_omp_aligned_twice : Error<
"a variable cannot appear in more than one aligned clause">;
def err_omp_local_var_in_threadprivate_init : Error<
"variable with local storage in initial value of threadprivate variable">;
+def err_omp_loop_not_canonical_init : Error<
+ "initialization clause of OpenMP for loop must be of the form "
+ "'var = init' or 'T var = init'">;
+def ext_omp_loop_not_canonical_init : ExtWarn<
+ "initialization clause of OpenMP for loop is not in canonical form "
+ "('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>;
+def err_omp_loop_not_canonical_cond : Error<
+ "condition of OpenMP for loop must be a relational comparison "
+ "('<', '<=', '>', or '>=') of loop variable %0">;
+def err_omp_loop_not_canonical_incr : Error<
+ "increment clause of OpenMP for loop must perform simple addition "
+ "or subtraction on loop variable %0">;
+def err_omp_loop_variable_type : Error<
+ "variable must be of integer or %select{pointer|random access iterator}0 type">;
+def err_omp_loop_incr_not_compatible : Error<
+ "increment expression must cause %0 to %select{decrease|increase}1 "
+ "on each iteration of OpenMP for loop">;
+def note_omp_loop_cond_requres_compatible_incr : Note<
+ "loop step is expected to be %select{negative|positive}0 due to this condition">;
+def err_omp_loop_cannot_use_stmt : Error<
+ "'%0' statement cannot be used in OpenMP for loop">;
+def err_omp_simd_region_cannot_use_stmt : Error<
+ "'%0' statement cannot be used in OpenMP simd region">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
Modified: cfe/trunk/include/clang/Sema/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Scope.h (original)
+++ cfe/trunk/include/clang/Sema/Scope.h Tue Jun 3 05:16:47 2014
@@ -101,22 +101,30 @@ public:
/// \brief This is the scope for a function-level C++ try or catch scope.
FnTryCatchScope = 0x4000,
- /// \brief This is the scope of OpenMP executable directive
- OpenMPDirectiveScope = 0x8000
+ /// \brief This is the scope of OpenMP executable directive.
+ OpenMPDirectiveScope = 0x8000,
+
+ /// \brief This is the scope of some OpenMP loop directive.
+ OpenMPLoopDirectiveScope = 0x10000,
+
+ /// \brief This is the scope of some OpenMP simd directive.
+ /// For example, it is used for 'omp simd', 'omp for simd'.
+ /// This flag is propagated to children scopes.
+ OpenMPSimdDirectiveScope = 0x20000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
/// scope.
Scope *AnyParent;
+ /// Flags - This contains a set of ScopeFlags, which indicates how the scope
+ /// interrelates with other control flow statements.
+ unsigned Flags;
+
/// Depth - This is the depth of this scope. The translation-unit scope has
/// depth 0.
unsigned short Depth;
- /// Flags - This contains a set of ScopeFlags, which indicates how the scope
- /// interrelates with other control flow statements.
- unsigned short Flags;
-
/// \brief Declarations with static linkage are mangled with the number of
/// scopes seen as a component.
unsigned short MSLocalManglingNumber;
@@ -360,6 +368,30 @@ public:
return (getFlags() & Scope::OpenMPDirectiveScope);
}
+ /// \brief Determine whether this scope is some OpenMP loop directive scope
+ /// (for example, 'omp for', 'omp simd').
+ bool isOpenMPLoopDirectiveScope() const {
+ if (getFlags() & Scope::OpenMPLoopDirectiveScope) {
+ assert(isOpenMPDirectiveScope() &&
+ "OpenMP loop directive scope is not a directive scope");
+ return true;
+ }
+ return false;
+ }
+
+ /// \brief Determine whether this scope is (or is nested into) some OpenMP
+ /// loop simd directive scope (for example, 'omp simd', 'omp for simd').
+ bool isOpenMPSimdDirectiveScope() const {
+ return getFlags() & Scope::OpenMPSimdDirectiveScope;
+ }
+
+ /// \brief Determine whether this scope is a loop having OpenMP loop
+ /// directive attached.
+ bool isOpenMPLoopScope() const {
+ const Scope *P = getParent();
+ return P && P->isOpenMPLoopDirectiveScope();
+ }
+
/// \brief Determine whether this scope is a C++ 'try' block.
bool isTryScope() const { return getFlags() & Scope::TryScope; }
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Jun 3 05:16:47 2014
@@ -7258,10 +7258,11 @@ private:
/// \brief Initialization of data-sharing attributes stack.
void InitDataSharingAttributesStack();
void DestroyDataSharingAttributesStack();
- ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op);
ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
OpenMPClauseKind CKind);
public:
+ ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
+ Expr *Op);
/// \brief Called on start of new data sharing attribute block.
void StartOpenMPDSABlock(OpenMPDirectiveKind K,
const DeclarationNameInfo &DirName,
Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Tue Jun 3 05:16:47 2014
@@ -86,7 +86,7 @@ StmtResult Parser::ParseOpenMPDeclarativ
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
FirstClauses(OMPC_unknown + 1);
- const unsigned ScopeFlags =
+ unsigned ScopeFlags =
Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
SourceLocation Loc = ConsumeToken(), EndLoc;
OpenMPDirectiveKind DKind = Tok.isAnnotation()
@@ -142,6 +142,9 @@ StmtResult Parser::ParseOpenMPDeclarativ
StmtResult AssociatedStmt;
bool CreateDirective = true;
+ if (DKind == OMPD_simd)
+ ScopeFlags |=
+ Scope::OpenMPLoopDirectiveScope | Scope::OpenMPSimdDirectiveScope;
ParseScope OMPDirectiveScope(this, ScopeFlags);
{
// The body is a block scope like in Lambdas and Blocks.
Modified: cfe/trunk/lib/Sema/Scope.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Scope.cpp?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Scope.cpp (original)
+++ cfe/trunk/lib/Sema/Scope.cpp Tue Jun 3 05:16:47 2014
@@ -39,6 +39,10 @@ void Scope::Init(Scope *parent, unsigned
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
MSLocalManglingParent = parent->MSLocalManglingParent;
+ if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
+ FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
+ 0)
+ Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
} else {
Depth = 0;
PrototypeDepth = 0;
@@ -178,6 +182,12 @@ void Scope::dumpImpl(raw_ostream &OS) co
} else if (Flags & OpenMPDirectiveScope) {
OS << "OpenMPDirectiveScope";
Flags &= ~OpenMPDirectiveScope;
+ } else if (Flags & OpenMPLoopDirectiveScope) {
+ OS << "OpenMPLoopDirectiveScope";
+ Flags &= ~OpenMPLoopDirectiveScope;
+ } else if (Flags & OpenMPSimdDirectiveScope) {
+ OS << "OpenMPSimdDirectiveScope";
+ Flags &= ~OpenMPSimdDirectiveScope;
}
if (Flags)
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jun 3 05:16:47 2014
@@ -618,7 +618,10 @@ ExprResult Sema::BuildCXXThrow(SourceLoc
if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-
+
+ if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+ Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
+
if (Ex && !Ex->isTypeDependent()) {
ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Tue Jun 3 05:16:47 2014
@@ -832,22 +832,497 @@ StmtResult Sema::ActOnOpenMPParallelDire
AStmt);
}
+namespace {
+/// \brief Helper class for checking canonical form of the OpenMP loops and
+/// extracting iteration space of each loop in the loop nest, that will be used
+/// for IR generation.
+class OpenMPIterationSpaceChecker {
+ /// \brief Reference to Sema.
+ Sema &SemaRef;
+ /// \brief A location for diagnostics (when there is no some better location).
+ SourceLocation DefaultLoc;
+ /// \brief A location for diagnostics (when increment is not compatible).
+ SourceLocation ConditionLoc;
+ /// \brief A source location for referring to condition later.
+ SourceRange ConditionSrcRange;
+ /// \brief Loop variable.
+ VarDecl *Var;
+ /// \brief Lower bound (initializer for the var).
+ Expr *LB;
+ /// \brief Upper bound.
+ Expr *UB;
+ /// \brief Loop step (increment).
+ Expr *Step;
+ /// \brief This flag is true when condition is one of:
+ /// Var < UB
+ /// Var <= UB
+ /// UB > Var
+ /// UB >= Var
+ bool TestIsLessOp;
+ /// \brief This flag is true when condition is strict ( < or > ).
+ bool TestIsStrictOp;
+ /// \brief This flag is true when step is subtracted on each iteration.
+ bool SubtractStep;
+
+public:
+ OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
+ : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
+ ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr),
+ UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false),
+ SubtractStep(false) {}
+ /// \brief Check init-expr for canonical loop form and save loop counter
+ /// variable - #Var and its initialization value - #LB.
+ bool CheckInit(Stmt *S);
+ /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags
+ /// for less/greater and for strict/non-strict comparison.
+ bool CheckCond(Expr *S);
+ /// \brief Check incr-expr for canonical loop form and return true if it
+ /// does not conform, otherwise save loop step (#Step).
+ bool CheckInc(Expr *S);
+ /// \brief Return the loop counter variable.
+ VarDecl *GetLoopVar() const { return Var; }
+ /// \brief Return true if any expression is dependent.
+ bool Dependent() const;
+
+private:
+ /// \brief Check the right-hand side of an assignment in the increment
+ /// expression.
+ bool CheckIncRHS(Expr *RHS);
+ /// \brief Helper to set loop counter variable and its initializer.
+ bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB);
+ /// \brief Helper to set upper bound.
+ bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR,
+ const SourceLocation &SL);
+ /// \brief Helper to set loop increment.
+ bool SetStep(Expr *NewStep, bool Subtract);
+};
+
+bool OpenMPIterationSpaceChecker::Dependent() const {
+ if (!Var) {
+ assert(!LB && !UB && !Step);
+ return false;
+ }
+ return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) ||
+ (UB && UB->isValueDependent()) || (Step && Step->isValueDependent());
+}
+
+bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) {
+ // State consistency checking to ensure correct usage.
+ assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr &&
+ !TestIsLessOp && !TestIsStrictOp);
+ if (!NewVar || !NewLB)
+ return true;
+ Var = NewVar;
+ LB = NewLB;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp,
+ const SourceRange &SR,
+ const SourceLocation &SL) {
+ // State consistency checking to ensure correct usage.
+ assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr &&
+ !TestIsLessOp && !TestIsStrictOp);
+ if (!NewUB)
+ return true;
+ UB = NewUB;
+ TestIsLessOp = LessOp;
+ TestIsStrictOp = StrictOp;
+ ConditionSrcRange = SR;
+ ConditionLoc = SL;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
+ // State consistency checking to ensure correct usage.
+ assert(Var != nullptr && LB != nullptr && Step == nullptr);
+ if (!NewStep)
+ return true;
+ if (!NewStep->isValueDependent()) {
+ // Check that the step is integer expression.
+ SourceLocation StepLoc = NewStep->getLocStart();
+ ExprResult Val =
+ SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep);
+ if (Val.isInvalid())
+ return true;
+ NewStep = Val.get();
+
+ // OpenMP [2.6, Canonical Loop Form, Restrictions]
+ // If test-expr is of form var relational-op b and relational-op is < or
+ // <= then incr-expr must cause var to increase on each iteration of the
+ // loop. If test-expr is of form var relational-op b and relational-op is
+ // > or >= then incr-expr must cause var to decrease on each iteration of
+ // the loop.
+ // If test-expr is of form b relational-op var and relational-op is < or
+ // <= then incr-expr must cause var to decrease on each iteration of the
+ // loop. If test-expr is of form b relational-op var and relational-op is
+ // > or >= then incr-expr must cause var to increase on each iteration of
+ // the loop.
+ llvm::APSInt Result;
+ bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context);
+ bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
+ bool IsConstNeg =
+ IsConstant && Result.isSigned() && (Subtract != Result.isNegative());
+ bool IsConstZero = IsConstant && !Result.getBoolValue();
+ if (UB && (IsConstZero ||
+ (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (!IsConstNeg || (IsUnsigned && !Subtract))))) {
+ SemaRef.Diag(NewStep->getExprLoc(),
+ diag::err_omp_loop_incr_not_compatible)
+ << Var << TestIsLessOp << NewStep->getSourceRange();
+ SemaRef.Diag(ConditionLoc,
+ diag::note_omp_loop_cond_requres_compatible_incr)
+ << TestIsLessOp << ConditionSrcRange;
+ return true;
+ }
+ }
+
+ Step = NewStep;
+ SubtractStep = Subtract;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
+ // Check init-expr for canonical loop form and save loop counter
+ // variable - #Var and its initialization value - #LB.
+ // OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
+ // var = lb
+ // integer-type var = lb
+ // random-access-iterator-type var = lb
+ // pointer-type var = lb
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
+ return true;
+ }
+ if (Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+ if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ if (BO->getOpcode() == BO_Assign)
+ if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS());
+ } else if (auto DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl()) {
+ if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
+ if (Var->hasInit()) {
+ // Accept non-canonical init form here but emit ext. warning.
+ if (Var->getInitStyle() != VarDecl::CInit)
+ SemaRef.Diag(S->getLocStart(),
+ diag::ext_omp_loop_not_canonical_init)
+ << S->getSourceRange();
+ return SetVarAndLB(Var, Var->getInit());
+ }
+ }
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S))
+ if (CE->getOperator() == OO_Equal)
+ if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1));
+
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
+ << S->getSourceRange();
+ return true;
+}
+
+/// \brief Ignore parenthesises, implicit casts, copy constructor and return the
+/// variable (which may be the loop variable) if possible.
+static const VarDecl *GetInitVarDecl(const Expr *E) {
+ if (!E)
+ return 0;
+ E = E->IgnoreParenImpCasts();
+ if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(E))
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor())
+ if (Ctor->isCopyConstructor() && CE->getNumArgs() == 1 &&
+ CE->getArg(0) != nullptr)
+ E = CE->getArg(0)->IgnoreParenImpCasts();
+ auto DRE = dyn_cast_or_null<DeclRefExpr>(E);
+ if (!DRE)
+ return nullptr;
+ return dyn_cast<VarDecl>(DRE->getDecl());
+}
+
+bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
+ // Check test-expr for canonical form, save upper-bound UB, flags for
+ // less/greater and for strict/non-strict comparison.
+ // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // var relational-op b
+ // b relational-op var
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var;
+ return true;
+ }
+ S = S->IgnoreParenImpCasts();
+ SourceLocation CondLoc = S->getLocStart();
+ if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ if (BO->isRelationalOp()) {
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetUB(BO->getRHS(),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+ BO->getSourceRange(), BO->getOperatorLoc());
+ if (GetInitVarDecl(BO->getRHS()) == Var)
+ return SetUB(BO->getLHS(),
+ (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+ BO->getSourceRange(), BO->getOperatorLoc());
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+ if (CE->getNumArgs() == 2) {
+ auto Op = CE->getOperator();
+ switch (Op) {
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_Less:
+ case OO_LessEqual:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
+ Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+ CE->getOperatorLoc());
+ if (GetInitVarDecl(CE->getArg(1)) == Var)
+ return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
+ Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+ CE->getOperatorLoc());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
+ << S->getSourceRange() << Var;
+ return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) {
+ // RHS of canonical loop form increment can be:
+ // var + incr
+ // incr + var
+ // var - incr
+ //
+ RHS = RHS->IgnoreParenImpCasts();
+ if (auto BO = dyn_cast<BinaryOperator>(RHS)) {
+ if (BO->isAdditiveOp()) {
+ bool IsAdd = BO->getOpcode() == BO_Add;
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetStep(BO->getRHS(), !IsAdd);
+ if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var)
+ return SetStep(BO->getLHS(), false);
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
+ bool IsAdd = CE->getOperator() == OO_Plus;
+ if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(CE->getArg(1), !IsAdd);
+ if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var)
+ return SetStep(CE->getArg(0), false);
+ }
+ }
+ SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+ << RHS->getSourceRange() << Var;
+ return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
+ // Check incr-expr for canonical loop form and return true if it
+ // does not conform.
+ // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // ++var
+ // var++
+ // --var
+ // var--
+ // var += incr
+ // var -= incr
+ // var = var + incr
+ // var = incr + var
+ // var = var - incr
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var;
+ return true;
+ }
+ S = S->IgnoreParens();
+ if (auto UO = dyn_cast<UnaryOperator>(S)) {
+ if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var)
+ return SetStep(
+ SemaRef.ActOnIntegerConstant(UO->getLocStart(),
+ (UO->isDecrementOp() ? -1 : 1)).get(),
+ false);
+ } else if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ switch (BO->getOpcode()) {
+ case BO_AddAssign:
+ case BO_SubAssign:
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign);
+ break;
+ case BO_Assign:
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return CheckIncRHS(BO->getRHS());
+ break;
+ default:
+ break;
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+ switch (CE->getOperator()) {
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(
+ SemaRef.ActOnIntegerConstant(
+ CE->getLocStart(),
+ ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(),
+ false);
+ break;
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual);
+ break;
+ case OO_Equal:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return CheckIncRHS(CE->getArg(1));
+ break;
+ default:
+ break;
+ }
+ }
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+ << S->getSourceRange() << Var;
+ return true;
+}
+}
+
+/// \brief Called on a for stmt to check and extract its iteration space
+/// for further processing (such as collapsing).
+static bool CheckOpenMPIterationSpace(OpenMPDirectiveKind DKind, Stmt *S,
+ Sema &SemaRef, DSAStackTy &DSA) {
+ // OpenMP [2.6, Canonical Loop Form]
+ // for (init-expr; test-expr; incr-expr) structured-block
+ auto For = dyn_cast_or_null<ForStmt>(S);
+ if (!For) {
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for)
+ << getOpenMPDirectiveName(DKind);
+ return true;
+ }
+ assert(For->getBody());
+
+ OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
+
+ // Check init.
+ Stmt *Init = For->getInit();
+ if (ISC.CheckInit(Init)) {
+ return true;
+ }
+
+ bool HasErrors = false;
+
+ // Check loop variable's type.
+ VarDecl *Var = ISC.GetLoopVar();
+
+ // OpenMP [2.6, Canonical Loop Form]
+ // Var is one of the following:
+ // A variable of signed or unsigned integer type.
+ // For C++, a variable of a random access iterator type.
+ // For C, a variable of a pointer type.
+ QualType VarType = Var->getType();
+ if (!VarType->isDependentType() && !VarType->isIntegerType() &&
+ !VarType->isPointerType() &&
+ !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type)
+ << SemaRef.getLangOpts().CPlusPlus;
+ HasErrors = true;
+ }
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in
+ // a Construct, C/C++].
+ // The loop iteration variable(s) in the associated for-loop(s) of a for or
+ // parallel for construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_linear &&
+ DVar.CKind != OMPC_threadprivate) {
+ // The loop iteration variable in the associated for-loop of a simd
+ // construct with just one associated for-loop may be listed in a linear
+ // clause with a constant-linear-step that is the increment of the
+ // associated for-loop.
+ // FIXME: allow OMPC_lastprivate when it is ready.
+ assert(DKind == OMPD_simd && "DSA for non-simd loop vars");
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ if (DVar.RefExpr)
+ SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ else
+ SemaRef.Diag(Var->getLocation(), diag::note_omp_predetermined_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ HasErrors = true;
+ } else {
+ // Make the loop iteration variable private by default.
+ DSA.addDSA(Var, nullptr, OMPC_private);
+ }
+
+ // Check test-expr.
+ HasErrors |= ISC.CheckCond(For->getCond());
+
+ // Check incr-expr.
+ HasErrors |= ISC.CheckInc(For->getInc());
+
+ if (ISC.Dependent())
+ return HasErrors;
+
+ // FIXME: Build loop's iteration space representation.
+ return HasErrors;
+}
+
+/// \brief A helper routine to skip no-op (attributed, compound) stmts get the
+/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt
+/// to get the first for loop.
+static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) {
+ if (IgnoreCaptured)
+ if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+ S = CapS->getCapturedStmt();
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // All loops associated with the construct must be perfectly nested; that is,
+ // there must be no intervening code nor any OpenMP directive between any two
+ // loops.
+ while (true) {
+ if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
+ if (CS->size() != 1)
+ break;
+ S = CS->body_back();
+ } else
+ break;
+ }
+ return S;
+}
+
+/// \brief Called on a for stmt to check itself and nested loops (if any).
+static bool CheckOpenMPLoop(OpenMPDirectiveKind DKind, unsigned NestedLoopCount,
+ Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA) {
+ // This is helper routine for loop directives (e.g., 'for', 'simd',
+ // 'for simd', etc.).
+ assert(NestedLoopCount == 1);
+ Stmt *CurStmt = IgnoreContainerStmts(AStmt, true);
+ for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
+ if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA))
+ return true;
+ // Move on to the next nested for loop, or to the loop body.
+ CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false);
+ }
+
+ // FIXME: Build resulting iteration space for IR generation (collapsing
+ // iteration spaces when loop count > 1 ('collapse' clause)).
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
- Stmt *CStmt = AStmt;
- while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(CStmt))
- CStmt = CS->getCapturedStmt();
- while (AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(CStmt))
- CStmt = AS->getSubStmt();
- ForStmt *For = dyn_cast<ForStmt>(CStmt);
- if (!For) {
- Diag(CStmt->getLocStart(), diag::err_omp_not_for)
- << getOpenMPDirectiveName(OMPD_simd);
+ // In presence of clause 'collapse', it will define the nested loops number.
+ // For now, pass default value of 1.
+ if (CheckOpenMPLoop(OMPD_simd, 1, AStmt, *this, *DSAStack))
return StmtError();
- }
-
- // FIXME: Checking loop canonical form, collapsing etc.
getCurFunction()->setHasBranchProtectedScope();
return OMPSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
@@ -904,8 +1379,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(Exp
return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
-ExprResult Sema::PerformImplicitIntegerConversion(SourceLocation Loc,
- Expr *Op) {
+ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
+ Expr *Op) {
if (!Op)
return ExprError();
@@ -958,7 +1433,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsCl
!NumThreads->containsUnexpandedParameterPack()) {
SourceLocation NumThreadsLoc = NumThreads->getLocStart();
ExprResult Val =
- PerformImplicitIntegerConversion(NumThreadsLoc, NumThreads);
+ PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads);
if (Val.isInvalid())
return nullptr;
@@ -1651,7 +2126,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause
!Step->isInstantiationDependent() &&
!Step->containsUnexpandedParameterPack()) {
SourceLocation StepLoc = Step->getLocStart();
- ExprResult Val = PerformImplicitIntegerConversion(StepLoc, Step);
+ ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step);
if (Val.isInvalid())
return nullptr;
StepExpr = Val.get();
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Jun 3 05:16:47 2014
@@ -2417,6 +2417,9 @@ Sema::ActOnBreakStmt(SourceLocation Brea
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
}
+ if (S->isOpenMPLoopScope())
+ return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
+ << "break");
return new (Context) BreakStmt(BreakLoc);
}
@@ -3188,6 +3191,9 @@ StmtResult Sema::ActOnCXXTryBlock(Source
!getSourceManager().isInSystemHeader(TryLoc))
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+ if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+ Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
+
const unsigned NumHandlers = Handlers.size();
assert(NumHandlers > 0 &&
"The parser shouldn't call this if there are no handlers.");
Added: cfe/trunk/test/OpenMP/simd_loop_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_loop_messages.cpp?rev=210095&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/simd_loop_messages.cpp (added)
+++ cfe/trunk/test/OpenMP/simd_loop_messages.cpp Tue Jun 3 05:16:47 2014
@@ -0,0 +1,574 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -verify %s
+
+static int sii;
+#pragma omp threadprivate(sii)
+
+int test_iteration_spaces() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ int ii, jj, kk;
+ float fii;
+ double dii;
+ #pragma omp simd
+ for (int i = 0; i < 10; i+=1) {
+ c[i] = a[i] + b[i];
+ }
+ #pragma omp simd
+ for (char i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+ #pragma omp simd
+ for (char i = 0; i < 10; i+='\1') {
+ c[i] = a[i] + b[i];
+ }
+ #pragma omp simd
+ for (long long i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ }
+ // expected-error at +2 {{expression must have integral or unscoped enumeration type, not 'double'}}
+ #pragma omp simd
+ for (long long i = 0; i < 10; i+=1.5) {
+ c[i] = a[i] + b[i];
+ }
+ #pragma omp simd
+ for (long long i = 0; i < 'z'; i+=1u) {
+ c[i] = a[i] + b[i];
+ }
+ // expected-error at +2 {{variable must be of integer or random access iterator type}}
+ #pragma omp simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+ // expected-error at +2 {{variable must be of integer or random access iterator type}}
+ #pragma omp simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+ // expected-error at +2 {{variable must be of integer or random access iterator type}}
+ #pragma omp simd
+ for (int &ref = ii; ref < 10; ref++) {
+ }
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (int i; i < 10; i++)
+ c[i] = a[i];
+
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (int i = 0, j = 0; i < 10; ++i)
+ c[i] = a[i];
+
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (;ii < 10; ++ii)
+ c[ii] = a[ii];
+
+ // expected-warning at +3 {{expression result unused}}
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (ii + 1;ii < 10; ++ii)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (c[ii] = 0;ii < 10; ++ii)
+ c[ii] = a[ii];
+
+ // Ok to skip parenthesises.
+ #pragma omp simd
+ for (((ii)) = 0;ii < 10; ++ii)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+ #pragma omp simd
+ for (int i = 0; i; i++)
+ c[i] = a[i];
+
+ // expected-error at +3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'i'}}
+ #pragma omp simd
+ for (int i = 0; jj < kk; ii++)
+ c[i] = a[i];
+
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+ #pragma omp simd
+ for (int i = 0; !!i; i++)
+ c[i] = a[i];
+
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+ #pragma omp simd
+ for (int i = 0; i != 1; i++)
+ c[i] = a[i];
+
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'i'}}
+ #pragma omp simd
+ for (int i = 0; ; i++)
+ c[i] = a[i];
+
+ // Ok.
+ #pragma omp simd
+ for (int i = 11; i > 10; i--)
+ c[i] = a[i];
+
+ // Ok.
+ #pragma omp simd
+ for (int i = 0; i < 10; ++i)
+ c[i] = a[i];
+
+ // Ok.
+ #pragma omp simd
+ for (ii = 0; ii < 10; ++ii)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ++jj)
+ c[ii] = a[jj];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ++ ++ ii)
+ c[ii] = a[ii];
+
+ // Ok but undefined behavior (in general, cannot check that incr
+ // is really loop-invariant).
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii + ii)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{expression must have integral or unscoped enumeration type, not 'float'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii + 1.0f)
+ c[ii] = a[ii];
+
+ // Ok - step was converted to integer type.
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii + (int)1.1f)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; jj = ii + 2)
+ c[ii] = a[ii];
+
+ // expected-warning at +3 {{relational comparison result unused}}
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; jj > kk + 2)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10;)
+ c[ii] = a[ii];
+
+ // expected-warning at +3 {{expression result unused}}
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; !ii)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii ? ++ii : ++jj)
+ c[ii] = a[ii];
+
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'ii'}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii < 10)
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii + 0)
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; ii = ii + (int)(0.8 - 0.45))
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; (ii) < 10; ii-=25)
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; (ii < 10); ii-=0)
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; ii > 10; (ii+=0))
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; ii < 10; (ii) = (1-1)+(ii))
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for ((ii = 0); ii > 10; (ii-=0))
+ c[ii] = a[ii];
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'ii' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (ii = 0; (ii < 10); (ii-=0))
+ c[ii] = a[ii];
+
+ // expected-note at +2 {{defined as private}}
+ // expected-error at +2 {{loop iteration variable may not be private}}
+ #pragma omp simd private(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+ // expected-error at +3 {{unexpected OpenMP clause 'shared' in directive '#pragma omp simd'}}
+ // expected-note at +2 {{defined as shared}}
+ // expected-error at +2 {{loop iteration variable may not be shared}}
+ #pragma omp simd shared(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+ #pragma omp simd linear(ii)
+ for (ii = 0; ii < 10; ii++)
+ c[ii] = a[ii];
+
+ // TODO: Add test for lastprivate.
+
+ #pragma omp parallel
+ {
+ #pragma omp simd
+ for (sii = 0; sii < 10; sii+=1)
+ c[sii] = a[sii];
+ }
+
+ // expected-error at +2 {{statement after '#pragma omp simd' must be a for loop}}
+ #pragma omp simd
+ for (auto &item : a) {
+ item = item + 1;
+ }
+
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'i' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (unsigned i = 9; i < 10; i--) {
+ c[i] = a[i] + b[i];
+ }
+
+ int (*lb)[4] = nullptr;
+ #pragma omp simd
+ for (int (*p)[4] = lb; p < lb + 8; ++p) {
+ }
+
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (int a{0}; a<10; ++a) {
+ }
+
+ return 0;
+}
+
+// Iterators allowed in openmp for-loops.
+namespace std {
+struct random_access_iterator_tag { };
+template <class Iter> struct iterator_traits {
+ typedef typename Iter::difference_type difference_type;
+ typedef typename Iter::iterator_category iterator_category;
+};
+template <class Iter>
+typename iterator_traits<Iter>::difference_type
+distance(Iter first, Iter last) { return first - last; }
+}
+class Iter0 {
+ public:
+ Iter0() { }
+ Iter0(const Iter0 &) { }
+ Iter0 operator ++() { return *this; }
+ Iter0 operator --() { return *this; }
+ bool operator <(Iter0 a) { return true; }
+};
+int operator -(Iter0 a, Iter0 b) { return 0; }
+class Iter1 {
+ public:
+ Iter1(float f=0.0f, double d=0.0) { }
+ Iter1(const Iter1 &) { }
+ Iter1 operator ++() { return *this; }
+ Iter1 operator --() { return *this; }
+ bool operator <(Iter1 a) { return true; }
+ bool operator >=(Iter1 a) { return false; }
+};
+class GoodIter {
+ public:
+ GoodIter() { }
+ GoodIter(const GoodIter &) { }
+ GoodIter(int fst, int snd) { }
+ GoodIter &operator =(const GoodIter &that) { return *this; }
+ GoodIter &operator =(const Iter0 &that) { return *this; }
+ GoodIter &operator +=(int x) { return *this; }
+ explicit GoodIter(void *) { }
+ GoodIter operator ++() { return *this; }
+ GoodIter operator --() { return *this; }
+ bool operator !() { return true; }
+ bool operator <(GoodIter a) { return true; }
+ bool operator <=(GoodIter a) { return true; }
+ bool operator >=(GoodIter a) { return false; }
+ typedef int difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+};
+int operator -(GoodIter a, GoodIter b) { return 0; }
+GoodIter operator -(GoodIter a) { return a; }
+GoodIter operator -(GoodIter a, int v) { return GoodIter(); }
+GoodIter operator +(GoodIter a, int v) { return GoodIter(); }
+GoodIter operator -(int v, GoodIter a) { return GoodIter(); }
+GoodIter operator +(int v, GoodIter a) { return GoodIter(); }
+
+int test_with_random_access_iterator() {
+ GoodIter begin, end;
+ Iter0 begin0, end0;
+ #pragma omp simd
+ for (GoodIter I = begin; I < end; ++I)
+ ++I;
+ // expected-error at +2 {{variable must be of integer or random access iterator type}}
+ #pragma omp simd
+ for (GoodIter &I = begin; I < end; ++I)
+ ++I;
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; --I)
+ ++I;
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (GoodIter I(begin); I < end; ++I)
+ ++I;
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (GoodIter I(nullptr); I < end; ++I)
+ ++I;
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (GoodIter I(0); I < end; ++I)
+ ++I;
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (GoodIter I(1,2); I < end; ++I)
+ ++I;
+ #pragma omp simd
+ for (begin = GoodIter(0); begin < end; ++begin)
+ ++begin;
+ #pragma omp simd
+ for (begin = begin0; begin < end; ++begin)
+ ++begin;
+ // expected-error at +2 {{initialization clause of OpenMP for loop must be of the form 'var = init' or 'T var = init'}}
+ #pragma omp simd
+ for (++begin; begin < end; ++begin)
+ ++begin;
+ #pragma omp simd
+ for (begin = end; begin < end; ++begin)
+ ++begin;
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+ #pragma omp simd
+ for (GoodIter I = begin; I - I; ++I)
+ ++I;
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+ #pragma omp simd
+ for (GoodIter I = begin; begin < end; ++I)
+ ++I;
+ // expected-error at +2 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', or '>=') of loop variable 'I'}}
+ #pragma omp simd
+ for (GoodIter I = begin; !I; ++I)
+ ++I;
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; I = I + 1)
+ ++I;
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; I = I - 1)
+ ++I;
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; I = -I)
+ ++I;
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; I = 2 + I)
+ ++I;
+ // expected-error at +2 {{increment clause of OpenMP for loop must perform simple addition or subtraction on loop variable 'I'}}
+ #pragma omp simd
+ for (GoodIter I = begin; I >= end; I = 2 - I)
+ ++I;
+ #pragma omp simd
+ for (Iter0 I = begin0; I < end0; ++I)
+ ++I;
+ // Initializer is constructor without params.
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (Iter0 I; I < end0; ++I)
+ ++I;
+ Iter1 begin1, end1;
+ #pragma omp simd
+ for (Iter1 I = begin1; I < end1; ++I)
+ ++I;
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (Iter1 I = begin1; I >= end1; ++I)
+ ++I;
+ // Initializer is constructor with all default params.
+ // expected-warning at +2 {{initialization clause of OpenMP for loop is not in canonical form ('var = init' or 'T var = init')}}
+ #pragma omp simd
+ for (Iter1 I; I < end1; ++I) {
+ }
+ return 0;
+}
+
+template <typename IT, int ST> class TC {
+ public:
+ int dotest_lt(IT begin, IT end) {
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (IT I = begin; I < end; I = I + ST) {
+ ++I;
+ }
+ // expected-note at +3 {{loop step is expected to be positive due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (IT I = begin; I <= end; I += ST) {
+ ++I;
+ }
+ #pragma omp simd
+ for (IT I = begin; I < end; ++I) {
+ ++I;
+ }
+ }
+
+ static IT step() {
+ return IT(ST);
+ }
+};
+template <typename IT, int ST=0> int dotest_gt(IT begin, IT end) {
+ // expected-note at +3 2 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (IT I = begin; I >= end; I = I + ST) {
+ ++I;
+ }
+ // expected-note at +3 2 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (IT I = begin; I >= end; I += ST) {
+ ++I;
+ }
+
+ // expected-note at +3 {{loop step is expected to be negative due to this condition}}
+ // expected-error at +2 {{increment expression must cause 'I' to decrease on each iteration of OpenMP for loop}}
+ #pragma omp simd
+ for (IT I = begin; I >= end; ++I) {
+ ++I;
+ }
+
+ #pragma omp simd
+ for (IT I = begin; I < end; I+=TC<int,ST>::step()) {
+ ++I;
+ }
+}
+
+void test_with_template() {
+ GoodIter begin, end;
+ TC<GoodIter, 100> t1;
+ TC<GoodIter, -100> t2;
+ t1.dotest_lt(begin, end);
+ t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
+ dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
+ dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+}
+
+void test_loop_break() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ #pragma omp simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ break; // OK in nested loop
+ }
+ switch(i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ if (c[i] > 10)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+
+ if (c[i] > 11)
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ }
+
+ #pragma omp simd
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ c[i] = a[i] + b[i];
+ if (c[i] > 10) {
+ if (c[i] < 20) {
+ break; // OK
+ }
+ }
+ }
+ }
+}
+
+void test_loop_eh() {
+ const int N = 100;
+ float a[N], b[N], c[N];
+ #pragma omp simd
+ for (int i = 0; i < 10; i++) {
+ c[i] = a[i] + b[i];
+ try { // expected-error {{'try' statement cannot be used in OpenMP simd region}}
+ for (int j = 0; j < 10; ++j) {
+ if (a[i] > b[j])
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ catch (float f) {
+ if (f > 0.1)
+ throw a[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ return; // expected-error {{cannot return from OpenMP region}}
+ }
+ switch(i) {
+ case 1:
+ b[i]++;
+ break;
+ default:
+ break;
+ }
+ for (int j = 0; j < 10; j++) {
+ if (c[i] > 10)
+ throw c[i]; // expected-error {{'throw' statement cannot be used in OpenMP simd region}}
+ }
+ }
+ if (c[9] > 10)
+ throw c[9]; // OK
+
+ #pragma omp simd
+ for (int i = 0; i < 10; ++i) {
+ struct S {
+ void g() { throw 0; }
+ };
+ }
+}
+
Modified: cfe/trunk/test/OpenMP/simd_misc_messages.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_misc_messages.c?rev=210095&r1=210094&r2=210095&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_misc_messages.c (original)
+++ cfe/trunk/test/OpenMP/simd_misc_messages.c Tue Jun 3 05:16:47 2014
@@ -414,3 +414,18 @@ void test_firstprivate()
for (i = 0; i < 16; ++i) ;
}
+void test_loop_messages()
+{
+ float a[100], b[100], c[100];
+ // expected-error at +2 {{variable must be of integer or pointer type}}
+ #pragma omp simd
+ for (float fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+ // expected-error at +2 {{variable must be of integer or pointer type}}
+ #pragma omp simd
+ for (double fi = 0; fi < 10.0; fi++) {
+ c[(int)fi] = a[(int)fi] + b[(int)fi];
+ }
+}
+
More information about the cfe-commits
mailing list