Skip to content
2 changes: 1 addition & 1 deletion clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ implementation.
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
| pure directives in DO CONCURRENT | | :none:`unclaimed` | |
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
| Optional argument for all clauses | :none:`unclaimed` | :none:`unclaimed` | |
| Optional argument for all clauses | :none:`partial` | :none:`In Progress` | Parse/Sema (nowait): https://github.com/llvm/llvm-project/pull/159628 |
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
| Function references for locator list items | :none:`unclaimed` | :none:`unclaimed` | |
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ OpenMP Support
- Added support for ``defaultmap`` directive implicit-behavior ``private``.
- Added parsing and semantic analysis support for ``groupprivate`` directive.
- Added support for 'omp fuse' directive.
- Updated parsing and semantic analysis support for ``nowait`` clause to accept
optional argument in OpenMP >= 60.

Improvements
^^^^^^^^^^^^
Expand Down
64 changes: 57 additions & 7 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -2291,18 +2291,68 @@ class OMPOrderedClause final
/// This represents 'nowait' clause in the '#pragma omp ...' directive.
///
/// \code
/// #pragma omp for nowait
/// #pragma omp for nowait (cond)
/// \endcode
/// In this example directive '#pragma omp for' has 'nowait' clause.
class OMPNowaitClause final : public OMPNoChildClause<llvm::omp::OMPC_nowait> {
/// In this example directive '#pragma omp for' has simple 'nowait' clause with
/// condition 'cond'.
class OMPNowaitClause final : public OMPClause {
friend class OMPClauseReader;

/// Location of '('.
SourceLocation LParenLoc;

/// Condition of the 'nowait' clause.
Stmt *Condition = nullptr;

/// Set condition.
void setCondition(Expr *Cond) { Condition = Cond; }

public:
/// Build 'nowait' clause.
/// Build 'nowait' clause with condition \a Cond.
///
/// \param Cond Condition of the clause.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPNowaitClause(SourceLocation StartLoc = SourceLocation(),
SourceLocation EndLoc = SourceLocation())
: OMPNoChildClause(StartLoc, EndLoc) {}
OMPNowaitClause(Expr *Cond, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_nowait, StartLoc, EndLoc),
LParenLoc(LParenLoc), Condition(Cond) {}

/// Build an empty clause.
OMPNowaitClause()
: OMPClause(llvm::omp::OMPC_nowait, SourceLocation(), SourceLocation()) {}

/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }

/// Returns the location of '('.
SourceLocation getLParenLoc() const { return LParenLoc; }

/// Returns condition.
Expr *getCondition() const { return cast_or_null<Expr>(Condition); }

child_range children() {
if (Condition)
return child_range(&Condition, &Condition + 1);
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
if (Condition)
return const_child_range(&Condition, &Condition + 1);
return const_child_range(const_child_iterator(), const_child_iterator());
}

child_range used_children();
const_child_range used_children() const {
auto Children = const_cast<OMPNowaitClause *>(this)->used_children();
return const_child_range(Children.begin(), Children.end());
}

static bool classof(const OMPClause *T) {
return T->getClauseKind() == llvm::omp::OMPC_nowait;
}
};

/// This represents 'untied' clause in the '#pragma omp ...' directive.
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3594,7 +3594,8 @@ bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) {
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNowaitClause(OMPNowaitClause *) {
bool RecursiveASTVisitor<Derived>::VisitOMPNowaitClause(OMPNowaitClause *C) {
TRY_TO(TraverseStmt(C->getCondition()));
return true;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Sema/SemaOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,8 @@ class SemaOpenMP : public SemaBase {
SourceLocation EndLoc);
/// Called on well-formed 'nowait' clause.
OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc,
SourceLocation EndLoc);
SourceLocation EndLoc,
SourceLocation LParenLoc, Expr *Condition);
/// Called on well-formed 'untied' clause.
OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc,
SourceLocation EndLoc);
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/AST/OpenMPClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ OMPClause::child_range OMPIfClause::used_children() {
return child_range(&Condition, &Condition + 1);
}

OMPClause::child_range OMPNowaitClause::used_children() {
if (Condition)
return child_range(&Condition, &Condition + 1);
return children();
}

OMPClause::child_range OMPGrainsizeClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
Expand Down Expand Up @@ -2113,8 +2119,13 @@ void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *Node) {
}
}

void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *) {
void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *Node) {
OS << "nowait";
if (auto *Cond = Node->getCondition()) {
OS << "(";
Cond->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
}

void OMPClausePrinter::VisitOMPUntiedClause(OMPUntiedClause *) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,10 @@ void OMPClauseProfiler::VisitOMPOrderedClause(const OMPOrderedClause *C) {
Profiler->VisitStmt(Num);
}

void OMPClauseProfiler::VisitOMPNowaitClause(const OMPNowaitClause *) {}
void OMPClauseProfiler::VisitOMPNowaitClause(const OMPNowaitClause *C) {
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}

void OMPClauseProfiler::VisitOMPUntiedClause(const OMPUntiedClause *) {}

Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3311,7 +3311,11 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
ErrorFound = true;
}

Clause = ParseOpenMPClause(CKind, WrongDirective);
if (CKind == OMPC_nowait && PP.LookAhead(/*N=*/0).is(tok::l_paren) &&
getLangOpts().OpenMP >= 60)
Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
else
Clause = ParseOpenMPClause(CKind, WrongDirective);
break;
case OMPC_self_maps:
// OpenMP [6.0, self_maps clause]
Expand Down
27 changes: 23 additions & 4 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16491,6 +16491,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
case OMPC_nowait:
Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
case OMPC_priority:
Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
Expand Down Expand Up @@ -16546,7 +16549,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
Expand Down Expand Up @@ -17955,7 +17957,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind,
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc);
break;
case OMPC_nowait:
Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc);
Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc,
/*LParenLoc=*/SourceLocation(),
/*Condition=*/nullptr);
break;
case OMPC_untied:
Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc);
Expand Down Expand Up @@ -18107,9 +18111,24 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind,
}

OMPClause *SemaOpenMP::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
SourceLocation EndLoc,
SourceLocation LParenLoc,
Expr *Condition) {
Expr *ValExpr = Condition;
if (Condition && LParenLoc.isValid()) {
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
ExprResult Val = SemaRef.CheckBooleanCondition(StartLoc, Condition);
if (Val.isInvalid())
return nullptr;

ValExpr = Val.get();
}
}
DSAStack->setNowaitRegion();
return new (getASTContext()) OMPNowaitClause(StartLoc, EndLoc);
return new (getASTContext())
OMPNowaitClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}

OMPClause *SemaOpenMP::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
Expand Down
21 changes: 19 additions & 2 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,17 @@ class TreeTransform {
LParenLoc, Num);
}

/// Build a new OpenMP 'nowait' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPNowaitClause(Expr *Condition, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().OpenMP().ActOnOpenMPNowaitClause(StartLoc, EndLoc,
LParenLoc, Condition);
}

/// Build a new OpenMP 'private' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
Expand Down Expand Up @@ -10612,8 +10623,14 @@ TreeTransform<Derived>::TransformOMPDetachClause(OMPDetachClause *C) {
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPNowaitClause(OMPNowaitClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
ExprResult Cond;
if (auto *Condition = C->getCondition()) {
Cond = getDerived().TransformExpr(Condition);
if (Cond.isInvalid())
return nullptr;
}
return getDerived().RebuildOMPNowaitClause(Cond.get(), C->getBeginLoc(),
C->getLParenLoc(), C->getEndLoc());
}

template <typename Derived>
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11684,7 +11684,10 @@ void OMPClauseReader::VisitOMPDetachClause(OMPDetachClause *C) {
C->setLParenLoc(Record.readSourceLocation());
}

void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {}
void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *C) {
C->setCondition(Record.readSubExpr());
C->setLParenLoc(Record.readSourceLocation());
}

void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7942,7 +7942,10 @@ void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) {
Record.AddSourceLocation(C->getLParenLoc());
}

void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {}
void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *C) {
Record.AddStmt(C->getCondition());
Record.AddSourceLocation(C->getLParenLoc());
}

void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {}

Expand Down
55 changes: 55 additions & 0 deletions clang/test/OpenMP/nowait_ast_print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Check no warnings/errors
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -fsyntax-only -verify %s
// expected-no-diagnostics

// Check AST and unparsing
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -ast-dump %s | FileCheck %s --check-prefix=DUMP
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -ast-print %s | FileCheck %s --check-prefix=PRINT

// Check same results after serialization round-trip
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -emit-pch -o %t %s
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT

#ifndef HEADER
#define HEADER

void nowait() {
int A=1;

// DUMP: OMPTargetDirective
// DUMP-NEXT: OMPNowaitClause
// PRINT: #pragma omp target nowait
#pragma omp target nowait
{
}

// DUMP: OMPTargetDirective
// DUMP-NEXT: OMPNowaitClause
// DUMP-NEXT: XXBoolLiteralExpr {{.*}} 'bool' false
// PRINT: #pragma omp target nowait(false)
#pragma omp target nowait(false)
{
}

// DUMP: OMPTargetDirective
// DUMP-NEXT: OMPNowaitClause
// DUMP-NEXT: XXBoolLiteralExpr {{.*}} 'bool' true
// PRINT: #pragma omp target nowait(true)
#pragma omp target nowait(true)
{
}

// DUMP: OMPTargetDirective
// DUMP-NEXT: OMPNowaitClause
// DUMP-NEXT: BinaryOperator {{.*}} 'bool' '>'
// DUMP-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
// DUMP-NEXT: DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'A' 'int'
// DUMP-NEXT: IntegerLiteral {{.*}} 'int' 5
// PRINT: #pragma omp target nowait(A > 5)
#pragma omp target nowait(A>5)
{
}

}
#endif
30 changes: 22 additions & 8 deletions clang/test/OpenMP/target_enter_data_nowait_messages.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp -fopenmp-version=45 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp -fopenmp-version=51 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp -fopenmp-version=52 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp -fopenmp-version=60 -verify=expected,omp-60-and-later -ferror-limit 100 -o - %s -Wuninitialized

// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp-simd -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp-simd -fopenmp-version=45 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp-simd -fopenmp-version=51 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp-simd -fopenmp-version=52 -verify=expected,omp-52-and-earlier -ferror-limit 100 -o - %s -Wuninitialized
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fopenmp-simd -fopenmp-version=60 -verify=expected,omp-60-and-later -ferror-limit 100 -o - %s -Wuninitialized

int main(int argc, char **argv) {
int i;
Expand All @@ -13,19 +19,27 @@ int main(int argc, char **argv) {
{}
#pragma omp target enter nowait data map(to: i) // expected-error {{expected an OpenMP directive}}
{}
#pragma omp target enter data nowait() map(to: i) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} expected-error {{expected at least one 'map' clause for '#pragma omp target enter data'}}
#pragma omp target enter data map(to: i) nowait() // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} omp-60-and-later-error {{expected expression}}
{}
#pragma omp target enter data map(to: i) nowait( // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
#pragma omp target enter data map(to: i) nowait( // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} omp-60-and-later-error {{expected expression}} omp-60-and-later-error {{expected ')'}} omp-60-and-later-note {{to match this '('}}
{}
#pragma omp target enter data map(to: i) nowait (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
#pragma omp target enter data map(to: i) nowait (argc)) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} omp-60-and-later-warning {{extra tokens at the end of '#pragma omp target_enter_data' are ignored}}
{}
#pragma omp target enter data map(to: i) nowait device (-10u)
{}
#pragma omp target enter data map(to: i) nowait (3.14) device (-10u) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
#pragma omp target enter data map(to: i) nowait (3.14) device (-10u) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
{}
#pragma omp target enter data map(to: i) nowait nowait // expected-error {{directive '#pragma omp target enter data' cannot contain more than one 'nowait' clause}}
#pragma omp target enter data map(to: i) nowait (argc>> i) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
{}
#pragma omp target enter data nowait map(to: i) nowait // expected-error {{directive '#pragma omp target enter data' cannot contain more than one 'nowait' clause}}
#pragma omp target enter data map(to: i) nowait (argv[1] = 2) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} omp-60-and-later-error {{expected ')'}} omp-60-and-later-note {{to match this '('}}
{}
#pragma omp target enter data map(to: i) nowait (argc > 0 ? argv[1] : argv[2]) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
{}
#pragma omp target enter data map(to: i) nowait (S1) // omp-52-and-earlier-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} omp-60-and-later-error {{use of undeclared identifier 'S1'}}
{}
#pragma omp target enter data map(to: i) nowait nowait // omp-52-and-earlier-error {{directive '#pragma omp target enter data' cannot contain more than one 'nowait' clause}} omp-60-and-later-error {{directive '#pragma omp target_enter_data' cannot contain more than one 'nowait' clause}}
{}
#pragma omp target enter data nowait map(to: i) nowait // omp-52-and-earlier-error {{directive '#pragma omp target enter data' cannot contain more than one 'nowait' clause}} omp-60-and-later-error {{directive '#pragma omp target_enter_data' cannot contain more than one 'nowait' clause}}
{}
return 0;
}
Loading