Author: Robert Imschweiler Date: 2025-06-24T21:12:40+02:00 New Revision: f624ba2d9d2143a0c2679ee9792cf455f965adec
URL: https://github.com/llvm/llvm-project/commit/f624ba2d9d2143a0c2679ee9792cf455f965adec DIFF: https://github.com/llvm/llvm-project/commit/f624ba2d9d2143a0c2679ee9792cf455f965adec.diff LOG: [OpenMP][clang] 6.0: parsing/sema for num_threads 'strict' modifier (#145490) Implement parsing and semantic analysis support for the optional 'strict' modifier of the num_threads clause. This modifier has been introduced in OpenMP 6.0, section 12.1.2. Note: this is basically 1:1 https://reviews.llvm.org/D138328. Added: Modified: clang/include/clang/AST/OpenMPClause.h 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/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/test/OpenMP/parallel_ast_print.cpp clang/test/OpenMP/parallel_num_threads_messages.cpp llvm/include/llvm/Frontend/OpenMP/OMP.td Removed: ################################################################################ diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 05239668b34b1..c6f99fb21a0f0 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -824,31 +824,52 @@ class OMPNumThreadsClause final public OMPClauseWithPreInit { friend class OMPClauseReader; + /// Modifiers for 'num_threads' clause. + OpenMPNumThreadsClauseModifier Modifier = OMPC_NUMTHREADS_unknown; + + /// Location of the modifier. + SourceLocation ModifierLoc; + + /// Sets modifier. + void setModifier(OpenMPNumThreadsClauseModifier M) { Modifier = M; } + + /// Sets modifier location. + void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// Set condition. void setNumThreads(Expr *NThreads) { setStmt(NThreads); } public: /// Build 'num_threads' clause with condition \a NumThreads. /// + /// \param Modifier Clause modifier. /// \param NumThreads Number of threads for the construct. /// \param HelperNumThreads Helper Number of threads for the construct. /// \param CaptureRegion Innermost OpenMP region where expressions in this /// clause must be captured. /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. + /// \param ModifierLoc Modifier location. /// \param EndLoc Ending location of the clause. - OMPNumThreadsClause(Expr *NumThreads, Stmt *HelperNumThreads, - OpenMPDirectiveKind CaptureRegion, + OMPNumThreadsClause(OpenMPNumThreadsClauseModifier Modifier, Expr *NumThreads, + Stmt *HelperNumThreads, OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) + SourceLocation ModifierLoc, SourceLocation EndLoc) : OMPOneStmtClause(NumThreads, StartLoc, LParenLoc, EndLoc), - OMPClauseWithPreInit(this) { + OMPClauseWithPreInit(this), Modifier(Modifier), + ModifierLoc(ModifierLoc) { setPreInitStmt(HelperNumThreads, CaptureRegion); } /// Build an empty clause. OMPNumThreadsClause() : OMPOneStmtClause(), OMPClauseWithPreInit(this) {} + /// Gets modifier. + OpenMPNumThreadsClauseModifier getModifier() const { return Modifier; } + + /// Gets modifier location. + SourceLocation getModifierLoc() const { return ModifierLoc; } + /// Returns number of threads. Expr *getNumThreads() const { return getStmtAs<Expr>(); } }; diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 2b1dc1e0121b2..9d6f816eea91f 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -86,6 +86,9 @@ #ifndef OPENMP_NUMTASKS_MODIFIER #define OPENMP_NUMTASKS_MODIFIER(Name) #endif +#ifndef OPENMP_NUMTHREADS_MODIFIER +#define OPENMP_NUMTHREADS_MODIFIER(Name) +#endif #ifndef OPENMP_DOACROSS_MODIFIER #define OPENMP_DOACROSS_MODIFIER(Name) #endif @@ -227,6 +230,9 @@ OPENMP_GRAINSIZE_MODIFIER(strict) // Modifiers for the 'num_tasks' clause. OPENMP_NUMTASKS_MODIFIER(strict) +// Modifiers for the 'num_tasks' clause. +OPENMP_NUMTHREADS_MODIFIER(strict) + // Modifiers for 'allocate' clause. OPENMP_ALLOCATE_MODIFIER(allocator) OPENMP_ALLOCATE_MODIFIER(align) @@ -238,6 +244,7 @@ OPENMP_DOACROSS_MODIFIER(sink_omp_cur_iteration) OPENMP_DOACROSS_MODIFIER(source_omp_cur_iteration) #undef OPENMP_NUMTASKS_MODIFIER +#undef OPENMP_NUMTHREADS_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 9afcce21a499d..f40db4c13c55a 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -223,6 +223,12 @@ enum OpenMPNumTasksClauseModifier { OMPC_NUMTASKS_unknown }; +enum OpenMPNumThreadsClauseModifier { +#define OPENMP_NUMTHREADS_MODIFIER(Name) OMPC_NUMTHREADS_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_NUMTHREADS_unknown +}; + /// OpenMP dependence types for 'doacross' clause. enum OpenMPDoacrossClauseModifier { #define OPENMP_DOACROSS_MODIFIER(Name) OMPC_DOACROSS_##Name, diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 7b169f56b6807..91c3d4bd5210e 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -877,10 +877,10 @@ class SemaOpenMP : public SemaBase { SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'num_threads' clause. - OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc); + OMPClause *ActOnOpenMPNumThreadsClause( + OpenMPNumThreadsClauseModifier Modifier, Expr *NumThreads, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc); /// Called on well-formed 'align' clause. OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 8b1caa05eec32..de8b5996818de 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1830,6 +1830,11 @@ void OMPClausePrinter::VisitOMPFinalClause(OMPFinalClause *Node) { void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) { OS << "num_threads("; + OpenMPNumThreadsClauseModifier Modifier = Node->getModifier(); + if (Modifier != OMPC_NUMTHREADS_unknown) { + OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier) + << ": "; + } Node->getNumThreads()->printPretty(OS, nullptr, Policy, 0); OS << ")"; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index a451fc7c01841..d3d393bd09396 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -185,11 +185,19 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, #define OPENMP_ALLOCATE_MODIFIER(Name) .Case(#Name, OMPC_ALLOCATE_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_ALLOCATE_unknown); + case OMPC_num_threads: { + unsigned Type = llvm::StringSwitch<unsigned>(Str) +#define OPENMP_NUMTHREADS_MODIFIER(Name) .Case(#Name, OMPC_NUMTHREADS_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_NUMTHREADS_unknown); + if (LangOpts.OpenMP < 60) + return OMPC_NUMTHREADS_unknown; + return Type; + } case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: case OMPC_final: - case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_sizes: @@ -520,11 +528,20 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'allocate' clause modifier"); + case OMPC_num_threads: + switch (Type) { + case OMPC_NUMTHREADS_unknown: + return "unknown"; +#define OPENMP_NUMTHREADS_MODIFIER(Name) \ + case OMPC_NUMTHREADS_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'num_threads' clause modifier"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: case OMPC_final: - case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_sizes: diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 78d3503d8eb68..f694ae1d0d112 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3196,7 +3196,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, if ((CKind == OMPC_ordered || CKind == OMPC_partial) && PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) Clause = ParseOpenMPClause(CKind, WrongDirective); - else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks) + else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks || + CKind == OMPC_num_threads) Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective); else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); @@ -3981,6 +3982,33 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Arg.push_back(OMPC_NUMTASKS_unknown); KLoc.emplace_back(); } + } else if (Kind == OMPC_num_threads) { + // Parse optional <num_threads modifier> ':' + OpenMPNumThreadsClauseModifier Modifier = + static_cast<OpenMPNumThreadsClauseModifier>(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), + getLangOpts())); + if (getLangOpts().OpenMP >= 60) { + if (NextToken().is(tok::colon)) { + Arg.push_back(Modifier); + KLoc.push_back(Tok.getLocation()); + // Parse modifier + ConsumeAnyToken(); + // Parse ':' + ConsumeAnyToken(); + } else { + if (Modifier == OMPC_NUMTHREADS_strict) { + Diag(Tok, diag::err_modifier_expected_colon) << "strict"; + // Parse modifier + ConsumeAnyToken(); + } + Arg.push_back(OMPC_NUMTHREADS_unknown); + KLoc.emplace_back(); + } + } else { + Arg.push_back(OMPC_NUMTHREADS_unknown); + KLoc.emplace_back(); + } } else { assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); @@ -4004,7 +4032,8 @@ 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_grainsize || Kind == OMPC_num_tasks || + Kind == OMPC_num_threads; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false, diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 00f4658180807..a30acbe9a4bca 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -15509,9 +15509,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_final: Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); break; - case OMPC_num_threads: - Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc); - break; case OMPC_safelen: Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -15565,6 +15562,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, break; case OMPC_grainsize: case OMPC_num_tasks: + case OMPC_num_threads: case OMPC_device: case OMPC_if: case OMPC_default: @@ -15911,10 +15909,41 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, return true; } -OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(Expr *NumThreads, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { +static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, + unsigned Last, + ArrayRef<unsigned> Exclude = {}) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + unsigned Skipped = Exclude.size(); + for (unsigned I = First; I < Last; ++I) { + if (llvm::is_contained(Exclude, I)) { + --Skipped; + continue; + } + Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'"; + if (I + Skipped + 2 == Last) + Out << " or "; + else if (I + Skipped + 1 != Last) + Out << ", "; + } + return std::string(Out.str()); +} + +OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause( + OpenMPNumThreadsClauseModifier Modifier, Expr *NumThreads, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { + assert((ModifierLoc.isInvalid() || getLangOpts().OpenMP >= 60) && + "Unexpected num_threads modifier in OpenMP < 60."); + + if (ModifierLoc.isValid() && Modifier == OMPC_NUMTHREADS_unknown) { + std::string Values = getListOfPossibleValues(OMPC_num_threads, /*First=*/0, + OMPC_NUMTHREADS_unknown); + Diag(ModifierLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseNameForDiag(OMPC_num_threads); + return nullptr; + } + Expr *ValExpr = NumThreads; Stmt *HelperValStmt = nullptr; @@ -15935,8 +15964,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(Expr *NumThreads, HelperValStmt = buildPreInits(getASTContext(), Captures); } - return new (getASTContext()) OMPNumThreadsClause( - ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); + return new (getASTContext()) + OMPNumThreadsClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, ModifierLoc, EndLoc); } ExprResult SemaOpenMP::VerifyPositiveIntegerConstantInClause( @@ -16301,26 +16331,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPSimpleClause( return Res; } -static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, - unsigned Last, - ArrayRef<unsigned> Exclude = {}) { - SmallString<256> Buffer; - llvm::raw_svector_ostream Out(Buffer); - unsigned Skipped = Exclude.size(); - for (unsigned I = First; I < Last; ++I) { - if (llvm::is_contained(Exclude, I)) { - --Skipped; - continue; - } - Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'"; - if (I + Skipped + 2 == Last) - Out << " or "; - else if (I + Skipped + 1 != Last) - Out << ", "; - } - return std::string(Out.str()); -} - OMPClause *SemaOpenMP::ActOnOpenMPDefaultClause(DefaultKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, @@ -16693,8 +16703,14 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause( static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr, StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); break; - case OMPC_final: case OMPC_num_threads: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1 && + "Modifier for num_threads clause and its location are expected."); + Res = ActOnOpenMPNumThreadsClause( + static_cast<OpenMPNumThreadsClauseModifier>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); + break; + case OMPC_final: case OMPC_safelen: case OMPC_simdlen: case OMPC_sizes: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 26bee7a96de22..0d58587cb8a99 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1714,12 +1714,14 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide diff erent behavior. - OMPClause *RebuildOMPNumThreadsClause(Expr *NumThreads, + OMPClause *RebuildOMPNumThreadsClause(OpenMPNumThreadsClauseModifier Modifier, + Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { - return getSema().OpenMP().ActOnOpenMPNumThreadsClause(NumThreads, StartLoc, - LParenLoc, EndLoc); + return getSema().OpenMP().ActOnOpenMPNumThreadsClause( + Modifier, NumThreads, StartLoc, LParenLoc, ModifierLoc, EndLoc); } /// Build a new OpenMP 'safelen' clause. @@ -10461,7 +10463,8 @@ TreeTransform<Derived>::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) { if (NumThreads.isInvalid()) return nullptr; return getDerived().RebuildOMPNumThreadsClause( - NumThreads.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + C->getModifier(), NumThreads.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getEndLoc()); } template <typename Derived> diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 6f082fe840b4c..b696cb2efee3d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11461,7 +11461,9 @@ void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) { void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { VisitOMPClauseWithPreInit(C); + C->setModifier(Record.readEnum<OpenMPNumThreadsClauseModifier>()); C->setNumThreads(Record.readSubExpr()); + C->setModifierLoc(Record.readSourceLocation()); C->setLParenLoc(Record.readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index c6487c5366a29..4cca214f8e308 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7802,7 +7802,9 @@ void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) { void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { VisitOMPClauseWithPreInit(C); + Record.writeEnum(C->getModifier()); Record.AddStmt(C->getNumThreads()); + Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getLParenLoc()); } diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp index 83afedcb740da..948baaff30d89 100644 --- a/clang/test/OpenMP/parallel_ast_print.cpp +++ b/clang/test/OpenMP/parallel_ast_print.cpp @@ -13,6 +13,14 @@ // RUN: %clang_cc1 -DOMP51 -verify -Wno-vla -fopenmp-simd -ast-print %s | FileCheck -check-prefixes=CHECK,OMP51 %s // RUN: %clang_cc1 -DOMP51 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s // RUN: %clang_cc1 -DOMP51 -fopenmp-simd -std=c++11 -include-pch %t -verify -Wno-vla %s -ast-print | FileCheck -check-prefixes=CHECK,OMP51 %s + +// RUN: %clang_cc1 -DOMP60 -verify -Wno-vla -fopenmp -fopenmp-version=60 -ast-print %s | FileCheck -check-prefixes=CHECK,OMP60 %s +// RUN: %clang_cc1 -DOMP60 -fopenmp -fopenmp-version=60 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -DOMP60 -fopenmp -fopenmp-version=60 -std=c++11 -include-pch %t -verify -Wno-vla %s -ast-print | FileCheck -check-prefixes=CHECK,OMP60 %s + +// RUN: %clang_cc1 -DOMP60 -verify -Wno-vla -fopenmp-simd -fopenmp-version=60 -ast-print %s | FileCheck -check-prefixes=CHECK,OMP60 %s +// RUN: %clang_cc1 -DOMP60 -fopenmp-simd -fopenmp-version=60 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -DOMP60 -fopenmp-simd -fopenmp-version=60 -std=c++11 -include-pch %t -verify -Wno-vla %s -ast-print | FileCheck -check-prefixes=CHECK,OMP60 %s // expected-no-diagnostics #ifndef HEADER @@ -164,8 +172,16 @@ T tmain(T argc, T *argv) { #pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(C) copyin(S<T>::TS, thrp) proc_bind(primary) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10]) foo(); #endif +#ifdef OMP60 +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(strict: C) copyin(S<T>::TS, thrp) proc_bind(primary) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10]) + foo(); +#endif #pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) reduction(task,+:argc) foo(); +#ifdef OMP60 +#pragma omp parallel if (C) num_threads(strict: s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) reduction(task,+:argc) + foo(); +#endif return 0; } @@ -180,8 +196,12 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: foo() // OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(C) copyin(S<T>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10]) // OMP51-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: C) copyin(S<T>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10]) +// OMP60-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) reduction(task, +: argc) // CHECK-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel if(C) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) reduction(task, +: argc) +// OMP60-NEXT: foo() // CHECK: template<> int tmain<int, 5>(int argc, int *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; @@ -193,8 +213,12 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: foo() // OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(5) copyin(S<int>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10]) // OMP51-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 5) copyin(S<int>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10]) +// OMP60-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) reduction(task, +: argc) // CHECK-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel if(5) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) reduction(task, +: argc) +// OMP60-NEXT: foo() // CHECK: template<> long tmain<long, 1>(long argc, long *argv) { // CHECK-NEXT: long b = argc, c, d, e, f, g; // CHECK-NEXT: static long a; @@ -206,8 +230,12 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: foo() // OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(1) copyin(S<long>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10]) // OMP51-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 1) copyin(S<long>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10]) +// OMP60-NEXT: foo() // CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) reduction(task, +: argc) // CHECK-NEXT: foo() +// OMP60-NEXT: #pragma omp parallel if(1) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) reduction(task, +: argc) +// OMP60-NEXT: foo() enum Enum { }; @@ -227,10 +255,22 @@ int main (int argc, char **argv) { // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(parallel: argc > 0) num_threads(ee) copyin(a) proc_bind(spread) reduction(|: c,d,arr1[argc]) reduction(*: e,arr[:10][0:argc]) allocate(e) foo(); // CHECK-NEXT: foo(); +#ifdef OMP60 +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(| : c, d, arr1[argc]) reduction(* : e, arr[:10][0:argc]) allocate(e) +// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(|: c,d,arr1[argc]) reduction(*: e,arr[:10][0:argc]) allocate(e) + foo(); +// OMP60-NEXT: foo(); +#endif +#pragma omp parallel allocate(e) if (b) num_threads(c) proc_bind(close) reduction(^:e, f) reduction(&& : g, arr[0:argc][:10]) // CHECK-NEXT: #pragma omp parallel allocate(e) if(b) num_threads(c) proc_bind(close) reduction(^: e,f) reduction(&&: g,arr[0:argc][:10]) + foo(); // CHECK-NEXT: foo() -#pragma omp parallel allocate(e) if (b) num_threads(c) proc_bind(close) reduction(^:e, f) reduction(&& : g, arr[0:argc][:10]) +#ifdef OMP60 +#pragma omp parallel allocate(e) if (b) num_threads(strict: c) proc_bind(close) reduction(^:e, f) reduction(&& : g, arr[0:argc][:10]) +// OMP60-NEXT: #pragma omp parallel allocate(e) if(b) num_threads(strict: c) proc_bind(close) reduction(^: e,f) reduction(&&: g,arr[0:argc][:10]) foo(); +// OMP60-NEXT: foo() +#endif return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x); } diff --git a/clang/test/OpenMP/parallel_num_threads_messages.cpp b/clang/test/OpenMP/parallel_num_threads_messages.cpp index 0e50c7e1eb2a7..02c1cb6e69d99 100644 --- a/clang/test/OpenMP/parallel_num_threads_messages.cpp +++ b/clang/test/OpenMP/parallel_num_threads_messages.cpp @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s -Wuninitialized - // RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP60 -verify=expected,omp60 -fopenmp -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP60 -verify=expected,omp60 -fopenmp-simd -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized + void foo() { } @@ -9,11 +11,11 @@ bool foobool(int argc) { return argc; } -struct S1; // expected-note {{declared here}} +struct S1; // expected-note {{declared here}} omp60-note {{declared here}} #define redef_num_threads(a, b) num_threads(a) -template <class T, typename S, int N> // expected-note {{declared here}} +template <class T, typename S, int N> // expected-note {{declared here}} omp60-note {{declared here}} T tmain(T argc, S **argv) { T z; #pragma omp parallel num_threads // expected-error {{expected '(' after 'num_threads'}} @@ -28,6 +30,39 @@ T tmain(T argc, S **argv) { #pragma omp parallel num_threads (argc+z) #pragma omp parallel num_threads (N) // expected-error {{argument to 'num_threads' clause must be a strictly positive integer value}} #pragma omp parallel redef_num_threads (argc, argc) + +#ifdef OMP60 + // Valid uses of strict modifier + #pragma omp parallel num_threads(strict: 4) + #pragma omp parallel num_threads(strict: argc+z) + + // Invalid: missing expression after strict: + #pragma omp parallel num_threads(strict: ) // omp60-error {{expected expression}} + #pragma omp parallel num_threads(strict:) // omp60-error {{expected expression}} + #pragma omp parallel num_threads(strict: // omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + + // Invalid: unknown/missing modifier + #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected 'strict' in OpenMP clause 'num_threads'}} + #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + #pragma omp parallel num_threads(:)// omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + + // Invalid: missing colon after modifier + #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':' after strict modifier}} + + // Invalid: negative, zero, or non-integral + #pragma omp parallel num_threads(strict: -1) // omp60-error {{argument to 'num_threads' clause must be a strictly positive integer value}} + #pragma omp parallel num_threads(strict: 0) // omp60-error {{argument to 'num_threads' clause must be a strictly positive integer value}} + #pragma omp parallel num_threads(strict: (argc > 0) ? argv[1] : argv[2]) // omp60-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads(strict: S) // omp60-error {{'S' does not refer to a value}} + #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error {{expected ')'}} omp60-note {{to match this '('}} omp60-error 2 {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads(strict: N) // omp60-error {{argument to 'num_threads' clause must be a strictly positive integer value}} + + // Invalid: multiple strict modifiers or mixed with non-strict + #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads(strict: 4), num_threads(5) // omp60-error {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} + #pragma omp parallel num_threads(4), num_threads(strict: 5) // omp60-error {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} +#endif // OMP60 + foo(); return argc; @@ -46,6 +81,38 @@ int z; #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression must have integral or unscoped enumeration type, not 'char *'}} #pragma omp parallel num_threads (num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of function template specialization 'tmain<int, char, -1>' requested here}} #pragma omp parallel redef_num_threads (argc, argc) + +#ifdef OMP60 + // Valid uses of strict modifier + #pragma omp parallel num_threads(strict: 4) + #pragma omp parallel num_threads(strict: argc+z) + + // Invalid: missing expression after strict: + #pragma omp parallel num_threads(strict: ) // omp60-error {{expected expression}} + #pragma omp parallel num_threads(strict:) // omp60-error {{expected expression}} + #pragma omp parallel num_threads(strict: // omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + + // Invalid: unknown/missing modifier + #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected 'strict' in OpenMP clause 'num_threads'}} + #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + #pragma omp parallel num_threads(:) // omp60-error {{expected expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}} + + // Invalid: missing colon after modifier + #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':' after strict modifier}} + + // Invalid: negative, zero, or non-integral + #pragma omp parallel num_threads(strict: -1) // omp60-error {{argument to 'num_threads' clause must be a strictly positive integer value}} + #pragma omp parallel num_threads(strict: 0) // omp60-error {{argument to 'num_threads' clause must be a strictly positive integer value}} + #pragma omp parallel num_threads(strict: (argc > 0) ? argv[1] : argv[2]) // omp60-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + #pragma omp parallel num_threads(strict: S1) // omp60-error {{'S1' does not refer to a value}} + #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error {{expected ')'}} omp60-note {{to match this '('}} omp60-error {{expression must have integral or unscoped enumeration type, not 'char *'}} + + // Invalid: multiple strict modifiers or mixed with non-strict + #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads(strict: 4), num_threads(5) // omp60-error {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} + #pragma omp parallel num_threads(4), num_threads(strict: 5) // omp60-error {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} +#endif // OMP60 + foo(); return tmain<int, char, 3>(argc, argv); // expected-note {{in instantiation of function template specialization 'tmain<int, char, 3>' requested here}} diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index a87111cb5a11d..b37c28477fb34 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -355,9 +355,16 @@ def OMPC_NumTeams : Clause<[Spelling<"num_teams">]> { let clangClass = "OMPNumTeamsClause"; let flangClass = "ScalarIntExpr"; } +def OMP_NUMTHREADS_Strict : EnumVal<"strict", 1, 1> {} +def OMP_NUMTHREADS_Unknown : EnumVal<"unknown", 2, 0> { let isDefault = 1; } def OMPC_NumThreads : Clause<[Spelling<"num_threads">]> { let clangClass = "OMPNumThreadsClause"; let flangClass = "ScalarIntExpr"; + let enumClauseValue = "NumThreadsType"; + let allowedClauseValues = [ + OMP_NUMTHREADS_Strict, + OMP_NUMTHREADS_Unknown + ]; } def OMPC_OMPX_Attribute : Clause<[Spelling<"ompx_attribute">]> { let clangClass = "OMPXAttributeClause"; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits