summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Bataev <a.bataev@hotmail.com>2014-06-20 07:16:17 +0000
committerAlexey Bataev <a.bataev@hotmail.com>2014-06-20 07:16:17 +0000
commitad5b6350d810c01b57661a37f296f2c1803588e5 (patch)
tree254bb56a0c5f613e699fc44906efa225587d3e1e
parent3f05ce1565771ec6daa895dcd7121bb48478536e (diff)
downloadclang-ad5b6350d810c01b57661a37f296f2c1803588e5.tar.gz
clang-ad5b6350d810c01b57661a37f296f2c1803588e5.tar.bz2
clang-ad5b6350d810c01b57661a37f296f2c1803588e5.tar.xz
[OPENMP] Initial support for 'schedule' clause.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211342 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h7
-rw-r--r--include/clang/AST/OpenMPClause.h98
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/Basic/OpenMPKinds.def13
-rw-r--r--include/clang/Basic/OpenMPKinds.h8
-rw-r--r--include/clang/Parse/Parser.h6
-rw-r--r--include/clang/Sema/Sema.h15
-rw-r--r--lib/AST/StmtPrinter.cpp10
-rw-r--r--lib/AST/StmtProfile.cpp5
-rw-r--r--lib/Basic/OpenMPKinds.cpp15
-rw-r--r--lib/Parse/ParseOpenMP.cpp54
-rw-r--r--lib/Sema/SemaOpenMP.cpp92
-rw-r--r--lib/Sema/TreeTransform.h26
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp12
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp8
-rw-r--r--test/OpenMP/for_ast_print.cpp16
-rw-r--r--test/OpenMP/for_schedule_messages.cpp91
-rw-r--r--tools/libclang/CIndex.cpp4
18 files changed, 478 insertions, 9 deletions
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 5679ba3b64..e83d7269c4 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2344,6 +2344,13 @@ RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *C) {
}
template <typename Derived>
+bool
+RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ TraverseStmt(C->getChunkSize());
+ return true;
+}
+
+template <typename Derived>
template <typename T>
void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (auto *I : Node->varlists())
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 82a6d2992b..9df30a374e 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -502,6 +502,104 @@ public:
StmtRange children() { return StmtRange(); }
};
+/// \brief This represents 'schedule' clause in the '#pragma omp ...' directive.
+///
+/// \code
+/// #pragma omp for schedule(static, 3)
+/// \endcode
+/// In this example directive '#pragma omp for' has 'schedule' clause with
+/// arguments 'static' and '3'.
+///
+class OMPScheduleClause : public OMPClause {
+ friend class OMPClauseReader;
+ /// \brief Location of '('.
+ SourceLocation LParenLoc;
+ /// \brief A kind of the 'schedule' clause.
+ OpenMPScheduleClauseKind Kind;
+ /// \brief Start location of the schedule ind in source code.
+ SourceLocation KindLoc;
+ /// \brief Location of ',' (if any).
+ SourceLocation CommaLoc;
+ /// \brief Chunk size.
+ Stmt *ChunkSize;
+
+ /// \brief Set schedule kind.
+ ///
+ /// \param K Schedule kind.
+ ///
+ void setScheduleKind(OpenMPScheduleClauseKind K) { Kind = K; }
+ /// \brief Sets the location of '('.
+ ///
+ /// \param Loc Location of '('.
+ ///
+ void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ /// \brief Set schedule kind start location.
+ ///
+ /// \param KLoc Schedule kind location.
+ ///
+ void setScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; }
+ /// \brief Set location of ','.
+ ///
+ /// \param Loc Location of ','.
+ ///
+ void setCommaLoc(SourceLocation Loc) { CommaLoc = Loc; }
+ /// \brief Set chunk size.
+ ///
+ /// \param E Chunk size.
+ ///
+ void setChunkSize(Expr *E) { ChunkSize = E; }
+
+public:
+ /// \brief Build 'schedule' clause with schedule kind \a Kind and chunk size
+ /// expression \a ChunkSize.
+ ///
+ /// \brief StartLoc Starting location of the clause.
+ /// \brief LParenLoc Location of '('.
+ /// \brief KLoc Starting location of the argument.
+ /// \brief CommaLoc Location of ','.
+ /// \brief EndLoc Ending location of the clause.
+ /// \brief Kind Schedule kind.
+ /// \brief ChunkSize Chunk size.
+ ///
+ OMPScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation KLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc, OpenMPScheduleClauseKind Kind,
+ Expr *ChunkSize)
+ : OMPClause(OMPC_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc), ChunkSize(ChunkSize) {}
+
+ /// \brief Build an empty clause.
+ ///
+ explicit OMPScheduleClause()
+ : OMPClause(OMPC_schedule, SourceLocation(), SourceLocation()),
+ Kind(OMPC_SCHEDULE_unknown), ChunkSize(nullptr) {}
+
+ /// \brief Get kind of the clause.
+ ///
+ OpenMPScheduleClauseKind getScheduleKind() const { return Kind; }
+ /// \brief Get location of '('.
+ ///
+ SourceLocation getLParenLoc() { return LParenLoc; }
+ /// \brief Get kind location.
+ ///
+ SourceLocation getScheduleKindLoc() { return KindLoc; }
+ /// \brief Get location of ','.
+ ///
+ SourceLocation getCommaLoc() { return CommaLoc; }
+ /// \brief Get chunk size.
+ ///
+ Expr *getChunkSize() { return dyn_cast_or_null<Expr>(ChunkSize); }
+ /// \brief Get chunk size.
+ ///
+ Expr *getChunkSize() const { return dyn_cast_or_null<Expr>(ChunkSize); }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_schedule;
+ }
+
+ StmtRange children() { return StmtRange(&ChunkSize, &ChunkSize + 1); }
+};
+
/// \brief This represents clause 'private' in the '#pragma omp ...' directives.
///
/// \code
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 3b756ef384..26841d3535 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2365,6 +2365,13 @@ RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *C) {
}
template <typename Derived>
+bool
+RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ TraverseStmt(C->getChunkSize());
+ return true;
+}
+
+template <typename Derived>
template <typename T>
void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (auto *I : Node->varlists())
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index a4bc961e29..f899570e62 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -33,6 +33,9 @@
#ifndef OPENMP_PROC_BIND_KIND
# define OPENMP_PROC_BIND_KIND(Name)
#endif
+#ifndef OPENMP_SCHEDULE_KIND
+#define OPENMP_SCHEDULE_KIND(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
@@ -56,6 +59,7 @@ OPENMP_CLAUSE(linear, OMPLinearClause)
OPENMP_CLAUSE(aligned, OMPAlignedClause)
OPENMP_CLAUSE(copyin, OMPCopyinClause)
OPENMP_CLAUSE(proc_bind, OMPProcBindClause)
+OPENMP_CLAUSE(schedule, OMPScheduleClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@@ -82,6 +86,7 @@ OPENMP_FOR_CLAUSE(lastprivate)
OPENMP_FOR_CLAUSE(firstprivate)
OPENMP_FOR_CLAUSE(reduction)
OPENMP_FOR_CLAUSE(collapse)
+OPENMP_FOR_CLAUSE(schedule)
// Static attributes for 'default' clause.
OPENMP_DEFAULT_KIND(none)
@@ -92,6 +97,14 @@ OPENMP_PROC_BIND_KIND(master)
OPENMP_PROC_BIND_KIND(close)
OPENMP_PROC_BIND_KIND(spread)
+// Static attributes for 'schedule' clause.
+OPENMP_SCHEDULE_KIND(static)
+OPENMP_SCHEDULE_KIND(dynamic)
+OPENMP_SCHEDULE_KIND(guided)
+OPENMP_SCHEDULE_KIND(auto)
+OPENMP_SCHEDULE_KIND(runtime)
+
+#undef OPENMP_SCHEDULE_KIND
#undef OPENMP_PROC_BIND_KIND
#undef OPENMP_DEFAULT_KIND
#undef OPENMP_DIRECTIVE
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index 57559074d3..65f74321f6 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -52,6 +52,14 @@ enum OpenMPProcBindClauseKind {
OMPC_PROC_BIND_unknown
};
+/// \brief OpenMP attributes for 'schedule' clause.
+enum OpenMPScheduleClauseKind {
+#define OPENMP_SCHEDULE_KIND(Name) \
+ OMPC_SCHEDULE_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_SCHEDULE_unknown
+};
+
OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str);
const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind);
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2c76dce761..ef09e7ac82 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -2345,6 +2345,12 @@ private:
/// \param Kind Kind of current clause.
///
OMPClause *ParseOpenMPSimpleClause(OpenMPClauseKind Kind);
+ /// \brief Parses clause with a single expression and an additional argument
+ /// of a kind \a Kind.
+ ///
+ /// \param Kind Kind of current clause.
+ ///
+ OMPClause *ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind);
/// \brief Parses clause with the list of variables of a kind \a Kind.
///
/// \param Kind Kind of current clause.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 872dbffb80..2f5cbef865 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7366,6 +7366,21 @@ public:
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ OMPClause *ActOnOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
+ unsigned Argument, Expr *Expr,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ArgumentLoc,
+ SourceLocation CommaLoc,
+ SourceLocation EndLoc);
+ /// \brief Called on well-formed 'schedule' clause.
+ OMPClause *ActOnOpenMPScheduleClause(OpenMPScheduleClauseKind Kind,
+ Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation KindLoc,
+ SourceLocation CommaLoc,
+ SourceLocation EndLoc);
+
OMPClause *
ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars,
Expr *TailExpr, SourceLocation StartLoc,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 16330a46fe..ca18e708a0 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -628,6 +628,16 @@ void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
<< ")";
}
+void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
+ OS << "schedule("
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind());
+ if (Node->getChunkSize()) {
+ OS << ", ";
+ Node->getChunkSize()->printPretty(OS, nullptr, Policy);
+ }
+ OS << ")";
+}
+
template<typename T>
void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
for (typename T::varlist_iterator I = Node->varlist_begin(),
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index ac6a1eb59a..bb41489597 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -288,6 +288,11 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
+void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
+ if (C->getChunkSize())
+ Profiler->VisitStmt(C->getChunkSize());
+}
+
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
for (auto *I : Node->varlists())
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 9b398a18d1..131d40a375 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -76,6 +76,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_PROC_BIND_unknown);
+ case OMPC_schedule:
+ return llvm::StringSwitch<OpenMPScheduleClauseKind>(Str)
+#define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_SCHEDULE_unknown);
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -118,6 +123,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'proc_bind' clause type");
+ case OMPC_schedule:
+ switch (Type) {
+ case OMPC_SCHEDULE_unknown:
+ return "unknown";
+#define OPENMP_SCHEDULE_KIND(Name) \
+ case OMPC_SCHEDULE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'schedule' clause type");
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 97b708ba86..9cd9d4d634 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -262,7 +262,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// if-clause | num_threads-clause | safelen-clause | default-clause |
/// private-clause | firstprivate-clause | shared-clause | linear-clause |
/// aligned-clause | collapse-clause | lastprivate-clause |
-/// reduction-clause
+/// reduction-clause | proc_bind-clause | schedule-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -307,6 +307,16 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
Clause = ParseOpenMPSimpleClause(CKind);
break;
+ case OMPC_schedule:
+ // OpenMP [2.7.1, Restrictions, p. 3]
+ // Only one schedule clause can appear on a loop directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPSingleExprWithArgClause(CKind);
+ break;
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
@@ -399,6 +409,48 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
Tok.getLocation());
}
+/// \brief Parsing of OpenMP clauses with single expressions and some additional
+/// argument like 'schedule' or 'dist_schedule'.
+///
+/// schedule-clause:
+/// 'schedule' '(' kind [',' expression ] ')'
+///
+OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = ConsumeToken();
+ SourceLocation CommaLoc;
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return nullptr;
+
+ ExprResult Val;
+ unsigned Type = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
+ SourceLocation KLoc = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+
+ if (Kind == OMPC_schedule &&
+ (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic ||
+ Type == OMPC_SCHEDULE_guided) &&
+ Tok.is(tok::comma)) {
+ CommaLoc = ConsumeAnyToken();
+ ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
+ Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+ if (Val.isInvalid())
+ return nullptr;
+ }
+
+ // Parse ')'.
+ T.consumeClose();
+
+ return Actions.ActOnOpenMPSingleExprWithArgClause(
+ Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc,
+ T.getCloseLocation());
+}
+
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
UnqualifiedId &ReductionId) {
SourceLocation TemplateKWLoc;
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 8015a23aea..515bd5f8c4 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -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:
@@ -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:
@@ -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,
@@ -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.");
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index a1a564e2f2..69685a9539 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1377,6 +1377,21 @@ public:
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.
@@ -6474,6 +6489,17 @@ TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) {
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) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 708c7f3866..cda835597f 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -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;
@@ -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();
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index fb8d14b861..0de9221c73 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -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);
diff --git a/test/OpenMP/for_ast_print.cpp b/test/OpenMP/for_ast_print.cpp
index 592c8abb26..665c0c55cf 100644
--- a/test/OpenMP/for_ast_print.cpp
+++ b/test/OpenMP/for_ast_print.cpp
@@ -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();
@@ -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();
diff --git a/test/OpenMP/for_schedule_messages.cpp b/test/OpenMP/for_schedule_messages.cpp
new file mode 100644
index 0000000000..be4ff4f703
--- /dev/null
+++ b/test/OpenMP/for_schedule_messages.cpp
@@ -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);
+}
+
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f99bb2102b..0958634a28 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -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())