Index: include/clang/AST/OpenMPClause.h =================================================================== --- include/clang/AST/OpenMPClause.h +++ include/clang/AST/OpenMPClause.h @@ -2893,6 +2893,135 @@ child_range children() { return child_range(&Priority, &Priority + 1); } }; +/// \brief This represents 'dist_schedule' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp distribute dist_schedule(static, 3) +/// \endcode +/// In this example directive '#pragma omp distribute' has 'dist_schedule' +/// clause with arguments 'static' and '3'. +/// +class OMPDistScheduleClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'schedule' clause. + OpenMPDistScheduleClauseKind Kind; + /// \brief Start location of the schedule kind in source code. + SourceLocation KindLoc; + /// \brief Location of ',' (if any). + SourceLocation CommaLoc; + /// \brief Chunk size and a reference to pseudo variable for combined + /// directives. + enum { CHUNK_SIZE, HELPER_CHUNK_SIZE, NUM_EXPRS }; + Stmt *ChunkSizes[NUM_EXPRS]; + + /// \brief Set schedule kind. + /// + /// \param K Schedule kind. + /// + void setDistScheduleKind(OpenMPDistScheduleClauseKind 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 setDistScheduleKindLoc(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) { ChunkSizes[CHUNK_SIZE] = E; } + /// \brief Set helper chunk size. + /// + /// \param E Helper chunk size. + /// + void setHelperChunkSize(Expr *E) { ChunkSizes[HELPER_CHUNK_SIZE] = E; } + +public: + /// \brief Build 'dist_schedule' clause with schedule kind \a Kind and chunk + /// size expression \a ChunkSize. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param KLoc Starting location of the argument. + /// \param CommaLoc Location of ','. + /// \param EndLoc Ending location of the clause. + /// \param Kind DistSchedule kind. + /// \param ChunkSize Chunk size. + /// \param HelperChunkSize Helper chunk size for combined directives. + /// + OMPDistScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation KLoc, SourceLocation CommaLoc, + SourceLocation EndLoc, + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, + Expr *HelperChunkSize) + : OMPClause(OMPC_dist_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc) { + ChunkSizes[CHUNK_SIZE] = ChunkSize; + ChunkSizes[HELPER_CHUNK_SIZE] = HelperChunkSize; + } + + /// \brief Build an empty clause. + /// + explicit OMPDistScheduleClause() + : OMPClause(OMPC_dist_schedule, SourceLocation(), SourceLocation()), + Kind(OMPC_DIST_SCHEDULE_unknown) { + ChunkSizes[CHUNK_SIZE] = nullptr; + ChunkSizes[HELPER_CHUNK_SIZE] = nullptr; + } + + /// \brief Get kind of the clause. + /// + OpenMPDistScheduleClauseKind getDistScheduleKind() const { return Kind; } + /// \brief Get location of '('. + /// + SourceLocation getLParenLoc() { return LParenLoc; } + /// \brief Get kind location. + /// + SourceLocation getDistScheduleKindLoc() { return KindLoc; } + /// \brief Get location of ','. + /// + SourceLocation getCommaLoc() { return CommaLoc; } + /// \brief Get chunk size. + /// + Expr *getChunkSize() { + return dyn_cast_or_null(ChunkSizes[CHUNK_SIZE]); + } + /// \brief Get chunk size. + /// + Expr *getChunkSize() const { + return dyn_cast_or_null(ChunkSizes[CHUNK_SIZE]); + } + /// \brief Get helper chunk size. + /// + Expr *getHelperChunkSize() { + return dyn_cast_or_null(ChunkSizes[HELPER_CHUNK_SIZE]); + } + /// \brief Get helper chunk size. + /// + Expr *getHelperChunkSize() const { + return dyn_cast_or_null(ChunkSizes[HELPER_CHUNK_SIZE]); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_dist_schedule; + } + + child_range children() { + return child_range(&ChunkSizes[CHUNK_SIZE], &ChunkSizes[CHUNK_SIZE] + 1); + } +}; } // end namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2753,6 +2753,14 @@ return true; } +template +bool RecursiveASTVisitor::VisitOMPDistScheduleClause( + OMPDistScheduleClause *C) { + TRY_TO(TraverseStmt(C->getChunkSize())); + TRY_TO(TraverseStmt(C->getHelperChunkSize())); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm Index: include/clang/Basic/OpenMPKinds.h =================================================================== --- include/clang/Basic/OpenMPKinds.h +++ include/clang/Basic/OpenMPKinds.h @@ -86,6 +86,13 @@ OMPC_MAP_unknown }; +/// \brief OpenMP attributes for 'dist_schedule' clause. +enum OpenMPDistScheduleClauseKind { +#define OPENMP_DIST_SCHEDULE_KIND(Name) OMPC_DIST_SCHEDULE_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DIST_SCHEDULE_unknown +}; + OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); Index: include/clang/Basic/OpenMPKinds.def =================================================================== --- include/clang/Basic/OpenMPKinds.def +++ include/clang/Basic/OpenMPKinds.def @@ -96,6 +96,10 @@ #ifndef OPENMP_MAP_KIND #define OPENMP_MAP_KIND(Name) #endif +#ifndef OPENMP_DIST_SCHEDULE_KIND +#define OPENMP_DIST_SCHEDULE_KIND(Name) +#endif + // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) @@ -165,6 +169,7 @@ OPENMP_CLAUSE(num_teams, OMPNumTeamsClause) OPENMP_CLAUSE(thread_limit, OMPThreadLimitClause) OPENMP_CLAUSE(priority, OMPPriorityClause) +OPENMP_CLAUSE(dist_schedule, OMPDistScheduleClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -345,12 +350,6 @@ OPENMP_ORDERED_CLAUSE(threads) OPENMP_ORDERED_CLAUSE(simd) -// Clauses allowed for OpenMP directive 'distribute' -OPENMP_DISTRIBUTE_CLAUSE(private) -OPENMP_DISTRIBUTE_CLAUSE(firstprivate) -OPENMP_DISTRIBUTE_CLAUSE(lastprivate) -OPENMP_DISTRIBUTE_CLAUSE(collapse) - // Map types and map type modifier for 'map' clause. OPENMP_MAP_KIND(alloc) OPENMP_MAP_KIND(to) @@ -392,6 +391,16 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(safelen) OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen) +// Clauses allowed for OpenMP directive 'distribute' +OPENMP_DISTRIBUTE_CLAUSE(private) +OPENMP_DISTRIBUTE_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_CLAUSE(lastprivate) +OPENMP_DISTRIBUTE_CLAUSE(collapse) +OPENMP_DISTRIBUTE_CLAUSE(dist_schedule) + +// Static attributes for 'dist_schedule' clause. +OPENMP_DIST_SCHEDULE_KIND(static) + #undef OPENMP_TASKLOOP_SIMD_CLAUSE #undef OPENMP_TASKLOOP_CLAUSE #undef OPENMP_LINEAR_KIND @@ -420,3 +429,4 @@ #undef OPENMP_FOR_SIMD_CLAUSE #undef OPENMP_DISTRIBUTE_CLAUSE #undef OPENMP_MAP_KIND +#undef OPENMP_DIST_SCHEDULE_KIND Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8167,6 +8167,11 @@ OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'dist_schedule' clause. + OMPClause *ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, + SourceLocation CommaLoc, SourceLocation EndLoc); /// \brief The kind of conversion being performed. enum CheckedConversionKind { Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -877,6 +877,16 @@ OS << ")"; } } + +void OMPClausePrinter::VisitOMPDistScheduleClause(OMPDistScheduleClause *Node) { + OS << "dist_schedule(" << getOpenMPSimpleClauseTypeName( + OMPC_dist_schedule, Node->getDistScheduleKind()); + if (Node->getChunkSize()) { + OS << ", "; + Node->getChunkSize()->printPretty(OS, nullptr, Policy); + } + OS << ")"; +} } //===----------------------------------------------------------------------===// Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -599,6 +599,16 @@ VisitOMPLoopDirective(S); } +void OMPClauseProfiler::VisitOMPDistScheduleClause( + const OMPDistScheduleClause *C) { + if (C->getChunkSize()) { + Profiler->VisitStmt(C->getChunkSize()); + if (C->getHelperChunkSize()) { + Profiler->VisitStmt(C->getChunkSize()); + } + } +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -106,6 +106,11 @@ #define OPENMP_MAP_KIND(Name) .Case(#Name, OMPC_MAP_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_MAP_unknown); + case OMPC_dist_schedule: + return llvm::StringSwitch(Str) +#define OPENMP_DIST_SCHEDULE_KIND(Name) .Case(#Name, OMPC_DIST_SCHEDULE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DIST_SCHEDULE_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -207,6 +212,16 @@ break; } llvm_unreachable("Invalid OpenMP 'map' clause type"); + case OMPC_dist_schedule: + switch (Type) { + case OMPC_DIST_SCHEDULE_unknown: + return "unknown"; +#define OPENMP_DIST_SCHEDULE_KIND(Name) \ + case OMPC_DIST_SCHEDULE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'dist_schedule' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -2486,6 +2486,7 @@ case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: + case OMPC_dist_schedule: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -470,6 +470,7 @@ Clause = ParseOpenMPSimpleClause(CKind); break; case OMPC_schedule: + case OMPC_dist_schedule: // OpenMP [2.7.1, Restrictions, p. 3] // Only one schedule clause can appear on a loop directive. if (!FirstClause) { @@ -659,7 +660,7 @@ ExprResult Val; unsigned Arg; SourceLocation KLoc; - if (Kind == OMPC_schedule) { + if (Kind == OMPC_schedule || Kind == OMPC_dist_schedule) { Arg = getOpenMPSimpleClauseType( Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); KLoc = Tok.getLocation(); @@ -667,7 +668,7 @@ Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); if ((Arg == OMPC_SCHEDULE_static || Arg == OMPC_SCHEDULE_dynamic || - Arg == OMPC_SCHEDULE_guided) && + Arg == OMPC_SCHEDULE_guided || Arg == OMPC_DIST_SCHEDULE_static) && Tok.is(tok::comma)) DelimLoc = ConsumeAnyToken(); } else { @@ -684,8 +685,9 @@ } } - bool NeedAnExpression = - (Kind == OMPC_schedule && DelimLoc.isValid()) || Kind == OMPC_if; + bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || + (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || + Kind == OMPC_if; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -5508,6 +5508,7 @@ case OMPC_threads: case OMPC_simd: case OMPC_map: + case OMPC_dist_schedule: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -5784,6 +5785,7 @@ case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: + case OMPC_dist_schedule: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -5882,6 +5884,11 @@ ActOnOpenMPIfClause(static_cast(Argument), Expr, StartLoc, LParenLoc, ArgumentLoc, DelimLoc, EndLoc); break; + case OMPC_dist_schedule: + Res = ActOnOpenMPDistScheduleClause( + static_cast(Argument), Expr, StartLoc, + LParenLoc, ArgumentLoc, DelimLoc, EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -6052,6 +6059,7 @@ case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: + case OMPC_dist_schedule: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -6184,6 +6192,7 @@ case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: + case OMPC_dist_schedule: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -8149,3 +8158,56 @@ return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc); } + +OMPClause *Sema::ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DIST_SCHEDULE_unknown) { + std::string Values; + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0); + Values += "'"; + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dist_schedule); + return nullptr; + } + Expr *ValExpr = ChunkSize; + Expr *HelperValExpr = nullptr; + 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)) { + if (Result.isSigned() && !Result.isStrictlyPositive()) { + Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) + << "dist_schedule" << ChunkSize->getSourceRange(); + return nullptr; + } + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { + auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(), + ChunkSize->getType(), ".chunk."); + auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(), + ChunkSize->getExprLoc(), + /*RefersToCapture=*/true); + HelperValExpr = ImpVarRef; + } + } + } + + return new (Context) + OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, + Kind, ValExpr, HelperValExpr); +} Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1700,6 +1700,19 @@ EndLoc); } + /// \brief Build a new OpenMP 'dist_schedule' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind, + Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation KindLoc, + SourceLocation CommaLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDistScheduleClause( + Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -7794,6 +7807,17 @@ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd()); } +template +OMPClause *TreeTransform::TransformOMPDistScheduleClause( + OMPDistScheduleClause *C) { + ExprResult E = getDerived().TransformExpr(C->getChunkSize()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPDistScheduleClause( + C->getDistScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(), + C->getDistScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1859,6 +1859,9 @@ case OMPC_priority: C = new (Context) OMPPriorityClause(); break; + case OMPC_dist_schedule: + C = new (Context) OMPDistScheduleClause(); + break; } Visit(C); C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); @@ -2198,6 +2201,16 @@ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); } +void OMPClauseReader::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + C->setDistScheduleKind( + static_cast(Record[Idx++])); + C->setChunkSize(Reader->Reader.ReadSubExpr()); + C->setHelperChunkSize(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setDistScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx)); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -2016,6 +2016,15 @@ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); } +void OMPClauseWriter::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + Record.push_back(C->getDistScheduleKind()); + Writer->Writer.AddStmt(C->getChunkSize()); + Writer->Writer.AddStmt(C->getHelperChunkSize()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Writer->Writer.AddSourceLocation(C->getDistScheduleKindLoc(), Record); + Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -2196,6 +2196,11 @@ void OMPClauseEnqueue::VisitOMPMapClause(const OMPMapClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPDistScheduleClause( + const OMPDistScheduleClause *C) { + Visitor->AddStmt(C->getChunkSize()); + Visitor->AddStmt(C->getHelperChunkSize()); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {