diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -232,8 +232,9 @@ void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); template bool IsOperatorValid(const T &, const D &); void CheckAtomicMemoryOrderClause( - const parser::OmpAtomicClauseList &, const parser::OmpAtomicClauseList &); - void CheckAtomicMemoryOrderClause(const parser::OmpAtomicClauseList &); + const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); + void CheckAtomicHintClause( + const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &); void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1543,46 +1543,60 @@ } void OmpStructureChecker::CheckAtomicMemoryOrderClause( - const parser::OmpAtomicClauseList &clauseList) { + const parser::OmpAtomicClauseList *leftHandClauseList, + const parser::OmpAtomicClauseList *rightHandClauseList) { int numMemoryOrderClause = 0; - for (const auto &clause : clauseList.v) { - if (std::get_if(&clause.u)) { - numMemoryOrderClause++; - if (numMemoryOrderClause > 1) { - context_.Say(clause.source, - "More than one memory order clause not allowed on OpenMP " - "Atomic construct"_err_en_US); - return; - } - } - } -} + auto checkForValidMemoryOrderClause = + [&](const parser::OmpAtomicClauseList *clauseList) { + for (const auto &clause : clauseList->v) { + if (std::get_if(&clause.u)) { + numMemoryOrderClause++; + if (numMemoryOrderClause > 1) { + context_.Say(clause.source, + "More than one memory order clause not allowed on " + "OpenMP Atomic construct"_err_en_US); + return; + } + } + } + }; + if (leftHandClauseList) { + checkForValidMemoryOrderClause(leftHandClauseList); + } + if (rightHandClauseList) { + checkForValidMemoryOrderClause(rightHandClauseList); + } +} + +void OmpStructureChecker::CheckAtomicHintClause( + const parser::OmpAtomicClauseList *leftOmpAtomicClauseList, + const parser::OmpAtomicClauseList *rightOmpAtomicClauseList) { + + auto checkForValidHintClause = + [&](const parser::OmpAtomicClauseList *clauseList) { + for (const auto &clause : clauseList->v) { + if (const auto ompClause = + std::get_if(&clause.u)) { + if (auto hintClause = std::get_if( + &ompClause->u)) { + if (auto evaluatedValue{GetIntValue(hintClause->v)}) { + int hintValue = evaluatedValue.value(); + if (hintValue != 0x0 && hintValue != 0x1 && hintValue != 0x2 && + hintValue != 0x4 && hintValue != 0x8) + context_.Say(clause.source, + "Hint clause value " + "is not a valid OpenMP synchronization value"_err_en_US); + } + } + } + } + }; -void OmpStructureChecker::CheckAtomicMemoryOrderClause( - const parser::OmpAtomicClauseList &leftHandClauseList, - const parser::OmpAtomicClauseList &rightHandClauseList) { - int numMemoryOrderClause = 0; - for (const auto &clause : leftHandClauseList.v) { - if (std::get_if(&clause.u)) { - numMemoryOrderClause++; - if (numMemoryOrderClause > 1) { - context_.Say(clause.source, - "More than one memory order clause not allowed on " - "OpenMP Atomic construct"_err_en_US); - return; - } - } + if (leftOmpAtomicClauseList) { + checkForValidHintClause(leftOmpAtomicClauseList); } - for (const auto &clause : rightHandClauseList.v) { - if (std::get_if(&clause.u)) { - numMemoryOrderClause++; - if (numMemoryOrderClause > 1) { - context_.Say(clause.source, - "More than one memory order clause not " - "allowed on OpenMP Atomic construct"_err_en_US); - return; - } - } + if (rightOmpAtomicClauseList) { + checkForValidHintClause(rightOmpAtomicClauseList); } } @@ -1598,25 +1612,33 @@ atomicConstruct.t) .statement); CheckAtomicMemoryOrderClause( - std::get(atomicConstruct.t)); + &std::get(atomicConstruct.t), + nullptr); + CheckAtomicHintClause( + &std::get(atomicConstruct.t), + nullptr); }, - [&](const parser::OmpAtomicUpdate &atomicConstruct) { - const auto &dir{std::get(atomicConstruct.t)}; + [&](const parser::OmpAtomicUpdate &atomicUpdate) { + const auto &dir{std::get(atomicUpdate.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); CheckAtomicUpdateAssignmentStmt( std::get>( - atomicConstruct.t) + atomicUpdate.t) .statement); CheckAtomicMemoryOrderClause( - std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t)); + &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t)); + CheckAtomicHintClause( + &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t)); }, [&](const auto &atomicConstruct) { const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicMemoryOrderClause( - std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t)); + CheckAtomicMemoryOrderClause(&std::get<0>(atomicConstruct.t), + &std::get<2>(atomicConstruct.t)); + CheckAtomicHintClause(&std::get<0>(atomicConstruct.t), + &std::get<2>(atomicConstruct.t)); }, }, x.u); diff --git a/flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90 b/flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90 @@ -0,0 +1,48 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! Semantic checks on hint clauses, as they appear on atomic constructs + +program sample + use omp_lib + integer :: x, y + !$omp atomic hint(1) write + y = 2 + + !$omp atomic read hint(2) + y = x + + !ERROR: Hint clause value is not a valid OpenMP synchronization value + !$omp atomic hint(3) + y = y + 10 + + !ERROR: Hint clause value is not a valid OpenMP synchronization value + !$omp atomic update hint(5) + y = x + + !ERROR: Hint clause value is not a valid OpenMP synchronization value + !$omp atomic hint(7) capture + y = x + x = y + !$omp end atomic + + !ERROR: Must be a constant value + !$omp atomic update hint(x) + y = y * 1 + + !$omp atomic read hint(4) + y = x + + !$omp atomic hint(8) + x = x * y + + !$omp atomic write hint(omp_sync_hint_uncontended) + x = 10 * y + + !$omp atomic hint(omp_lock_hint_speculative) + x = y + x + + !$omp atomic hint(omp_sync_hint_uncontended) read + y = x + + !$omp atomic hint(omp_sync_hint_nonspeculative) + y = y * 9 +end program