153 changes: 107 additions & 46 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2751,21 +2751,32 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
static bool CheckOpenMPIterationSpace(
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
Expr *NestedLoopCountExpr,
Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
LoopIterationSpace &ResultIterSpace) {
// 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)
<< (NestedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind)
<< NestedLoopCount << (CurrentNestedLoopCount > 0)
<< CurrentNestedLoopCount;
if (NestedLoopCount > 1)
SemaRef.Diag(NestedLoopCountExpr->getExprLoc(),
diag::note_omp_collapse_expr)
<< NestedLoopCountExpr->getSourceRange();
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << NestedLoopCount
<< (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
if (NestedLoopCount > 1) {
if (CollapseLoopCountExpr && OrderedLoopCountExpr)
SemaRef.Diag(DSA.getConstructLoc(),
diag::note_omp_collapse_ordered_expr)
<< 2 << CollapseLoopCountExpr->getSourceRange()
<< OrderedLoopCountExpr->getSourceRange();
else if (CollapseLoopCountExpr)
SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(),
diag::note_omp_collapse_ordered_expr)
<< 0 << CollapseLoopCountExpr->getSourceRange();
else
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
diag::note_omp_collapse_ordered_expr)
<< 1 << OrderedLoopCountExpr->getSourceRange();
}
return true;
}
assert(For->getBody());
Expand Down Expand Up @@ -2840,7 +2851,8 @@ static bool CheckOpenMPIterationSpace(
} else if (LoopVarRefExpr != nullptr) {
// Make the loop iteration variable private (for worksharing constructs),
// linear (for simd directives with the only one associated loop) or
// lastprivate (for simd directives with several collapsed loops).
// lastprivate (for simd directives with several collapsed or ordered
// loops).
if (DVar.CKind == OMPC_unknown)
DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(),
/*FromParent=*/false);
Expand Down Expand Up @@ -2942,16 +2954,23 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
/// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
/// number of collapsed loops otherwise.
static unsigned
CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA,
CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef,
DSAStackTy &DSA,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
OMPLoopDirective::HelperExprs &Built) {
unsigned NestedLoopCount = 1;
if (NestedLoopCountExpr) {
if (CollapseLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
llvm::APSInt Result;
if (NestedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
NestedLoopCount = Result.getLimitedValue();
if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
NestedLoopCount += Result.getLimitedValue() - 1;
}
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
llvm::APSInt Result;
if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
NestedLoopCount += Result.getLimitedValue() - 1;
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
Expand All @@ -2960,8 +2979,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
NestedLoopCount, NestedLoopCountExpr,
VarsWithImplicitDSA, IterSpaces[Cnt]))
NestedLoopCount, CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA,
IterSpaces[Cnt]))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
Expand All @@ -2978,11 +2998,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,

// An example of what is generated for the following code:
//
// #pragma omp simd collapse(2)
// #pragma omp simd collapse(2) ordered(2)
// for (i = 0; i < NI; ++i)
// for (j = J0; j < NJ; j+=2) {
// <loop body>
// }
// for (k = 0; k < NK; ++k)
// for (j = J0; j < NJ; j+=2) {
// <loop body>
// }
//
// We generate the code below.
// Note: the loop body may be outlined in CodeGen.
Expand Down Expand Up @@ -3292,7 +3313,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
return NestedLoopCount;
}

static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
auto &&CollapseFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_collapse;
};
Expand All @@ -3303,15 +3324,27 @@ static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
return nullptr;
}

static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) {
auto &&OrderedFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_ordered;
};
OMPExecutableDirective::filtered_clause_iterator<decltype(OrderedFilter)> I(
Clauses, std::move(OrderedFilter));
if (I)
return cast<OMPOrderedClause>(*I)->getNumForLoops();
return nullptr;
}

StmtResult Sema::ActOnOpenMPSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this,
*DSAStack, VarsWithImplicitDSA, B);
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();

Expand All @@ -3338,10 +3371,11 @@ StmtResult Sema::ActOnOpenMPForDirective(
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this,
*DSAStack, VarsWithImplicitDSA, B);
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();

Expand All @@ -3358,10 +3392,12 @@ StmtResult Sema::ActOnOpenMPForSimdDirective(
SourceLocation EndLoc,
llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_for_simd, GetCollapseNumberExpr(Clauses), AStmt,
*this, *DSAStack, VarsWithImplicitDSA, B);
CheckOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();

