summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h7
-rw-r--r--include/clang/AST/OpenMPClause.h56
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h8
-rw-r--r--include/clang/Basic/OpenMPKinds.def2
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/AST/StmtPrinter.cpp6
-rw-r--r--lib/AST/StmtProfile.cpp5
-rw-r--r--lib/Basic/OpenMPKinds.cpp2
-rw-r--r--lib/Parse/ParseOpenMP.cpp10
-rw-r--r--lib/Sema/SemaOpenMP.cpp19
-rw-r--r--lib/Sema/TreeTransform.h21
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp8
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp5
-rw-r--r--test/OpenMP/simd_ast_print.cpp8
-rw-r--r--test/OpenMP/simd_collapse_messages.cpp79
-rw-r--r--test/OpenMP/simd_misc_messages.c72
-rw-r--r--tools/libclang/CIndex.cpp4
17 files changed, 309 insertions, 7 deletions
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 43fa147eea..109d623c79 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2316,6 +2316,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) {
}
template <typename Derived>
+bool
+RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ TraverseStmt(C->getNumForLoops());
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
return true;
}
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 108238c092..2be6882f1d 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -306,6 +306,62 @@ public:
StmtRange children() { return StmtRange(&Safelen, &Safelen + 1); }
};
+/// \brief This represents 'collapse' clause in the '#pragma omp ...'
+/// directive.
+///
+/// \code
+/// #pragma omp simd collapse(3)
+/// \endcode
+/// In this example directive '#pragma omp simd' has clause 'collapse'
+/// with single expression '3'.
+/// The parameter must be a constant positive integer expression, it specifies
+/// the number of nested loops that should be collapsed into a single iteration
+/// space.
+///
+class OMPCollapseClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief Number of for-loops.
+ Stmt *NumForLoops;
+
+ /// \brief Set the number of associated for-loops.
+ void setNumForLoops(Expr *Num) { NumForLoops = Num; }
+
+public:
+ /// \brief Build 'collapse' clause.
+ ///
+ /// \param Num Expression associated with this clause.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ ///
+ OMPCollapseClause(Expr *Num, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_collapse, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ NumForLoops(Num) {}
+
+ /// \brief Build an empty clause.
+ ///
+ explicit OMPCollapseClause()
+ : OMPClause(OMPC_collapse, SourceLocation(), SourceLocation()),
+ LParenLoc(SourceLocation()), NumForLoops(nullptr) {}
+
+ /// \brief Sets the location of '('.
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ /// \brief Return the number of associated for-loops.
+ Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_collapse;
+ }
+
+ StmtRange children() { return StmtRange(&NumForLoops, &NumForLoops + 1); }
+};
+
/// \brief This represents 'default' clause in the '#pragma omp ...' directive.
///
/// \code
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index e1fa54829a..d000ae70e3 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2331,13 +2331,19 @@ RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
return true;
}
-template <typename Derived>
+template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) {
TraverseStmt(C->getSafelen());
return true;
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ TraverseStmt(C->getNumForLoops());
+ return true;
+}
+
+template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
return true;
}
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 8977f99917..0adc9841e3 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -41,6 +41,7 @@ OPENMP_DIRECTIVE(simd)
OPENMP_CLAUSE(if, OMPIfClause)
OPENMP_CLAUSE(num_threads, OMPNumThreadsClause)
OPENMP_CLAUSE(safelen, OMPSafelenClause)
+OPENMP_CLAUSE(collapse, OMPCollapseClause)
OPENMP_CLAUSE(default, OMPDefaultClause)
OPENMP_CLAUSE(private, OMPPrivateClause)
OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
@@ -63,6 +64,7 @@ OPENMP_PARALLEL_CLAUSE(copyin)
OPENMP_SIMD_CLAUSE(private)
OPENMP_SIMD_CLAUSE(linear)
OPENMP_SIMD_CLAUSE(safelen)
+OPENMP_SIMD_CLAUSE(collapse)
// Static attributes for 'default' clause.
OPENMP_DEFAULT_KIND(none)
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 4235c3d776..ecb405cb61 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7334,6 +7334,10 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'collapse' clause.
+ OMPClause *ActOnOpenMPCollapseClause(Expr *Num, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
unsigned Argument,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index e5f24dc5d5..0804d4089b 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -608,6 +608,12 @@ void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) {
OS << ")";
}
+void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) {
+ OS << "collapse(";
+ Node->getNumForLoops()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
OS << "default("
<< getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind())
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 5dbaa0e832..9cff6d6743 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -279,6 +279,11 @@ void OMPClauseProfiler::VisitOMPSafelenClause(const OMPSafelenClause *C) {
Profiler->VisitStmt(C->getSafelen());
}
+void OMPClauseProfiler::VisitOMPCollapseClause(const OMPCollapseClause *C) {
+ if (C->getNumForLoops())
+ Profiler->VisitStmt(C->getNumForLoops());
+}
+
void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index f67cac8d40..c0142410b4 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -83,6 +83,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
@@ -119,6 +120,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index dfd8ca7c2c..5916098ab1 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -257,7 +257,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
///
/// clause:
/// if-clause | num_threads-clause | safelen-clause | default-clause |
-/// private-clause | firstprivate-clause | shared-clause | linear-clause
+/// private-clause | firstprivate-clause | shared-clause | linear-clause |
+/// collapse-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -274,11 +275,13 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
+ case OMPC_collapse:
// OpenMP [2.5, Restrictions]
// At most one if clause can appear on the directive.
// At most one num_threads clause can appear on the directive.
// OpenMP [2.8.1, simd construct, Restrictions]
- // Only one safelen clause can appear on a simd directive.
+ // Only one safelen clause can appear on a simd directive.
+ // Only one collapse clause can appear on a simd directive.
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
@@ -334,6 +337,9 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
/// safelen-clause:
/// 'safelen' '(' expression ')'
///
+/// collapse-clause:
+/// 'collapse' '(' expression ')'
+///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
SourceLocation Loc = ConsumeToken();
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 18cfd43c80..39ec632735 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -809,6 +809,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_safelen:
Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_collapse:
+ Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
@@ -950,6 +953,20 @@ OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc,
OMPSafelenClause(Safelen.take(), StartLoc, LParenLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *Num, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.8.1, simd construct, Description]
+ // The parameter of the collapse clause must be a constant
+ // positive integer expression.
+ ExprResult NumForLoops =
+ VerifyPositiveIntegerConstantInClause(Num, OMPC_collapse);
+ if (NumForLoops.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPCollapseClause(NumForLoops.take(), StartLoc, LParenLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
unsigned Argument,
SourceLocation ArgumentLoc,
@@ -971,6 +988,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
@@ -1086,6 +1104,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_if:
case OMPC_num_threads:
case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ef82b82146..3386b5bcee 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1333,6 +1333,17 @@ public:
return getSema().ActOnOpenMPSafelenClause(Len, StartLoc, LParenLoc, EndLoc);
}
+ /// \brief Build a new OpenMP 'collapse' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPCollapseClause(Expr *Num, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPCollapseClause(Num, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// \brief Build a new OpenMP 'default' clause.
///
/// By default, performs semantic analysis to build the new statement.
@@ -6399,6 +6410,16 @@ TreeTransform<Derived>::TransformOMPSafelenClause(OMPSafelenClause *C) {
E.take(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCollapseClause(OMPCollapseClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getNumForLoops());
+ if (E.isInvalid())
+ return 0;
+ return getDerived().RebuildOMPCollapseClause(
+ E.take(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
template<typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPDefaultClause(OMPDefaultClause *C) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index b51f097638..89bc7fefa2 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1682,6 +1682,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_safelen:
C = new (Context) OMPSafelenClause();
break;
+ case OMPC_collapse:
+ C = new (Context) OMPCollapseClause();
+ break;
case OMPC_default:
C = new (Context) OMPDefaultClause();
break;
@@ -1726,6 +1729,11 @@ void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
}
+void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ C->setNumForLoops(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
C->setDefaultKind(
static_cast<OpenMPDefaultClauseKind>(Record[Idx++]));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index c827060d9d..a79772a533 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1690,6 +1690,11 @@ void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) {
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
}
+void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ Writer->Writer.AddStmt(C->getNumForLoops());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
Record.push_back(C->getDefaultKind());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
diff --git a/test/OpenMP/simd_ast_print.cpp b/test/OpenMP/simd_ast_print.cpp
index 5e8cbecfbc..efc65c9428 100644
--- a/test/OpenMP/simd_ast_print.cpp
+++ b/test/OpenMP/simd_ast_print.cpp
@@ -97,10 +97,10 @@ int main (int argc, char **argv) {
for (int i=0; i < 2; ++i)*a=2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: *a = 2;
-#pragma omp simd private(argc, b)
+#pragma omp simd private(argc, b) collapse(2)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
-// CHECK-NEXT: #pragma omp simd private(argc,b)
+// CHECK-NEXT: #pragma omp simd private(argc,b) collapse(2)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j) {
// CHECK-NEXT: foo();
@@ -112,8 +112,8 @@ int main (int argc, char **argv) {
// CHECK-NEXT: foo();
const int CLEN = 4;
// CHECK-NEXT: const int CLEN = 4;
- #pragma omp simd linear(a:CLEN) safelen(CLEN)
-// CHECK-NEXT: #pragma omp simd linear(a: CLEN) safelen(CLEN)
+ #pragma omp simd linear(a:CLEN) safelen(CLEN) collapse( 1 )
+// CHECK-NEXT: #pragma omp simd linear(a: CLEN) safelen(CLEN) collapse(1)
for (int i = 0; i < 10; ++i)foo();
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/simd_collapse_messages.cpp b/test/OpenMP/simd_collapse_messages.cpp
new file mode 100644
index 0000000000..eea9596ac3
--- /dev/null
+++ b/test/OpenMP/simd_collapse_messages.cpp
@@ -0,0 +1,79 @@
+// 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) { //expected-note 2 {{declared here}}
+ #pragma omp simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp simd collapse ( // 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 simd collapse () // 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 simd collapse (argc
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse (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 simd collapse (1)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}}
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp simd collapse ((ST > 0) ? 1 + ST : 2)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ // expected-error@+3 2 {{directive '#pragma omp simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+2 2 {{argument to 'collapse' clause must be a positive integer value}}
+ // expected-error@+1 2 {{expression is not an integral constant expression}}
+ #pragma omp simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp simd collapse (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 simd collapse (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 simd collapse (1)
+ for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
+ #pragma omp simd collapse (N) // expected-error {{argument to 'collapse' 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 simd collapse // expected-error {{expected '(' after 'collapse'}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp simd collapse ( // 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 simd collapse () // expected-error {{expected expression}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp simd collapse (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 simd collapse (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}}
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp simd collapse (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 simd' cannot contain more than one 'collapse' clause}}
+ // expected-error@+1 2 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse (foobool(argc)), collapse (true), collapse (-5)
+ for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
+ #pragma omp simd collapse (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 simd collapse (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 simd' must be a for loop}}
+ // expected-note@+1 {{in instantiation of function template specialization 'tmain<int, char, -1, -2>' requested here}}
+ #pragma omp simd collapse(collapse(tmain<int, char, -1, -2>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{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);
+}
+
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 6e2f81cee1..58f10ac5da 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -146,6 +146,78 @@ void test_safelen()
for (i = 0; i < 16; ++i);
}
+void test_collapse()
+{
+ int i;
+ // expected-error@+1 {{expected '('}}
+ #pragma omp simd collapse
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd collapse()
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(,
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(,)
+ for (i = 0; i < 16; ++i) ;
+ // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}}
+ // expected-error@+1 {{expected '('}}
+ #pragma omp simd collapse 4)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4,
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4,)
+ for (i = 0; i < 16; ++i) ;
+ // xxpected-error@+1 {{expected expression}}
+ #pragma omp simd collapse(4)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4 4)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4,,4)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd collapse(4)
+ for (int i1 = 0; i1 < 16; ++i1)
+ for (int i2 = 0; i2 < 16; ++i2)
+ for (int i3 = 0; i3 < 16; ++i3)
+ for (int i4 = 0; i4 < 16; ++i4)
+ foo();
+ // expected-error@+2 {{expected ')'}}
+ // expected-note@+1 {{to match this '('}}
+ #pragma omp simd collapse(4,8)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expression is not an integer constant expression}}
+ #pragma omp simd collapse(2.5)
+ for (i = 0; i < 16; ++i);
+ // expected-error@+1 {{expression is not an integer constant expression}}
+ #pragma omp simd collapse(foo())
+ for (i = 0; i < 16; ++i);
+ // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse(-5)
+ for (i = 0; i < 16; ++i);
+ // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse(0)
+ for (i = 0; i < 16; ++i);
+ // expected-error@+1 {{argument to 'collapse' clause must be a positive integer value}}
+ #pragma omp simd collapse(5-5)
+ for (i = 0; i < 16; ++i);
+}
+
void test_linear()
{
int i;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 5710d66890..bc1174ae3c 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1935,6 +1935,10 @@ void OMPClauseEnqueue::VisitOMPSafelenClause(const OMPSafelenClause *C) {
Visitor->AddStmt(C->getSafelen());
}
+void OMPClauseEnqueue::VisitOMPCollapseClause(const OMPCollapseClause *C) {
+ Visitor->AddStmt(C->getNumForLoops());
+}
+
void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) { }