Author: Kevin Sala Penades Date: 2025-11-07T13:19:37-08:00 New Revision: 64ff52a5e95422e8ea30e7ebc748e0e54ce28e8e
URL: https://github.com/llvm/llvm-project/commit/64ff52a5e95422e8ea30e7ebc748e0e54ce28e8e DIFF: https://github.com/llvm/llvm-project/commit/64ff52a5e95422e8ea30e7ebc748e0e54ce28e8e.diff LOG: [OpenMP][Clang] Add parser/semantic support for dyn_groupprivate clause (#152651) This PR adds support for the `dyn_groupprivate` clause, which will be part of OpenMP 6.1. This feature allows users to request dynamic shared memory on target regions. --------- Co-authored-by: Krzysztof Parzyszek <[email protected]> Added: clang/test/OpenMP/target_dyn_groupprivate_messages.cpp clang/test/OpenMP/target_teams_dyn_groupprivate_messages.cpp clang/test/OpenMP/teams_dyn_groupprivate_messages.cpp Modified: clang/include/clang/AST/OpenMPClause.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/OpenMPKinds.def clang/include/clang/Basic/OpenMPKinds.h clang/include/clang/Sema/SemaOpenMP.h clang/lib/AST/OpenMPClause.cpp clang/lib/AST/StmtProfile.cpp clang/lib/Basic/OpenMPKinds.cpp clang/lib/Parse/ParseOpenMP.cpp clang/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/tools/libclang/CIndex.cpp llvm/include/llvm/Frontend/OpenMP/OMP.td llvm/unittests/Frontend/OpenMPDecompositionTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 4f507485968cd..3296fbf409552 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -10068,6 +10068,152 @@ class OMPXDynCGroupMemClause Expr *getSize() const { return getStmtAs<Expr>(); } }; +/// This represents 'dyn_groupprivate' clause in '#pragma omp target ...' +/// and '#pragma omp teams ...' directives. +/// +/// \code +/// #pragma omp target [...] dyn_groupprivate(a,b: N) +/// \endcode +class OMPDynGroupprivateClause : public OMPClause, public OMPClauseWithPreInit { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Modifiers for 'dyn_groupprivate' clause. + enum { SIMPLE, FALLBACK, NUM_MODIFIERS }; + unsigned Modifiers[NUM_MODIFIERS]; + + /// Locations of modifiers. + SourceLocation ModifiersLoc[NUM_MODIFIERS]; + + /// The size of the dyn_groupprivate. + Expr *Size = nullptr; + + /// Set the first dyn_groupprivate modifier. + /// + /// \param M The modifier. + void setDynGroupprivateModifier(OpenMPDynGroupprivateClauseModifier M) { + Modifiers[SIMPLE] = M; + } + + /// Set the second dyn_groupprivate modifier. + /// + /// \param M The modifier. + void setDynGroupprivateFallbackModifier( + OpenMPDynGroupprivateClauseFallbackModifier M) { + Modifiers[FALLBACK] = M; + } + + /// Set location of the first dyn_groupprivate modifier. + void setDynGroupprivateModifierLoc(SourceLocation Loc) { + ModifiersLoc[SIMPLE] = Loc; + } + + /// Set location of the second dyn_groupprivate modifier. + void setDynGroupprivateFallbackModifierLoc(SourceLocation Loc) { + ModifiersLoc[FALLBACK] = Loc; + } + + /// Sets the location of '('. + /// + /// \param Loc Location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + /// Set size. + /// + /// \param E Size. + void setSize(Expr *E) { Size = E; } + +public: + /// Build 'dyn_groupprivate' clause with a size expression \a Size. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param Size Size. + /// \param M1 The first modifier applied to 'dyn_groupprivate' clause. + /// \param M1Loc Location of the first modifier. + /// \param M2 The second modifier applied to 'dyn_groupprivate' clause. + /// \param M2Loc Location of the second modifier. + OMPDynGroupprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, Expr *Size, Stmt *HelperSize, + OpenMPDirectiveKind CaptureRegion, + OpenMPDynGroupprivateClauseModifier M1, + SourceLocation M1Loc, + OpenMPDynGroupprivateClauseFallbackModifier M2, + SourceLocation M2Loc) + : OMPClause(llvm::omp::OMPC_dyn_groupprivate, StartLoc, EndLoc), + OMPClauseWithPreInit(this), LParenLoc(LParenLoc), Size(Size) { + setPreInitStmt(HelperSize, CaptureRegion); + Modifiers[SIMPLE] = M1; + Modifiers[FALLBACK] = M2; + ModifiersLoc[SIMPLE] = M1Loc; + ModifiersLoc[FALLBACK] = M2Loc; + } + + /// Build an empty clause. + explicit OMPDynGroupprivateClause() + : OMPClause(llvm::omp::OMPC_dyn_groupprivate, SourceLocation(), + SourceLocation()), + OMPClauseWithPreInit(this) { + Modifiers[SIMPLE] = OMPC_DYN_GROUPPRIVATE_unknown; + Modifiers[FALLBACK] = OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown; + } + + /// Get the first modifier of the clause. + OpenMPDynGroupprivateClauseModifier getDynGroupprivateModifier() const { + return static_cast<OpenMPDynGroupprivateClauseModifier>(Modifiers[SIMPLE]); + } + + /// Get the second modifier of the clause. + OpenMPDynGroupprivateClauseFallbackModifier + getDynGroupprivateFallbackModifier() const { + return static_cast<OpenMPDynGroupprivateClauseFallbackModifier>( + Modifiers[FALLBACK]); + } + + /// Get location of '('. + SourceLocation getLParenLoc() { return LParenLoc; } + + /// Get the first modifier location. + SourceLocation getDynGroupprivateModifierLoc() const { + return ModifiersLoc[SIMPLE]; + } + + /// Get the second modifier location. + SourceLocation getDynGroupprivateFallbackModifierLoc() const { + return ModifiersLoc[FALLBACK]; + } + + /// Get size. + Expr *getSize() { return Size; } + + /// Get size. + const Expr *getSize() const { return Size; } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(&Size), + reinterpret_cast<Stmt **>(&Size) + 1); + } + + const_child_range children() const { + auto Children = const_cast<OMPDynGroupprivateClause *>(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_dyn_groupprivate; + } +}; + /// This represents the 'doacross' clause for the '#pragma omp ordered' /// directive. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 8cb0a657023b4..8f427427d71ed 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -4165,6 +4165,14 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXDynCGroupMemClause( return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + TRY_TO(VisitOMPClauseWithPreInit(C)); + TRY_TO(TraverseStmt(C->getSize())); + return true; +} + template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPDoacrossClause( OMPDoacrossClause *C) { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 04f2e8d654fd5..3e864475f22a1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12137,6 +12137,9 @@ def err_omp_unexpected_schedule_modifier : Error< "modifier '%0' cannot be used along with modifier '%1'">; def err_omp_schedule_nonmonotonic_static : Error< "'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind">; +def err_omp_incompatible_dyn_groupprivate_modifier + : Error<"modifier '%0' cannot be used along with modifier '%1' in " + "dyn_groupprivate">; def err_omp_simple_clause_incompatible_with_ordered : Error< "'%0' clause with '%1' modifier cannot be specified if an 'ordered' clause is specified">; def err_omp_ordered_simd : Error< diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 328a0747a82a8..166b80314f687 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -86,6 +86,12 @@ #ifndef OPENMP_GRAINSIZE_MODIFIER #define OPENMP_GRAINSIZE_MODIFIER(Name) #endif +#ifndef OPENMP_DYN_GROUPPRIVATE_MODIFIER +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) +#endif +#ifndef OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) +#endif #ifndef OPENMP_NUMTASKS_MODIFIER #define OPENMP_NUMTASKS_MODIFIER(Name) #endif @@ -242,6 +248,14 @@ OPENMP_BIND_KIND(thread) // Modifiers for the 'grainsize' clause. OPENMP_GRAINSIZE_MODIFIER(strict) +// Modifiers for the 'dyn_groupprivate' clause. +OPENMP_DYN_GROUPPRIVATE_MODIFIER(cgroup) + +// Fallback modifiers for the 'dyn_groupprivate' clause. +OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(abort) +OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(null) +OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(default_mem) + // Modifiers for the 'num_tasks' clause. OPENMP_NUMTASKS_MODIFIER(strict) @@ -263,6 +277,8 @@ OPENMP_THREADSET_KIND(omp_team) #undef OPENMP_NUMTASKS_MODIFIER #undef OPENMP_NUMTHREADS_MODIFIER +#undef OPENMP_DYN_GROUPPRIVATE_MODIFIER +#undef OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER #undef OPENMP_GRAINSIZE_MODIFIER #undef OPENMP_BIND_KIND #undef OPENMP_ADJUST_ARGS_KIND diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index c9ddbcd6d46c1..41b2c4e41dcb8 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -224,6 +224,20 @@ enum OpenMPGrainsizeClauseModifier { OMPC_GRAINSIZE_unknown }; +enum OpenMPDynGroupprivateClauseModifier { +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) OMPC_DYN_GROUPPRIVATE_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DYN_GROUPPRIVATE_unknown +}; + +enum OpenMPDynGroupprivateClauseFallbackModifier { + OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown = OMPC_DYN_GROUPPRIVATE_unknown, +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) \ + OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DYN_GROUPPRIVATE_FALLBACK_last +}; + enum OpenMPNumTasksClauseModifier { #define OPENMP_NUMTASKS_MODIFIER(Name) OMPC_NUMTASKS_##Name, #include "clang/Basic/OpenMPKinds.def" diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index ba12b403d9b9a..e5628e845c9ee 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -1411,6 +1411,13 @@ class SemaOpenMP : public SemaBase { SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on a well-formed 'dyn_groupprivate' clause. + OMPClause *ActOnOpenMPDynGroupprivateClause( + OpenMPDynGroupprivateClauseModifier M1, + OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, + SourceLocation M2Loc, SourceLocation EndLoc); + /// Called on well-formed 'doacross' clause. OMPClause * ActOnOpenMPDoacrossClause(OpenMPDoacrossClauseModifier DepType, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 59d94590e04d1..0640fed823771 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -105,6 +105,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast<const OMPFilterClause *>(C); case OMPC_ompx_dyn_cgroup_mem: return static_cast<const OMPXDynCGroupMemClause *>(C); + case OMPC_dyn_groupprivate: + return static_cast<const OMPDynGroupprivateClause *>(C); case OMPC_message: return static_cast<const OMPMessageClause *>(C); case OMPC_default: @@ -2857,6 +2859,24 @@ void OMPClausePrinter::VisitOMPXDynCGroupMemClause( OS << ")"; } +void OMPClausePrinter::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *Node) { + OS << "dyn_groupprivate("; + if (Node->getDynGroupprivateModifier() != OMPC_DYN_GROUPPRIVATE_unknown) { + OS << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, + Node->getDynGroupprivateModifier()); + if (Node->getDynGroupprivateFallbackModifier() != + OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown) { + OS << ", "; + OS << getOpenMPSimpleClauseTypeName( + OMPC_dyn_groupprivate, Node->getDynGroupprivateFallbackModifier()); + } + OS << ": "; + } + Node->getSize()->printPretty(OS, nullptr, Policy, 0); + OS << ')'; +} + void OMPClausePrinter::VisitOMPDoacrossClause(OMPDoacrossClause *Node) { OS << "doacross("; OpenMPDoacrossClauseModifier DepType = Node->getDependenceType(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c909e1bcecd38..4a8c638c85331 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -968,6 +968,12 @@ void OMPClauseProfiler::VisitOMPXDynCGroupMemClause( if (Expr *Size = C->getSize()) Profiler->VisitStmt(Size); } +void OMPClauseProfiler::VisitOMPDynGroupprivateClause( + const OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + if (auto *Size = C->getSize()) + Profiler->VisitStmt(Size); +} void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { VisitOMPClauseList(C); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 3d41f2d197b81..8e60fc26a7947 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -196,6 +196,16 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, return OMPC_GRAINSIZE_unknown; return Type; } + case OMPC_dyn_groupprivate: { + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) \ + .Case(#Name, OMPC_DYN_GROUPPRIVATE_##Name) +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) \ + .Case(#Name, OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name) \ + .Case("fallback(" #Name ")", OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DYN_GROUPPRIVATE_unknown); + } case OMPC_num_tasks: { unsigned Type = llvm::StringSwitch<unsigned>(Str) #define OPENMP_NUMTASKS_MODIFIER(Name) .Case(#Name, OMPC_NUMTASKS_##Name) @@ -544,6 +554,20 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'grainsize' clause modifier"); + case OMPC_dyn_groupprivate: + switch (Type) { + case OMPC_DYN_GROUPPRIVATE_unknown: + case OMPC_DYN_GROUPPRIVATE_FALLBACK_last: + return "unknown"; +#define OPENMP_DYN_GROUPPRIVATE_MODIFIER(Name) \ + case OMPC_DYN_GROUPPRIVATE_##Name: \ + return #Name; +#define OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(Name) \ + case OMPC_DYN_GROUPPRIVATE_FALLBACK_##Name: \ + return "fallback(" #Name ")"; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'dyn_groupprivate' clause modifier"); case OMPC_num_tasks: switch (Type) { case OMPC_NUMTASKS_unknown: diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 31bc941e6a015..334438edfc2e8 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3178,6 +3178,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_align: case OMPC_message: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3216,7 +3217,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) Clause = ParseOpenMPClause(CKind, WrongDirective); else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks || - CKind == OMPC_num_threads) + CKind == OMPC_num_threads || CKind == OMPC_dyn_groupprivate) Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective); else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); @@ -4009,6 +4010,83 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Arg.push_back(OMPC_GRAINSIZE_unknown); KLoc.emplace_back(); } + } else if (Kind == OMPC_dyn_groupprivate) { + enum { SimpleModifier, ComplexModifier, NumberOfModifiers }; + Arg.resize(NumberOfModifiers); + KLoc.resize(NumberOfModifiers); + Arg[SimpleModifier] = OMPC_DYN_GROUPPRIVATE_unknown; + Arg[ComplexModifier] = OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown; + + auto ConsumeModifier = [&]() { + unsigned Type = NumberOfModifiers; + unsigned Modifier; + SourceLocation Loc; + if (!Tok.isAnnotation() && PP.getSpelling(Tok) == "fallback" && + NextToken().is(tok::l_paren)) { + ConsumeToken(); + BalancedDelimiterTracker ParenT(*this, tok::l_paren, tok::r_paren); + ParenT.consumeOpen(); + + Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); + if (Modifier <= OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown || + Modifier >= OMPC_DYN_GROUPPRIVATE_FALLBACK_last) { + Diag(Tok.getLocation(), diag::err_expected) + << "'abort', 'null' or 'default_mem' in fallback modifier"; + SkipUntil(tok::r_paren); + return std::make_tuple(Type, Modifier, Loc); + } + Type = ComplexModifier; + Loc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ParenT.consumeClose(); + } else { + Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); + if (Modifier < OMPC_DYN_GROUPPRIVATE_unknown) { + Type = SimpleModifier; + Loc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + } + return std::make_tuple(Type, Modifier, Loc); + }; + + auto SaveModifier = [&](unsigned Type, unsigned Modifier, + SourceLocation Loc) { + assert(Type < NumberOfModifiers && "Unexpected modifier type"); + if (!KLoc[Type].isValid()) { + Arg[Type] = Modifier; + KLoc[Type] = Loc; + } else { + Diag(Loc, diag::err_omp_incompatible_dyn_groupprivate_modifier) + << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, Modifier) + << getOpenMPSimpleClauseTypeName(OMPC_dyn_groupprivate, Arg[Type]); + } + }; + + // Parse 'modifier' + auto [Type1, Mod1, Loc1] = ConsumeModifier(); + if (Type1 < NumberOfModifiers) { + SaveModifier(Type1, Mod1, Loc1); + if (Tok.is(tok::comma)) { + // Parse ',' 'modifier' + ConsumeAnyToken(); + auto [Type2, Mod2, Loc2] = ConsumeModifier(); + if (Type2 < NumberOfModifiers) + SaveModifier(Type2, Mod2, Loc2); + } + // Parse ':' + if (Tok.is(tok::colon)) + ConsumeAnyToken(); + else + Diag(Tok, diag::warn_pragma_expected_colon) + << "dyn_groupprivate modifier"; + } } else if (Kind == OMPC_num_tasks) { // Parse optional <num_tasks modifier> ':' OpenMPNumTasksClauseModifier Modifier = @@ -4083,11 +4161,11 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, } } - bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || - (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || - Kind == OMPC_if || Kind == OMPC_device || - Kind == OMPC_grainsize || Kind == OMPC_num_tasks || - Kind == OMPC_num_threads; + bool NeedAnExpression = + (Kind == OMPC_schedule && DelimLoc.isValid()) || + (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || Kind == OMPC_if || + Kind == OMPC_device || Kind == OMPC_grainsize || Kind == OMPC_num_tasks || + Kind == OMPC_num_threads || Kind == OMPC_dyn_groupprivate; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS( diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 256f9521b3a7e..465dab2b65eb1 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -16532,6 +16532,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_holds: Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_dyn_groupprivate: case OMPC_grainsize: case OMPC_num_tasks: case OMPC_num_threads: @@ -16658,6 +16659,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_num_teams: case OMPC_thread_limit: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: + // TODO: This may need to consider teams too. if (Leafs[0] == OMPD_target) return OMPD_target; break; @@ -17705,7 +17708,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { - case OMPC_schedule: + case OMPC_schedule: { enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements }; assert(Argument.size() == NumberOfElements && ArgumentLoc.size() == NumberOfElements); @@ -17716,6 +17719,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2], ArgumentLoc[ScheduleKind], DelimLoc, EndLoc); break; + } case OMPC_if: assert(Argument.size() == 1 && ArgumentLoc.size() == 1); Res = ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument.back()), @@ -17771,6 +17775,20 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr, StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); break; + case OMPC_dyn_groupprivate: { + enum { Modifier1, Modifier2, NumberOfElements }; + assert(Argument.size() == NumberOfElements && + ArgumentLoc.size() == NumberOfElements && + "Modifiers for dyn_groupprivate clause and their locations are " + "expected."); + Res = ActOnOpenMPDynGroupprivateClause( + static_cast<OpenMPDynGroupprivateClauseModifier>(Argument[Modifier1]), + static_cast<OpenMPDynGroupprivateClauseFallbackModifier>( + Argument[Modifier2]), + Expr, StartLoc, LParenLoc, ArgumentLoc[Modifier1], + ArgumentLoc[Modifier2], EndLoc); + break; + } case OMPC_num_threads: assert(Argument.size() == 1 && ArgumentLoc.size() == 1 && "Modifier for num_threads clause and its location are expected."); @@ -18127,6 +18145,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_affinity: case OMPC_when: case OMPC_ompx_dyn_cgroup_mem: + case OMPC_dyn_groupprivate: default: llvm_unreachable("Clause is not allowed."); } @@ -25246,6 +25265,49 @@ OMPClause *SemaOpenMP::ActOnOpenMPXDynCGroupMemClause(Expr *Size, ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } +OMPClause *SemaOpenMP::ActOnOpenMPDynGroupprivateClause( + OpenMPDynGroupprivateClauseModifier M1, + OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, + SourceLocation M2Loc, SourceLocation EndLoc) { + + if ((M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) || + (M2Loc.isValid() && M2 == OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown)) { + std::string Values = getListOfPossibleValues( + OMPC_dyn_groupprivate, /*First=*/0, OMPC_DYN_GROUPPRIVATE_unknown); + Diag((M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) ? M1Loc + : M2Loc, + diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dyn_groupprivate); + return nullptr; + } + + Expr *ValExpr = Size; + Stmt *HelperValStmt = nullptr; + + // OpenMP [2.5, Restrictions] + // The dyn_groupprivate expression must evaluate to a positive integer + // value. + if (!isNonNegativeIntegerValue(ValExpr, SemaRef, OMPC_dyn_groupprivate, + /*StrictlyPositive=*/false)) + return nullptr; + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause( + DKind, OMPC_dyn_groupprivate, getLangOpts().OpenMP); + if (CaptureRegion != OMPD_unknown && + !SemaRef.CurContext->isDependentContext()) { + ValExpr = SemaRef.MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(getASTContext(), Captures); + } + + return new (getASTContext()) OMPDynGroupprivateClause( + StartLoc, LParenLoc, EndLoc, ValExpr, HelperValStmt, CaptureRegion, M1, + M1Loc, M2, M2Loc); +} + OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause( OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 94105f10d71b5..c2491489f40d2 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2463,6 +2463,19 @@ class TreeTransform { LParenLoc, EndLoc); } + /// Build a new OpenMP 'dyn_groupprivate' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide diff erent behavior. + OMPClause *RebuildOMPDynGroupprivateClause( + OpenMPDynGroupprivateClauseModifier M1, + OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, + SourceLocation M2Loc, SourceLocation EndLoc) { + return getSema().OpenMP().ActOnOpenMPDynGroupprivateClause( + M1, M2, Size, StartLoc, LParenLoc, M1Loc, M2Loc, EndLoc); + } + /// Build a new OpenMP 'ompx_attribute' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -11725,6 +11738,19 @@ OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause( Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + ExprResult Size = getDerived().TransformExpr(C->getSize()); + if (Size.isInvalid()) + return nullptr; + return getDerived().RebuildOMPDynGroupprivateClause( + C->getDynGroupprivateModifier(), C->getDynGroupprivateFallbackModifier(), + Size.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getDynGroupprivateModifierLoc(), + C->getDynGroupprivateFallbackModifierLoc(), C->getEndLoc()); +} + template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPDoacrossClause(OMPDoacrossClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index d5528219bb7d5..a04041c10b4ba 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11544,6 +11544,9 @@ OMPClause *OMPClauseReader::readClause() { case llvm::omp::OMPC_ompx_dyn_cgroup_mem: C = new (Context) OMPXDynCGroupMemClause(); break; + case llvm::omp::OMPC_dyn_groupprivate: + C = new (Context) OMPDynGroupprivateClause(); + break; case llvm::omp::OMPC_doacross: { unsigned NumVars = Record.readInt(); unsigned NumLoops = Record.readInt(); @@ -12736,6 +12739,19 @@ void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { C->setLParenLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + C->setDynGroupprivateModifier( + Record.readEnum<OpenMPDynGroupprivateClauseModifier>()); + C->setDynGroupprivateFallbackModifier( + Record.readEnum<OpenMPDynGroupprivateClauseFallbackModifier>()); + C->setSize(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); + C->setDynGroupprivateModifierLoc(Record.readSourceLocation()); + C->setDynGroupprivateFallbackModifierLoc(Record.readSourceLocation()); +} + void OMPClauseReader::VisitOMPDoacrossClause(OMPDoacrossClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setDependenceType( diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index b1fd151790d96..821e7df1bce53 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -8651,6 +8651,17 @@ void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPDynGroupprivateClause( + OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + Record.push_back(C->getDynGroupprivateModifier()); + Record.push_back(C->getDynGroupprivateFallbackModifier()); + Record.AddStmt(C->getSize()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getDynGroupprivateModifierLoc()); + Record.AddSourceLocation(C->getDynGroupprivateFallbackModifierLoc()); +} + void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); diff --git a/clang/test/OpenMP/target_dyn_groupprivate_messages.cpp b/clang/test/OpenMP/target_dyn_groupprivate_messages.cpp new file mode 100644 index 0000000000000..385bd5e89829d --- /dev/null +++ b/clang/test/OpenMP/target_dyn_groupprivate_messages.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=61 %s -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=61 %s -Wuninitialized + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template <class T, class S> // expected-note {{declared here}} +int tmain(T argc, S **argv) { + T z; + #pragma omp target dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp target dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}} + foo(); + #pragma omp target dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp target dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp target' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp target dyn_groupprivate (S) // expected-error {{'S' does not refer to a value}} + foo(); + #pragma omp target dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(argc+z) + foo(); + return 0; +} + +int main(int argc, char **argv) { +constexpr int n = -1; +int z; + #pragma omp target dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp target dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}} + foo(); + #pragma omp target dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp target dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp target' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp target dyn_groupprivate (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(dyn_groupprivate(tmain(argc, argv) // expected-error2 {{expected ')'}} expected-note2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char>' requested here}} + foo(); + #pragma omp target dyn_groupprivate(-1) // expected-error {{argument to 'dyn_groupprivate' clause must be a non-negative integer value}} + foo(); + #pragma omp target dyn_groupprivate(cgrou) // expected-error {{use of undeclared identifier 'cgrou'}} + foo(); + #pragma omp target dyn_groupprivate(cgrou: argc) // expected-error {{use of undeclared identifier 'cgrou'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(cgroup,cgroup: argc) // expected-error {{modifier 'cgroup' cannot be used along with modifier 'cgroup' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(default_mem),fallback(abort): argc) // expected-error {{modifier 'fallback(abort)' cannot be used along with modifier 'fallback(default_mem)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(abort),fallback(null): argc) // expected-error {{modifier 'fallback(null)' cannot be used along with modifier 'fallback(abort)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(cgroup): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(fallback(): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(: argc) // expected-error {{expected ')'}} expected-error {{expected expression}} expected-note {{to match this '('}} + foo(); + + return tmain(argc, argv); +} + diff --git a/clang/test/OpenMP/target_teams_dyn_groupprivate_messages.cpp b/clang/test/OpenMP/target_teams_dyn_groupprivate_messages.cpp new file mode 100644 index 0000000000000..ac2cc0dde5073 --- /dev/null +++ b/clang/test/OpenMP/target_teams_dyn_groupprivate_messages.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=61 %s -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=61 %s -Wuninitialized + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template <class T, class S> // expected-note {{declared here}} +int tmain(T argc, S **argv) { + T z; + #pragma omp target teams dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp target teams dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target teams dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target teams' are ignored}} + foo(); + #pragma omp target teams dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp target teams dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp target teams dyn_groupprivate (S) // expected-error {{'S' does not refer to a value}} + foo(); + #pragma omp target teams dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate(argc+z) + foo(); + return 0; +} + +int main(int argc, char **argv) { +constexpr int n = -1; +int z; + #pragma omp target teams dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp target teams dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target teams dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target teams' are ignored}} + foo(); + #pragma omp target teams dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp target teams dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp target teams dyn_groupprivate (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate(dyn_groupprivate(tmain(argc, argv) // expected-error2 {{expected ')'}} expected-note2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char>' requested here}} + foo(); + #pragma omp target teams dyn_groupprivate(-1) // expected-error {{argument to 'dyn_groupprivate' clause must be a non-negative integer value}} + foo(); + #pragma omp target teams dyn_groupprivate(cgrou) // expected-error {{use of undeclared identifier 'cgrou'}} + foo(); + #pragma omp target teams dyn_groupprivate(cgrou: argc) // expected-error {{use of undeclared identifier 'cgrou'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate(cgroup,cgroup: argc) // expected-error {{modifier 'cgroup' cannot be used along with modifier 'cgroup' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(default_mem),fallback(abort): argc) // expected-error {{modifier 'fallback(abort)' cannot be used along with modifier 'fallback(default_mem)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(abort),fallback(null): argc) // expected-error {{modifier 'fallback(null)' cannot be used along with modifier 'fallback(abort)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(cgroup): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(fallback(): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams dyn_groupprivate(: argc) // expected-error {{expected ')'}} expected-error {{expected expression}} expected-note {{to match this '('}} + foo(); + + return tmain(argc, argv); +} + diff --git a/clang/test/OpenMP/teams_dyn_groupprivate_messages.cpp b/clang/test/OpenMP/teams_dyn_groupprivate_messages.cpp new file mode 100644 index 0000000000000..701ebfb43eec6 --- /dev/null +++ b/clang/test/OpenMP/teams_dyn_groupprivate_messages.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=61 %s -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=61 %s -Wuninitialized + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template <class T, class S> // expected-note {{declared here}} +int tmain(T argc, S **argv) { + T z; + #pragma omp teams dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp teams dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp teams dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}} + foo(); + #pragma omp teams dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp teams dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp teams dyn_groupprivate (S) // expected-error {{'S' does not refer to a value}} + foo(); + #pragma omp teams dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate(argc+z) + foo(); + return 0; +} + +int main(int argc, char **argv) { +constexpr int n = -1; +int z; + #pragma omp teams dyn_groupprivate // expected-error {{expected '(' after 'dyn_groupprivate'}} + foo(); + #pragma omp teams dyn_groupprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate () // expected-error {{expected expression}} + foo(); + #pragma omp teams dyn_groupprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate (argc)) // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}} + foo(); + #pragma omp teams dyn_groupprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + foo(); + #pragma omp teams dyn_groupprivate (foobool(argc)), dyn_groupprivate (true) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'dyn_groupprivate' clause}} + foo(); + #pragma omp teams dyn_groupprivate (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp teams dyn_groupprivate (argv[1]=2) // expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate(dyn_groupprivate(tmain(argc, argv) // expected-error2 {{expected ')'}} expected-note2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char>' requested here}} + foo(); + #pragma omp teams dyn_groupprivate(-1) // expected-error {{argument to 'dyn_groupprivate' clause must be a non-negative integer value}} + foo(); + #pragma omp teams dyn_groupprivate(cgrou) // expected-error {{use of undeclared identifier 'cgrou'}} + foo(); + #pragma omp teams dyn_groupprivate(cgrou: argc) // expected-error {{use of undeclared identifier 'cgrou'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate(cgroup,cgroup: argc) // expected-error {{modifier 'cgroup' cannot be used along with modifier 'cgroup' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(default_mem),fallback(abort): argc) // expected-error {{modifier 'fallback(abort)' cannot be used along with modifier 'fallback(default_mem)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(abort),fallback(null): argc) // expected-error {{modifier 'fallback(null)' cannot be used along with modifier 'fallback(abort)' in dyn_groupprivate}} + foo(); + #pragma omp target dyn_groupprivate(fallback(cgroup): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target dyn_groupprivate(fallback(): argc) // expected-error {{expected 'abort', 'null' or 'default_mem' in fallback modifier}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp teams dyn_groupprivate(: argc) // expected-error {{expected ')'}} expected-error {{expected expression}} expected-note {{to match this '('}} + foo(); + + return tmain(argc, argv); +} + diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 08776d9bcabfc..f4d6fa72a1dfe 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2757,6 +2757,11 @@ void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause( VisitOMPClauseWithPreInit(C); Visitor->AddStmt(C->getSize()); } +void OMPClauseEnqueue::VisitOMPDynGroupprivateClause( + const OMPDynGroupprivateClause *C) { + VisitOMPClauseWithPreInit(C); + Visitor->AddStmt(C->getSize()); +} void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { VisitOMPClauseList(C); } diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index bebab9ba63488..a01858fb220f1 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -187,6 +187,7 @@ def OMPC_DynamicAllocators : Clause<[Spelling<"dynamic_allocators">]> { let isValueOptional = true; } def OMPC_DynGroupprivate : Clause<[Spelling<"dyn_groupprivate">]> { + let clangClass = "OMPDynGroupprivateClause"; let flangClass = "OmpDynGroupprivateClause"; } def OMPC_Enter : Clause<[Spelling<"enter">]> { diff --git a/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp b/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp index a8706ceac141f..e0c6b3904310c 100644 --- a/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp +++ b/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp @@ -88,6 +88,7 @@ using DistSchedule = tomp::clause::DistScheduleT<TypeTy, IdTy, ExprTy>; using Doacross = tomp::clause::DoacrossT<TypeTy, IdTy, ExprTy>; using DynamicAllocators = tomp::clause::DynamicAllocatorsT<TypeTy, IdTy, ExprTy>; +using DynGroupprivate = tomp::clause::DynGroupprivateT<TypeTy, IdTy, ExprTy>; using Enter = tomp::clause::EnterT<TypeTy, IdTy, ExprTy>; using Exclusive = tomp::clause::ExclusiveT<TypeTy, IdTy, ExprTy>; using Fail = tomp::clause::FailT<TypeTy, IdTy, ExprTy>; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
