92 changes: 92 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
break;
case OMPC_default:
case OMPC_proc_bind:
case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
Expand Down Expand Up @@ -1689,6 +1690,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
Expand Down Expand Up @@ -1779,6 +1781,95 @@ OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, unsigned Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ArgumentLoc, SourceLocation CommaLoc,
SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_schedule:
Res = ActOnOpenMPScheduleClause(
static_cast<OpenMPScheduleClauseKind>(Argument), Expr, StartLoc,
LParenLoc, ArgumentLoc, CommaLoc, EndLoc);
break;
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}

OMPClause *Sema::ActOnOpenMPScheduleClause(
OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_SCHEDULE_unknown) {
std::string Values;
std::string Sep(", ");
for (unsigned i = 0; i < OMPC_SCHEDULE_unknown; ++i) {
Values += "'";
Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i);
Values += "'";
switch (i) {
case OMPC_SCHEDULE_unknown - 2:
Values += " or ";
break;
case OMPC_SCHEDULE_unknown - 1:
break;
default:
Values += Sep;
break;
}
}
Diag(KindLoc, diag::err_omp_unexpected_clause_value)
<< Values << getOpenMPClauseName(OMPC_schedule);
return nullptr;
}
Expr *ValExpr = ChunkSize;
if (ChunkSize) {
if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
!ChunkSize->isInstantiationDependent() &&
!ChunkSize->containsUnexpandedParameterPack()) {
SourceLocation ChunkSizeLoc = ChunkSize->getLocStart();
ExprResult Val =
PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
if (Val.isInvalid())
return nullptr;

ValExpr = Val.get();

// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
llvm::APSInt Result;
if (ValExpr->isIntegerConstantExpr(Result, Context) &&
Result.isSigned() && !Result.isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
<< "schedule" << ChunkSize->getSourceRange();
return nullptr;
}
}
}

return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc,
EndLoc, Kind, ValExpr);
}

OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
Expand Down Expand Up @@ -1819,6 +1910,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_schedule:
case OMPC_threadprivate:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,21 @@ class TreeTransform {
StartLoc, LParenLoc, EndLoc);
}

/// \brief Build a new OpenMP 'schedule' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPScheduleClause(OpenMPScheduleClauseKind Kind,
Expr *ChunkSize,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation KindLoc,
SourceLocation CommaLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPScheduleClause(
Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
}

/// \brief Build a new OpenMP 'private' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
Expand Down Expand Up @@ -6472,6 +6487,17 @@ TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) {
C->getLParenLoc(), C->getLocEnd());
}

template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPScheduleClause(OMPScheduleClause *C) {
ExprResult E = getDerived().TransformExpr(C->getChunkSize());
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPScheduleClause(
C->getScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(),
C->getScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd());
}

template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_proc_bind:
C = new (Context) OMPProcBindClause();
break;
case OMPC_schedule:
C = new (Context) OMPScheduleClause();
break;
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
Expand Down Expand Up @@ -1757,6 +1760,15 @@ void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
C->setProcBindKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
}

void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
C->setScheduleKind(
static_cast<OpenMPScheduleClauseKind>(Record[Idx++]));
C->setChunkSize(Reader->Reader.ReadSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
C->setScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx));
C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
}

void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,14 @@ void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
Writer->Writer.AddSourceLocation(C->getProcBindKindKwLoc(), Record);
}

void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
Record.push_back(C->getScheduleKind());
Writer->Writer.AddStmt(C->getChunkSize());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Writer->Writer.AddSourceLocation(C->getScheduleKindLoc(), Record);
Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
}

void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Expand Down
16 changes: 8 additions & 8 deletions clang/test/OpenMP/for_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ T tmain(T argc) {
T b = argc, c, d, e, f, g;
static T a;
// CHECK: static T a;
#pragma omp for
// CHECK-NEXT: #pragma omp for
#pragma omp for schedule(dynamic)
// CHECK-NEXT: #pragma omp for schedule(dynamic)
for (int i = 0; i < 2; ++i)
a = 2;
// 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)
#pragma omp for private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N)
for (int i = 0; i < 10; ++i)
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)
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: foo();
Expand All @@ -36,19 +36,19 @@ int main(int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
// CHECK: static int a;
#pragma omp for
// CHECK-NEXT: #pragma omp for
#pragma omp for schedule(guided, argc)
// CHECK-NEXT: #pragma omp for schedule(guided, argc)
for (int i = 0; i < 2; ++i)
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
#pragma omp for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2)
#pragma omp for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2)
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: foo();
Expand Down
91 changes: 91 additions & 0 deletions clang/test/OpenMP/for_schedule_messages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %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) {
#pragma omp for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} 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 schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (auto // 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 schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} 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 schedule (auto, // 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 schedule (runtime, 3) // 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];
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp for schedule (guided argc
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+1 2 {{argument to 'schedule' clause must be a positive integer value}}
#pragma omp for schedule (static, 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 schedule (dynamic, 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 schedule (guided, (ST > 0) ? 1 + ST : 2)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'schedule' clause}}
// expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
#pragma omp for schedule (static, foobool(argc)), schedule (dynamic, true), schedule (guided, -5)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (static, S) // expected-error {{'S' does not refer to a value}} 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];
// expected-error@+1 2 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp for schedule (guided, 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 schedule (dynamic, 1)
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp for schedule (static, N) // expected-error {{argument to 'schedule' clause must be a positive integer value}}
for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
return argc;
}

int main(int argc, char **argv) {
#pragma omp for schedule // expected-error {{expected '(' after 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} 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 schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (auto // 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 schedule (auto_dynamic // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} 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 schedule (auto, // 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 schedule (runtime, 3) // 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 schedule (guided, 4 // 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 schedule (static, 2+2)) // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (dynamic, foobool(1) > 0 ? 1 : 2)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'schedule' clause}}
// expected-error@+1 {{argument to 'schedule' clause must be a positive integer value}}
#pragma omp for schedule (guided, foobool(argc)), schedule (static, true), schedule (dynamic, -5)
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
#pragma omp for schedule (guided, S1) // expected-error {{'S1' does not refer to a value}} expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}}
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
// expected-error@+1 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp for schedule (static, 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 schedule(dynamic, schedule(tmain<int, char, -1, -2>(argc, argv) // expected-error {{expected ')'}} expected-note {{to match this '('}}
foo();
// 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: 4 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,10 @@ void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { }

void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) { }

void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) {
Visitor->AddStmt(C->getChunkSize());
}

template<typename T>
void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
for (const auto *I : Node->varlists())
Expand Down