diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2014-06-20 07:16:17 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2014-06-20 07:16:17 +0000 |
commit | ad5b6350d810c01b57661a37f296f2c1803588e5 (patch) | |
tree | 254bb56a0c5f613e699fc44906efa225587d3e1e | |
parent | 3f05ce1565771ec6daa895dcd7121bb48478536e (diff) | |
download | clang-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.h | 7 | ||||
-rw-r--r-- | include/clang/AST/OpenMPClause.h | 98 | ||||
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 7 | ||||
-rw-r--r-- | include/clang/Basic/OpenMPKinds.def | 13 | ||||
-rw-r--r-- | include/clang/Basic/OpenMPKinds.h | 8 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 15 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 10 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 5 | ||||
-rw-r--r-- | lib/Basic/OpenMPKinds.cpp | 15 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 54 | ||||
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 92 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 26 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 12 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 8 | ||||
-rw-r--r-- | test/OpenMP/for_ast_print.cpp | 16 | ||||
-rw-r--r-- | test/OpenMP/for_schedule_messages.cpp | 91 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 4 |
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()) |