Expand Down Expand Up @@ -3490,10 +3526,12 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
CS->getCapturedDecl()->setNothrow();

OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt,
*this, *DSAStack, VarsWithImplicitDSA, B);
CheckOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();

Expand All @@ -3519,10 +3557,12 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
CS->getCapturedDecl()->setNothrow();

OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_parallel_for_simd, GetCollapseNumberExpr(Clauses),
AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
CheckOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();

Expand Down Expand Up @@ -4426,6 +4466,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_collapse:
Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
case OMPC_default:
case OMPC_proc_bind:
case OMPC_schedule:
Expand All @@ -4438,7 +4481,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
Expand Down Expand Up @@ -4588,7 +4630,11 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
return ExprError();
}
if (CKind == OMPC_collapse) {
DSAStack->setCollapseNumber(Result.getExtValue());
DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
Result.getExtValue());
} else if (CKind == OMPC_ordered) {
DSAStack->setCollapseNumber(DSAStack->getCollapseNumber() - 1 +
Result.getExtValue());
}
return ICE;
}
Expand Down Expand Up @@ -4623,6 +4669,27 @@ OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc,
SourceLocation LParenLoc,
Expr *NumForLoops) {
DSAStack->setOrderedRegion();
// OpenMP [2.7.1, loop construct, Description]
// OpenMP [2.8.1, simd construct, Description]
// OpenMP [2.9.6, distribute construct, Description]
// The parameter of the ordered clause must be a constant
// positive integer expression if any.
if (NumForLoops && LParenLoc.isValid()) {
ExprResult NumForLoopsResult =
VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_ordered);
if (NumForLoopsResult.isInvalid())
return nullptr;
NumForLoops = NumForLoopsResult.get();
}
return new (Context)
OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPSimpleClause(
OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
Expand Down Expand Up @@ -4915,12 +4982,6 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
return Res;
}

OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
DSAStack->setOrderedRegion();
return new (Context) OMPOrderedClause(StartLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
DSAStack->setNowaitRegion();
Expand Down
20 changes: 18 additions & 2 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,16 @@ class TreeTransform {
Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
}

/// \brief Build a new OpenMP 'ordered' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc,
SourceLocation LParenLoc, Expr *Num) {
return getSema().ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Num);
}

/// \brief Build a new OpenMP 'private' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
Expand Down Expand Up @@ -7237,8 +7247,14 @@ TreeTransform<Derived>::TransformOMPScheduleClause(OMPScheduleClause *C) {
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPOrderedClause(OMPOrderedClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
ExprResult E;
if (auto *Num = C->getNumForLoops()) {
E = getDerived().TransformExpr(Num);
if (E.isInvalid())
return nullptr;
}
return getDerived().RebuildOMPOrderedClause(C->getLocStart(), C->getLocEnd(),
C->getLParenLoc(), E.get());
}

template <typename Derived>
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1845,7 +1845,10 @@ void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
}

void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *) {}
void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) {
C->setNumForLoops(Reader->Reader.ReadSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
}

void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,10 @@ void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
}

void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *) {}
void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) {
Writer->Writer.AddStmt(C->getNumForLoops());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
}

void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {}

