From 50cdcf65c9f21dc80f3867960bc8b3daa6b09bd5 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Wed, 19 Feb 2025 08:54:19 +0000 Subject: [PATCH 1/8] [Flang][OpenMP] Allow copyprivate and nowait on the directive clauses Issue: - Single construct used to throw semantic error for copyprivate and nowiat clause when used in the single directive. - Also, the Nowait and copyprivate restrictions has be removed from OpenMP 6.0 Fix: - The above mentioned semantic error was valid until OpenMP 5.1. - From OpenMP 5.2, copyprivate and nowait is allowed in both clause and end-clause From Reference guide (OpenMP 5.2, 2.10.2): ``` !$omp single [clause[ [,]clause] ... ] loosely-structured-block !$omp end single [end-clause[ [,]end-clause] ...] clause: copyprivate (list) nowait [...] end-clause: copyprivate (list) nowait ``` --- flang/lib/Semantics/check-omp-structure.cpp | 57 ++++++++++++++++--- .../Semantics/OpenMP/clause-validity01.f90 | 6 +- flang/test/Semantics/OpenMP/single03.f90 | 54 ++++++++++++++++++ .../test/Semantics/OpenMP/threadprivate04.f90 | 2 +- 4 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 flang/test/Semantics/OpenMP/single03.f90 diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 1d6fe6c8d4249..93f71c1951658 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1203,6 +1203,40 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { deviceConstructFound_ = true; } + unsigned version{context_.langOptions().OpenMPVersion}; + if (version >= 52 && + GetContext().directive == llvm::omp::Directive::OMPD_single) { + bool foundCopyPrivate{false}; + bool foundNowait{false}; + parser::CharBlock NowaitSource{""}; + auto catchCopyPrivateNowaitClauses = [&](const auto &dir) { + for (auto &clause : std::get(dir.t).v) { + if (clause.Id() == llvm::omp::Clause::OMPC_copyprivate) { + if (foundCopyPrivate) { + context_.Say(clause.source, + "At most one COPYPRIVATE clause can appear on the SINGLE directive"_err_en_US); + } else { + foundCopyPrivate = true; + } + } else if (clause.Id() == llvm::omp::Clause::OMPC_nowait) { + if (foundNowait) { + context_.Say(clause.source, + "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US); + } else { + foundNowait = true; + NowaitSource = clause.source; + } + } + } + }; + catchCopyPrivateNowaitClauses(beginBlockDir); + catchCopyPrivateNowaitClauses(endBlockDir); + if (version == 52 && foundCopyPrivate && foundNowait) { + context_.Say(NowaitSource, + "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US); + } + } + switch (beginDir.v) { case llvm::omp::Directive::OMPD_target: if (CheckTargetBlockOnlyTeams(block)) { @@ -2853,7 +2887,8 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) { CheckMultListItems(); // 2.7.3 Single Construct Restriction - if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) { + if (context_.langOptions().OpenMPVersion < 52 && + GetContext().directive == llvm::omp::Directive::OMPD_end_single) { CheckNotAllowedIfClause( llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); } @@ -3481,14 +3516,16 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_nowait); - if (llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) { + if (context_.langOptions().OpenMPVersion < 52 && + llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) { + std::string dirName{ + parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())}; context_.Say(GetContext().clauseSource, "%s clause is not allowed on the OMP %s directive," - " use it on OMP END %s directive "_err_en_US, + " use it on OMP END %s directive or %s"_err_en_US, parser::ToUpperCaseLetters( getClauseName(llvm::omp::Clause::OMPC_nowait).str()), - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()), - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())); + dirName, dirName, TryVersion(52)); } } @@ -4220,14 +4257,16 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) { CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_copyprivate); CheckCopyingPolymorphicAllocatable( symbols, llvm::omp::Clause::OMPC_copyprivate); - if (GetContext().directive == llvm::omp::Directive::OMPD_single) { + if (context_.langOptions().OpenMPVersion < 52 && + GetContext().directive == llvm::omp::Directive::OMPD_single) { + std::string dirName{ + parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())}; context_.Say(GetContext().clauseSource, "%s clause is not allowed on the OMP %s directive," - " use it on OMP END %s directive "_err_en_US, + " use it on OMP END %s directive or %s"_err_en_US, parser::ToUpperCaseLetters( getClauseName(llvm::omp::Clause::OMPC_copyprivate).str()), - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()), - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())); + dirName, dirName, TryVersion(52)); } } diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index e8114154a809b..0349a5a760753 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -330,7 +330,7 @@ !$omp parallel b = 1 !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive - !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive + !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52 !$omp single private(a) lastprivate(c) nowait a = 3.14 !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive @@ -351,7 +351,7 @@ a = 1.0 !ERROR: COPYPRIVATE clause is not allowed on the END WORKSHARE directive !$omp end workshare nowait copyprivate(a) - !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive + !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive or try -fopenmp-version=52 !$omp workshare nowait !$omp end workshare !$omp end parallel @@ -420,7 +420,7 @@ !$omp parallel !ERROR: No ORDERED clause with a parameter can be specified on the DO SIMD directive !ERROR: NOGROUP clause is not allowed on the DO SIMD directive - !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive + !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive or try -fopenmp-version=52 !$omp do simd ordered(2) NOGROUP nowait do i = 1, N do j = 1, N diff --git a/flang/test/Semantics/OpenMP/single03.f90 b/flang/test/Semantics/OpenMP/single03.f90 new file mode 100644 index 0000000000000..bc7647b66e39f --- /dev/null +++ b/flang/test/Semantics/OpenMP/single03.f90 @@ -0,0 +1,54 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52 +! +! OpenMP Version 5.2 +! +! 2.10.2 single Construct +! Copyprivate and Nowait clauses are allowed in both clause and end clause + +subroutine omp_single + integer, save :: i + integer :: j + i = 10; j = 11 + + !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp single copyprivate(i) nowait + print *, "omp single", i + !$omp end single + + !$omp parallel private(i) + !$omp single copyprivate(i) + print *, "omp single", i + !$omp end single + !$omp end parallel + + !$omp parallel + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp single nowait + print *, "omp single", i + !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(i) + + !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context + !$omp single copyprivate(i) + print *, "omp single", i + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp end single nowait + + !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !$omp single private(j) copyprivate(j) + print *, "omp single", j + !ERROR: At most one COPYPRIVATE clause can appear on the SINGLE directive + !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !$omp end single copyprivate(j) + + !$omp single nowait + print *, "omp single", j + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !$omp end single nowait + !$omp end parallel + + !$omp single nowait + print *, "omp single", i + !$omp end single +end subroutine omp_single diff --git a/flang/test/Semantics/OpenMP/threadprivate04.f90 b/flang/test/Semantics/OpenMP/threadprivate04.f90 index 3d8c7fb8de8fa..db23cdb06ed96 100644 --- a/flang/test/Semantics/OpenMP/threadprivate04.f90 +++ b/flang/test/Semantics/OpenMP/threadprivate04.f90 @@ -14,7 +14,7 @@ program main !$omp parallel num_threads(x1) !$omp end parallel - !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive + !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52 !$omp single copyprivate(x2, /blk1/) !$omp end single From 2ebb099bac421c7faa310227d0c97e84899b689c Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Mon, 24 Feb 2025 06:18:34 +0000 Subject: [PATCH 2/8] [Flang] Remove semantic checks for Copyprivate and nowait --- flang/lib/Semantics/check-omp-structure.cpp | 32 +++---------------- .../Semantics/OpenMP/clause-validity01.f90 | 9 ++---- .../test/Semantics/OpenMP/threadprivate04.f90 | 1 - 3 files changed, 7 insertions(+), 35 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 93f71c1951658..af609cc89a336 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1203,9 +1203,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { deviceConstructFound_ = true; } - unsigned version{context_.langOptions().OpenMPVersion}; - if (version >= 52 && - GetContext().directive == llvm::omp::Directive::OMPD_single) { + if (GetContext().directive == llvm::omp::Directive::OMPD_single) { bool foundCopyPrivate{false}; bool foundNowait{false}; parser::CharBlock NowaitSource{""}; @@ -1231,7 +1229,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { }; catchCopyPrivateNowaitClauses(beginBlockDir); catchCopyPrivateNowaitClauses(endBlockDir); - if (version == 52 && foundCopyPrivate && foundNowait) { + unsigned version{context_.langOptions().OpenMPVersion}; + if (version <= 52 && foundCopyPrivate && foundNowait) { context_.Say(NowaitSource, "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US); } @@ -2887,8 +2886,7 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) { CheckMultListItems(); // 2.7.3 Single Construct Restriction - if (context_.langOptions().OpenMPVersion < 52 && - GetContext().directive == llvm::omp::Directive::OMPD_end_single) { + if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) { CheckNotAllowedIfClause( llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); } @@ -3516,17 +3514,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_nowait); - if (context_.langOptions().OpenMPVersion < 52 && - llvm::omp::noWaitClauseNotAllowedSet.test(GetContext().directive)) { - std::string dirName{ - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())}; - context_.Say(GetContext().clauseSource, - "%s clause is not allowed on the OMP %s directive," - " use it on OMP END %s directive or %s"_err_en_US, - parser::ToUpperCaseLetters( - getClauseName(llvm::omp::Clause::OMPC_nowait).str()), - dirName, dirName, TryVersion(52)); - } } bool OmpStructureChecker::IsDataRefTypeParamInquiry( @@ -4257,17 +4244,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) { CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_copyprivate); CheckCopyingPolymorphicAllocatable( symbols, llvm::omp::Clause::OMPC_copyprivate); - if (context_.langOptions().OpenMPVersion < 52 && - GetContext().directive == llvm::omp::Directive::OMPD_single) { - std::string dirName{ - parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())}; - context_.Say(GetContext().clauseSource, - "%s clause is not allowed on the OMP %s directive," - " use it on OMP END %s directive or %s"_err_en_US, - parser::ToUpperCaseLetters( - getClauseName(llvm::omp::Clause::OMPC_copyprivate).str()), - dirName, dirName, TryVersion(52)); - } } void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) { diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 0349a5a760753..f6a252d8c7535 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -330,7 +330,6 @@ !$omp parallel b = 1 !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive - !ERROR: NOWAIT clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52 !$omp single private(a) lastprivate(c) nowait a = 3.14 !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive @@ -351,7 +350,6 @@ a = 1.0 !ERROR: COPYPRIVATE clause is not allowed on the END WORKSHARE directive !$omp end workshare nowait copyprivate(a) - !ERROR: NOWAIT clause is not allowed on the OMP WORKSHARE directive, use it on OMP END WORKSHARE directive or try -fopenmp-version=52 !$omp workshare nowait !$omp end workshare !$omp end parallel @@ -420,7 +418,6 @@ !$omp parallel !ERROR: No ORDERED clause with a parameter can be specified on the DO SIMD directive !ERROR: NOGROUP clause is not allowed on the DO SIMD directive - !ERROR: NOWAIT clause is not allowed on the OMP DO SIMD directive, use it on OMP END DO SIMD directive or try -fopenmp-version=52 !$omp do simd ordered(2) NOGROUP nowait do i = 1, N do j = 1, N @@ -428,7 +425,7 @@ enddo enddo !omp end do nowait - !$omp end parallel + !$omp end parallel ! 2.11.4 parallel-do-simd-clause -> parallel-clause | ! do-simd-clause @@ -586,7 +583,7 @@ allc = 3.14 enddo - !$omp target enter data map(alloc:A) device(0) - !$omp target exit data map(delete:A) device(0) + !$omp target enter data map(alloc:A) device(0) + !$omp target exit data map(delete:A) device(0) end program diff --git a/flang/test/Semantics/OpenMP/threadprivate04.f90 b/flang/test/Semantics/OpenMP/threadprivate04.f90 index db23cdb06ed96..d261f33b4dbd7 100644 --- a/flang/test/Semantics/OpenMP/threadprivate04.f90 +++ b/flang/test/Semantics/OpenMP/threadprivate04.f90 @@ -14,7 +14,6 @@ program main !$omp parallel num_threads(x1) !$omp end parallel - !ERROR: COPYPRIVATE clause is not allowed on the OMP SINGLE directive, use it on OMP END SINGLE directive or try -fopenmp-version=52 !$omp single copyprivate(x2, /blk1/) !$omp end single From 656864e62a088d432e25b8b62a3ed2a1ef74c7c9 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Mon, 24 Feb 2025 07:32:33 +0000 Subject: [PATCH 3/8] Fix failures --- flang/test/Semantics/OpenMP/clause-validity01.f90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index f6a252d8c7535..9d1c932b59456 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -330,10 +330,13 @@ !$omp parallel b = 1 !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive !$omp single private(a) lastprivate(c) nowait a = 3.14 !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive !$omp end single copyprivate(a) nowait nowait c = 2 From 6cbaf66bc0041f223307d95b97d88a53a97cb8cb Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Mon, 24 Feb 2025 09:01:51 +0000 Subject: [PATCH 4/8] Remove duplicate checks --- flang/lib/Semantics/check-omp-structure.cpp | 6 ------ flang/test/Semantics/OpenMP/clause-validity01.f90 | 7 +++---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index af609cc89a336..e2afff9d4120a 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2885,12 +2885,6 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) { // clause CheckMultListItems(); - // 2.7.3 Single Construct Restriction - if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) { - CheckNotAllowedIfClause( - llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); - } - auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name, llvmOmpClause clauseTy) { if (sym.test(Symbol::Flag::OmpThreadprivate)) diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 9d1c932b59456..5e0d91914c441 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -333,7 +333,6 @@ !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive !$omp single private(a) lastprivate(c) nowait a = 3.14 - !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !ERROR: At most one NOWAIT clause can appear on the SINGLE directive @@ -428,7 +427,7 @@ enddo enddo !omp end do nowait - !$omp end parallel + !$omp end parallel ! 2.11.4 parallel-do-simd-clause -> parallel-clause | ! do-simd-clause @@ -586,7 +585,7 @@ allc = 3.14 enddo - !$omp target enter data map(alloc:A) device(0) - !$omp target exit data map(delete:A) device(0) + !$omp target enter data map(alloc:A) device(0) + !$omp target exit data map(delete:A) device(0) end program From eebd6c6a3c69dcd3d5fbf29a0f1114717f6c11d4 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Fri, 28 Feb 2025 10:47:14 +0000 Subject: [PATCH 5/8] Fix Copyprivate clause semantics check Changes: - Throw error for repeated list items in the copyprivate clause - Throw warnings for repeated use of copyprivate and nowait in the end directive --- flang/lib/Semantics/check-omp-structure.cpp | 72 ++++++++++++++----- .../Semantics/OpenMP/clause-validity01.f90 | 4 +- flang/test/Semantics/OpenMP/single03.f90 | 4 +- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index e2afff9d4120a..9d75d308b28f8 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1204,33 +1204,71 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { } if (GetContext().directive == llvm::omp::Directive::OMPD_single) { - bool foundCopyPrivate{false}; - bool foundNowait{false}; - parser::CharBlock NowaitSource{""}; - auto catchCopyPrivateNowaitClauses = [&](const auto &dir) { + std::set singleCopyprivateSyms; + std::set endSingleCopyprivateSyms; + bool singleNowait{false}; + bool endSingleNowait{false}; + parser::CharBlock NowaitSource; + + auto catchCopyPrivateNowaitClauses = [&](const auto &dir, bool endDir) { for (auto &clause : std::get(dir.t).v) { if (clause.Id() == llvm::omp::Clause::OMPC_copyprivate) { - if (foundCopyPrivate) { - context_.Say(clause.source, - "At most one COPYPRIVATE clause can appear on the SINGLE directive"_err_en_US); - } else { - foundCopyPrivate = true; + for (const auto &ompObject : GetOmpObjectList(clause)->v) { + const auto *name{parser::Unwrap(ompObject)}; + if (Symbol * symbol{name->symbol}) { + if (singleCopyprivateSyms.count(symbol)) { + if (endDir) { + context_.Warn(common::UsageWarning::OpenMPUsage, name->source, + "The COPYPRIVATE clause with '%s' is already used on the SINGLE directive"_warn_en_US, + name->ToString()); + } else { + context_.Say(name->source, + "'%s' appears in more than one COPYPRIVATE clause on the SINGLE directive"_err_en_US, + name->ToString()); + } + } else if (endSingleCopyprivateSyms.count(symbol)) { + context_.Say(name->source, + "'%s' appears in more than one COPYPRIVATE clause on the END SINGLE directive"_err_en_US, + name->ToString()); + } else { + if (endDir) { + endSingleCopyprivateSyms.insert(symbol); + } else { + singleCopyprivateSyms.insert(symbol); + } + } + } } } else if (clause.Id() == llvm::omp::Clause::OMPC_nowait) { - if (foundNowait) { + if (singleNowait) { + if (endDir) { + context_.Warn(common::UsageWarning::OpenMPUsage, clause.source, + "NOWAIT clause is already used on the SINGLE directive"_warn_en_US); + } else { + context_.Say(clause.source, + "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US); + } + } else if (endSingleNowait) { context_.Say(clause.source, - "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US); + "At most one NOWAIT clause can appear on the END SINGLE directive"_err_en_US); } else { - foundNowait = true; + if (endDir) { + endSingleNowait = true; + } else { + singleNowait = true; + } + } + if (!NowaitSource.ToString().size()) { NowaitSource = clause.source; } } } }; - catchCopyPrivateNowaitClauses(beginBlockDir); - catchCopyPrivateNowaitClauses(endBlockDir); + catchCopyPrivateNowaitClauses(beginBlockDir, false); + catchCopyPrivateNowaitClauses(endBlockDir, true); unsigned version{context_.langOptions().OpenMPVersion}; - if (version <= 52 && foundCopyPrivate && foundNowait) { + if (version <= 52 && NowaitSource.ToString().size() && + (singleCopyprivateSyms.size() || endSingleCopyprivateSyms.size())) { context_.Say(NowaitSource, "NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive"_err_en_US); } @@ -1818,8 +1856,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPDispatchConstruct &x) { auto it{block.begin()}; bool passChecks{false}; - if (const parser::AssignmentStmt * - assignStmt{parser::Unwrap(*it)}) { + if (const parser::AssignmentStmt *assignStmt{ + parser::Unwrap(*it)}) { if (parser::Unwrap(assignStmt->t)) { passChecks = true; } diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 5e0d91914c441..9b9981306f15b 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -334,8 +334,8 @@ !$omp single private(a) lastprivate(c) nowait a = 3.14 !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct - !ERROR: At most one NOWAIT clause can appear on the SINGLE directive - !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive !$omp end single copyprivate(a) nowait nowait c = 2 diff --git a/flang/test/Semantics/OpenMP/single03.f90 b/flang/test/Semantics/OpenMP/single03.f90 index bc7647b66e39f..86b46546b971a 100644 --- a/flang/test/Semantics/OpenMP/single03.f90 +++ b/flang/test/Semantics/OpenMP/single03.f90 @@ -38,13 +38,13 @@ subroutine omp_single !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct !$omp single private(j) copyprivate(j) print *, "omp single", j - !ERROR: At most one COPYPRIVATE clause can appear on the SINGLE directive !ERROR: COPYPRIVATE variable 'j' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !WARNING: The COPYPRIVATE clause with 'j' is already used on the SINGLE directive !$omp end single copyprivate(j) !$omp single nowait print *, "omp single", j - !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive !$omp end single nowait !$omp end parallel From 292203e6e290669ee2a10f108cde22c0b474250f Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Fri, 28 Feb 2025 10:47:33 +0000 Subject: [PATCH 6/8] Add a test --- flang/test/Semantics/OpenMP/single04.f90 | 81 ++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 flang/test/Semantics/OpenMP/single04.f90 diff --git a/flang/test/Semantics/OpenMP/single04.f90 b/flang/test/Semantics/OpenMP/single04.f90 new file mode 100644 index 0000000000000..c223b8c83db20 --- /dev/null +++ b/flang/test/Semantics/OpenMP/single04.f90 @@ -0,0 +1,81 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52 +! +! OpenMP Version 5.2 +! +! 2.10.2 single Construct +! Valid and invalid testcases for copyprivate and nowait clause on the single directive + +program single + ! Valid testcases + !$omp single + print *, x + !$omp end single + + !$omp single nowait + print *, x + !$omp end single + + !$omp single copyprivate(x, y, z) + print *, x + !$omp end single + + !$omp single + print *, x + !$omp end single copyprivate(x) + + ! Invalid testcases + !$omp single + print *, x + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp end single copyprivate(x) nowait + + !ERROR: 'x' appears in more than one COPYPRIVATE clause on the SINGLE directive + !$omp single copyprivate(x) copyprivate(x) + print *, x + !$omp end single + + !$omp single + print *, x + !ERROR: 'x' appears in more than one COPYPRIVATE clause on the END SINGLE directive + !$omp end single copyprivate(x) copyprivate(x) + + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !$omp single nowait nowait + print *, x + !$omp end single + + !$omp single + print *, x + !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive + !$omp end single nowait nowait + + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp single copyprivate(x) nowait + print *, x + !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive + !$omp end single copyprivate(x) nowait + + !$omp single copyprivate(x) + print *, x + !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp end single copyprivate(x) nowait + + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp single copyprivate(x, y) nowait + print *, x + !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive + !ERROR: 'z' appears in more than one COPYPRIVATE clause on the END SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive + !$omp end single copyprivate(x, z) copyprivate(z) nowait + + !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive + !$omp single copyprivate(x) nowait copyprivate(y) copyprivate(z) + print *, x + !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive + !WARNING: The COPYPRIVATE clause with 'y' is already used on the SINGLE directive + !WARNING: The COPYPRIVATE clause with 'z' is already used on the SINGLE directive + !WARNING: NOWAIT clause is already used on the SINGLE directive + !$omp end single copyprivate(x, y, z) nowait +end program From 5168d4e1f1045638ac49a03f72ec3348eca14bfc Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Fri, 28 Feb 2025 11:46:05 +0000 Subject: [PATCH 7/8] Fix clang format --- flang/lib/Semantics/check-omp-structure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 9d75d308b28f8..f4cd6dc47f6a9 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1856,8 +1856,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPDispatchConstruct &x) { auto it{block.begin()}; bool passChecks{false}; - if (const parser::AssignmentStmt *assignStmt{ - parser::Unwrap(*it)}) { + if (const parser::AssignmentStmt * + assignStmt{parser::Unwrap(*it)}) { if (parser::Unwrap(assignStmt->t)) { passChecks = true; } From 87b7aaccc0f477a896997b36fd6189ed90bfc0b3 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Mon, 3 Mar 2025 06:37:32 +0000 Subject: [PATCH 8/8] Fix: Allow nowait only once --- flang/lib/Semantics/check-omp-structure.cpp | 21 ++++--------------- .../Semantics/OpenMP/clause-validity01.f90 | 4 ++-- flang/test/Semantics/OpenMP/single03.f90 | 2 +- flang/test/Semantics/OpenMP/single04.f90 | 6 +++--- llvm/include/llvm/Frontend/OpenMP/OMP.td | 4 +++- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index f4cd6dc47f6a9..a30b39b42cac5 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1206,8 +1206,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { if (GetContext().directive == llvm::omp::Directive::OMPD_single) { std::set singleCopyprivateSyms; std::set endSingleCopyprivateSyms; - bool singleNowait{false}; - bool endSingleNowait{false}; + bool foundNowait{false}; parser::CharBlock NowaitSource; auto catchCopyPrivateNowaitClauses = [&](const auto &dir, bool endDir) { @@ -1240,23 +1239,11 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { } } } else if (clause.Id() == llvm::omp::Clause::OMPC_nowait) { - if (singleNowait) { - if (endDir) { - context_.Warn(common::UsageWarning::OpenMPUsage, clause.source, - "NOWAIT clause is already used on the SINGLE directive"_warn_en_US); - } else { - context_.Say(clause.source, - "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US); - } - } else if (endSingleNowait) { + if (foundNowait) { context_.Say(clause.source, - "At most one NOWAIT clause can appear on the END SINGLE directive"_err_en_US); + "At most one NOWAIT clause can appear on the SINGLE directive"_err_en_US); } else { - if (endDir) { - endSingleNowait = true; - } else { - singleNowait = true; - } + foundNowait = !endDir; } if (!NowaitSource.ToString().size()) { NowaitSource = clause.source; diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 9b9981306f15b..5e0d91914c441 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -334,8 +334,8 @@ !$omp single private(a) lastprivate(c) nowait a = 3.14 !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct - !WARNING: NOWAIT clause is already used on the SINGLE directive - !WARNING: NOWAIT clause is already used on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive !$omp end single copyprivate(a) nowait nowait c = 2 diff --git a/flang/test/Semantics/OpenMP/single03.f90 b/flang/test/Semantics/OpenMP/single03.f90 index 86b46546b971a..dc2c2fd27eb04 100644 --- a/flang/test/Semantics/OpenMP/single03.f90 +++ b/flang/test/Semantics/OpenMP/single03.f90 @@ -44,7 +44,7 @@ subroutine omp_single !$omp single nowait print *, "omp single", j - !WARNING: NOWAIT clause is already used on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !$omp end single nowait !$omp end parallel diff --git a/flang/test/Semantics/OpenMP/single04.f90 b/flang/test/Semantics/OpenMP/single04.f90 index c223b8c83db20..9505745c600e9 100644 --- a/flang/test/Semantics/OpenMP/single04.f90 +++ b/flang/test/Semantics/OpenMP/single04.f90 @@ -53,7 +53,7 @@ program single !$omp single copyprivate(x) nowait print *, x !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive - !WARNING: NOWAIT clause is already used on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !$omp end single copyprivate(x) nowait !$omp single copyprivate(x) @@ -67,7 +67,7 @@ program single print *, x !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive !ERROR: 'z' appears in more than one COPYPRIVATE clause on the END SINGLE directive - !WARNING: NOWAIT clause is already used on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !$omp end single copyprivate(x, z) copyprivate(z) nowait !ERROR: NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive @@ -76,6 +76,6 @@ program single !WARNING: The COPYPRIVATE clause with 'x' is already used on the SINGLE directive !WARNING: The COPYPRIVATE clause with 'y' is already used on the SINGLE directive !WARNING: The COPYPRIVATE clause with 'z' is already used on the SINGLE directive - !WARNING: NOWAIT clause is already used on the SINGLE directive + !ERROR: At most one NOWAIT clause can appear on the SINGLE directive !$omp end single copyprivate(x, y, z) nowait end program diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 210acbff5af20..11c3c3379925f 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -998,9 +998,11 @@ def OMP_Single : Directive<"single"> { VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, ]; + let allowedOnceClauses = [ + VersionedClause, + ]; let association = AS_Block; let category = CA_Executable; }