[clang] f624ba2 - [OpenMP][clang] 6.0: parsing/sema for num_threads 'strict' modifier (#145490)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 24 12:12:44 PDT 2025
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";
More information about the cfe-commits
mailing list