Expand Down
14 changes: 12 additions & 2 deletions clang/test/OpenMP/for_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,25 @@ T tmain(T argc) {
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered nowait
#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered nowait
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
Expand Down
104 changes: 104 additions & 0 deletions clang/test/OpenMP/for_ordered_clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// RUN: %clang_cc1 -verify -fopenmp %s

void foo() {
}

bool foobool(int argc) {
return argc;
}

struct S1; // expected-note {{declared here}}

template <class T, typename S, int N, int ST> // expected-note {{declared here}}
T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
#pragma omp for ordered
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered() // expected-error {{expected expression}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
// expected-error@+2 2 {{expression is not an integral constant expression}}
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp for ordered(argc
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
#pragma omp for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(1)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'ordered' clause}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(1)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
for (T i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for'}}
return argc;
}

int main(int argc, char **argv) {
#pragma omp for ordered
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp for ordered() // expected-error {{expected expression}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp for ordered(4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'ordered' clause}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp for', but found only 1}}
#pragma omp for ordered(2 + 2)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}} expected-note {{as specified in 'ordered' clause}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp for', but found only 1}}
#pragma omp for ordered(foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'ordered' clause}}
// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
#pragma omp for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp for ordered(S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+1 {{expression is not an integral constant expression}}
#pragma omp for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{statement after '#pragma omp for' must be a for loop}}
// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
#pragma omp for ordered(ordered(tmain < int, char, -1, -2 > (argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
foo();
#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp for'}}
// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
return tmain<int, char, 1, 0>(argc, argv);
}

14 changes: 12 additions & 2 deletions clang/test/OpenMP/parallel_for_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,24 @@ T tmain(T argc) {
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered if (argc) num_threads(N) default(shared) shared(e) reduction(+ : h)
#pragma omp parallel for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) if (argc) num_threads(N) default(shared) shared(e) reduction(+ : h)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
for (int j = 0; j < 10; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered if(argc) num_threads(N) default(shared) shared(e) reduction(+: h)
// CHECK-NEXT: #pragma omp parallel for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) if(argc) num_threads(N) default(shared) shared(e) reduction(+: h)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
Expand Down
104 changes: 104 additions & 0 deletions clang/test/OpenMP/parallel_for_ordered_messages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// RUN: %clang_cc1 -verify -fopenmp %s

void foo() {
}

bool foobool(int argc) {
return argc;
}

struct S1; // expected-note {{declared here}}

template <class T, typename S, int N, int ST> // expected-note {{declared here}}
T tmain(T argc, S **argv) { //expected-note 2 {{declared here}}
#pragma omp parallel for ordered
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered() // expected-error {{expected expression}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}}
// expected-error@+2 2 {{expression is not an integral constant expression}}
// expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}}
#pragma omp parallel for ordered(argc
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
#pragma omp parallel for ordered(ST // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(1)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered((ST > 0) ? 1 + ST : 2) // expected-note 2 {{as specified in 'ordered' clause}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST]; // expected-error 2 {{expected 2 for loops after '#pragma omp parallel for', but found only 1}}
// expected-error@+3 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
// expected-error@+2 2 {{argument to 'ordered' clause must be a positive integer value}}
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+1 2 {{expression is not an integral constant expression}}
#pragma omp parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(1)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(N) // expected-error {{argument to 'ordered' clause must be a positive integer value}}
for (T i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp parallel for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for'}}
return argc;
}

int main(int argc, char **argv) {
#pragma omp parallel for ordered
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp parallel for ordered( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp parallel for ordered() // expected-error {{expected expression}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp parallel for ordered(4 // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{as specified in 'ordered' clause}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp parallel for', but found only 1}}
#pragma omp parallel for ordered(2 + 2)) // expected-warning {{extra tokens at the end of '#pragma omp parallel for' are ignored}} expected-note {{as specified in 'ordered' clause}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4]; // expected-error {{expected 4 for loops after '#pragma omp parallel for', but found only 1}}
#pragma omp parallel for ordered(foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{expression is not an integral constant expression}}
// expected-error@+2 2 {{directive '#pragma omp parallel for' cannot contain more than one 'ordered' clause}}
// expected-error@+1 2 {{argument to 'ordered' clause must be a positive integer value}}
#pragma omp parallel for ordered(foobool(argc)), ordered(true), ordered(-5)
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
#pragma omp parallel for ordered(S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+1 {{expression is not an integral constant expression}}
#pragma omp parallel for ordered(argv[1] = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = 4; i < 12; i++)
argv[0][i] = argv[0][i] - argv[0][i - 4];
// expected-error@+3 {{statement after '#pragma omp parallel for' must be a for loop}}
// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
#pragma omp parallel for ordered(ordered(tmain < int, char, -1, -2 > (argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}}
foo();
#pragma omp parallel for ordered(2) // expected-note {{as specified in 'ordered' clause}}
foo(); // expected-error {{expected 2 for loops after '#pragma omp parallel for'}}
// expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, 1, 0>' requested here}}
return tmain<int, char, 1, 0>(argc, argv);
}

4 changes: 3 additions & 1 deletion clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,9 @@ void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) {
Visitor->AddStmt(C->getHelperChunkSize());
}

void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *) {}
void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) {
Visitor->AddStmt(C->getNumForLoops());
}

void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *) {}

Expand Down