[flang-commits] [flang] 3519dcf - Added OpenMP 5.0 specification based semantic checks for atomic update construct
Nimish Mishra via flang-commits
flang-commits at lists.llvm.org
Sun Jan 23 23:54:08 PST 2022
Author: Nimish Mishra
Date: 2022-01-24T13:24:00+05:30
New Revision: 3519dcfec22963fbb84e154cecc2df22e6c7724f
URL: https://github.com/llvm/llvm-project/commit/3519dcfec22963fbb84e154cecc2df22e6c7724f
DIFF: https://github.com/llvm/llvm-project/commit/3519dcfec22963fbb84e154cecc2df22e6c7724f.diff
LOG: Added OpenMP 5.0 specification based semantic checks for atomic update construct
Added:
flang/test/Semantics/omp-atomic02.f90
flang/test/Semantics/omp-atomic03.f90
flang/test/Semantics/omp-atomic04.f90
flang/test/Semantics/omp-atomic05.f90
Modified:
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/test/Semantics/omp-atomic01.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index df66a42dede52..802fdf650a07c 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1324,13 +1324,163 @@ void OmpStructureChecker::Leave(const parser::OmpEndBlockDirective &x) {
}
}
+template <typename T, typename D>
+bool OmpStructureChecker::IsOperatorValid(const T &node, const D &variable) {
+ using AllowedBinaryOperators =
+ std::variant<parser::Expr::Add, parser::Expr::Multiply,
+ parser::Expr::Subtract, parser::Expr::Divide, parser::Expr::AND,
+ parser::Expr::OR, parser::Expr::EQV, parser::Expr::NEQV>;
+ using BinaryOperators = std::variant<parser::Expr::Add,
+ parser::Expr::Multiply, parser::Expr::Subtract, parser::Expr::Divide,
+ parser::Expr::AND, parser::Expr::OR, parser::Expr::EQV,
+ parser::Expr::NEQV, parser::Expr::Power, parser::Expr::Concat,
+ parser::Expr::LT, parser::Expr::LE, parser::Expr::EQ, parser::Expr::NE,
+ parser::Expr::GE, parser::Expr::GT>;
+
+ if constexpr (common::HasMember<T, BinaryOperators>) {
+ const auto &variableName{variable.GetSource().ToString()};
+ const auto &exprLeft{std::get<0>(node.t)};
+ const auto &exprRight{std::get<1>(node.t)};
+ if ((exprLeft.value().source.ToString() != variableName) &&
+ (exprRight.value().source.ToString() != variableName)) {
+ context_.Say(variable.GetSource(),
+ "Atomic update variable '%s' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct"_err_en_US,
+ variableName);
+ }
+ return common::HasMember<T, AllowedBinaryOperators>;
+ }
+ return true;
+}
+
+void OmpStructureChecker::CheckAtomicUpdateAssignmentStmt(
+ const parser::AssignmentStmt &assignment) {
+ const auto &expr{std::get<parser::Expr>(assignment.t)};
+ const auto &var{std::get<parser::Variable>(assignment.t)};
+ std::visit(
+ common::visitors{
+ [&](const common::Indirection<parser::FunctionReference> &x) {
+ const auto &procedureDesignator{
+ std::get<parser::ProcedureDesignator>(x.value().v.t)};
+ const parser::Name *name{
+ std::get_if<parser::Name>(&procedureDesignator.u)};
+ if (name &&
+ !(name->source == "max" || name->source == "min" ||
+ name->source == "iand" || name->source == "ior" ||
+ name->source == "ieor")) {
+ context_.Say(expr.source,
+ "Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement"_err_en_US);
+ } else if (name) {
+ bool foundMatch{false};
+ if (auto varDesignatorIndirection =
+ std::get_if<Fortran::common::Indirection<
+ Fortran::parser::Designator>>(&var.u)) {
+ const auto &varDesignator = varDesignatorIndirection->value();
+ if (const auto *dataRef = std::get_if<Fortran::parser::DataRef>(
+ &varDesignator.u)) {
+ if (const auto *name =
+ std::get_if<Fortran::parser::Name>(&dataRef->u)) {
+ const auto &varSymbol = *name->symbol;
+ if (const auto *e{GetExpr(expr)}) {
+ for (const Symbol &symbol :
+ evaluate::CollectSymbols(*e)) {
+ if (symbol == varSymbol) {
+ foundMatch = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!foundMatch) {
+ context_.Say(expr.source,
+ "Atomic update variable '%s' not found in the argument list of intrinsic procedure"_err_en_US,
+ var.GetSource().ToString());
+ }
+ }
+ },
+ [&](const auto &x) {
+ if (!IsOperatorValid(x, var)) {
+ context_.Say(expr.source,
+ "Invalid operator in OpenMP ATOMIC (UPDATE) statement"_err_en_US);
+ }
+ },
+ },
+ expr.u);
+}
+
+void OmpStructureChecker::CheckAtomicMemoryOrderClause(
+ const parser::OmpAtomicClauseList &clauseList) {
+ int numMemoryOrderClause = 0;
+ for (const auto &clause : clauseList.v) {
+ if (std::get_if<Fortran::parser::OmpMemoryOrderClause>(&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;
+ }
+ }
+ }
+}
+
+void OmpStructureChecker::CheckAtomicMemoryOrderClause(
+ const parser::OmpAtomicClauseList &leftHandClauseList,
+ const parser::OmpAtomicClauseList &rightHandClauseList) {
+ int numMemoryOrderClause = 0;
+ for (const auto &clause : leftHandClauseList.v) {
+ if (std::get_if<Fortran::parser::OmpMemoryOrderClause>(&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;
+ }
+ }
+ }
+ for (const auto &clause : rightHandClauseList.v) {
+ if (std::get_if<Fortran::parser::OmpMemoryOrderClause>(&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;
+ }
+ }
+ }
+}
+
void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
std::visit(
common::visitors{
- [&](const auto &someAtomicConstruct) {
- const auto &dir{std::get<parser::Verbatim>(someAtomicConstruct.t)};
+ [&](const parser::OmpAtomic &atomicConstruct) {
+ const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
+ PushContextAndClauseSets(
+ dir.source, llvm::omp::Directive::OMPD_atomic);
+ CheckAtomicUpdateAssignmentStmt(
+ std::get<parser::Statement<parser::AssignmentStmt>>(
+ atomicConstruct.t)
+ .statement);
+ CheckAtomicMemoryOrderClause(
+ std::get<parser::OmpAtomicClauseList>(atomicConstruct.t));
+ },
+ [&](const parser::OmpAtomicUpdate &atomicConstruct) {
+ const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
+ PushContextAndClauseSets(
+ dir.source, llvm::omp::Directive::OMPD_atomic);
+ CheckAtomicUpdateAssignmentStmt(
+ std::get<parser::Statement<parser::AssignmentStmt>>(
+ atomicConstruct.t)
+ .statement);
+ CheckAtomicMemoryOrderClause(
+ std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t));
+ },
+ [&](const auto &atomicConstruct) {
+ const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
PushContextAndClauseSets(
dir.source, llvm::omp::Directive::OMPD_atomic);
+ CheckAtomicMemoryOrderClause(
+ std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t));
},
},
x.u);
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index bf98f360ed58b..88005ad4b64d5 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -229,6 +229,12 @@ class OmpStructureChecker
void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
+ template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
+ void CheckAtomicMemoryOrderClause(
+ const parser::OmpAtomicClauseList &, const parser::OmpAtomicClauseList &);
+ void CheckAtomicMemoryOrderClause(const parser::OmpAtomicClauseList &);
+ void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &);
+ void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
void CheckSIMDNest(const parser::OpenMPConstruct &x);
void CheckTargetNest(const parser::OpenMPConstruct &x);
diff --git a/flang/test/Semantics/omp-atomic01.f90 b/flang/test/Semantics/omp-atomic01.f90
index 9f9e26f9081f9..b668de202c17e 100644
--- a/flang/test/Semantics/omp-atomic01.f90
+++ b/flang/test/Semantics/omp-atomic01.f90
@@ -12,152 +12,184 @@
! At most one memory-order-clause may appear on the construct.
!READ
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the READ directive
!$omp atomic seq_cst seq_cst read
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the READ directive
!$omp atomic read seq_cst seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the READ directive
!$omp atomic seq_cst read seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the READ directive
!$omp atomic acquire acquire read
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the READ directive
!$omp atomic read acquire acquire
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the READ directive
!$omp atomic acquire read acquire
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the READ directive
!$omp atomic relaxed relaxed read
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the READ directive
!$omp atomic read relaxed relaxed
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the READ directive
!$omp atomic relaxed read relaxed
i = j
!UPDATE
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
!$omp atomic seq_cst seq_cst update
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
!$omp atomic update seq_cst seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
!$omp atomic seq_cst update seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the UPDATE directive
!$omp atomic release release update
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the UPDATE directive
!$omp atomic update release release
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the UPDATE directive
!$omp atomic release update release
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the UPDATE directive
!$omp atomic relaxed relaxed update
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the UPDATE directive
!$omp atomic update relaxed relaxed
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the UPDATE directive
!$omp atomic relaxed update relaxed
i = j
!CAPTURE
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive
!$omp atomic seq_cst seq_cst capture
i = j
j = k
!$omp end atomic
-
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive
!$omp atomic capture seq_cst seq_cst
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive
!$omp atomic seq_cst capture seq_cst
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the CAPTURE directive
!$omp atomic release release capture
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the CAPTURE directive
!$omp atomic capture release release
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the CAPTURE directive
!$omp atomic release capture release
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the CAPTURE directive
!$omp atomic relaxed relaxed capture
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the CAPTURE directive
!$omp atomic capture relaxed relaxed
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the CAPTURE directive
!$omp atomic relaxed capture relaxed
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive
!$omp atomic acq_rel acq_rel capture
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive
!$omp atomic capture acq_rel acq_rel
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive
!$omp atomic acq_rel capture acq_rel
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive
!$omp atomic acquire acquire capture
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive
!$omp atomic capture acquire acquire
i = j
j = k
!$omp end atomic
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive
!$omp atomic acquire capture acquire
i = j
@@ -165,43 +197,55 @@
!$omp end atomic
!WRITE
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the WRITE directive
!$omp atomic seq_cst seq_cst write
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the WRITE directive
!$omp atomic write seq_cst seq_cst
i = j
+
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the WRITE directive
!$omp atomic seq_cst write seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the WRITE directive
!$omp atomic release release write
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the WRITE directive
!$omp atomic write release release
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the WRITE directive
!$omp atomic release write release
i = j
-
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the WRITE directive
!$omp atomic relaxed relaxed write
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the WRITE directive
!$omp atomic write relaxed relaxed
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the WRITE directive
!$omp atomic relaxed write relaxed
i = j
!No atomic-clause
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELAXED clause can appear on the ATOMIC directive
!$omp atomic relaxed relaxed
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive
!$omp atomic seq_cst seq_cst
i = j
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
!ERROR: At most one RELEASE clause can appear on the ATOMIC directive
!$omp atomic release release
i = j
diff --git a/flang/test/Semantics/omp-atomic02.f90 b/flang/test/Semantics/omp-atomic02.f90
new file mode 100644
index 0000000000000..ec04fda86afc5
--- /dev/null
+++ b/flang/test/Semantics/omp-atomic02.f90
@@ -0,0 +1,109 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -fopenmp
+
+! OpenMP Atomic construct
+! section 2.17.7
+! operator is one of +, *, -, /, .AND., .OR., .EQV., or .NEQV
+
+program OmpAtomic
+ use omp_lib
+ CHARACTER c*3, d*3
+ LOGICAL l, m, n
+
+ a = 1
+ b = 2
+ c = 'foo'
+ d = 'bar'
+ m = .TRUE.
+ n = .FALSE.
+ !$omp parallel num_threads(4)
+
+ !$omp atomic
+ a = a + (4*2)
+ !$omp atomic
+ a = a*(b + 1)
+ !$omp atomic
+ a = a - 3
+ !$omp atomic
+ a = a/(b + 1)
+ !$omp atomic
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ a = a**4
+ !$omp atomic
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ c = c//d
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .LT. b
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .LE. b
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .EQ. b
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .NE. b
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .GE. b
+ !$omp atomic
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .GT. b
+ !$omp atomic
+ m = m .AND. n
+ !$omp atomic
+ m = m .OR. n
+ !$omp atomic
+ m = m .EQV. n
+ !$omp atomic
+ m = m .NEQV. n
+ !$omp atomic update
+ a = a + (4*2)
+ !$omp atomic update
+ a = a*(b + 1)
+ !$omp atomic update
+ a = a - 3
+ !$omp atomic update
+ a = a/(b + 1)
+ !$omp atomic update
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ a = a**4
+ !$omp atomic update
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ c = c//d
+ !$omp atomic update
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .LT. b
+ !$omp atomic update
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .LE. b
+ !$omp atomic update
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .EQ. b
+ !$omp atomic update
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .GE. b
+ !$omp atomic update
+ !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement
+ l = a .GT. b
+ !$omp atomic update
+ m = m .AND. n
+ !$omp atomic update
+ m = m .OR. n
+ !$omp atomic update
+ m = m .EQV. n
+ !$omp atomic update
+ m = m .NEQV. n
+ !$omp end parallel
+end program OmpAtomic
diff --git a/flang/test/Semantics/omp-atomic03.f90 b/flang/test/Semantics/omp-atomic03.f90
new file mode 100644
index 0000000000000..4262416fa9930
--- /dev/null
+++ b/flang/test/Semantics/omp-atomic03.f90
@@ -0,0 +1,93 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -fopenmp
+
+! OpenMP Atomic construct
+! section 2.17.7
+! Intrinsic procedure name is one of MAX, MIN, IAND, IOR, or IEOR.
+
+program OmpAtomic
+ use omp_lib
+ real x
+ integer :: y, z, a, b, c, d
+ x = 5.73
+ y = 3
+ z = 1
+!$omp atomic
+ y = IAND(y, 4)
+!$omp atomic
+ y = IOR(y, 5)
+!$omp atomic
+ y = IEOR(y, 6)
+!$omp atomic
+ y = MAX(y, 7)
+!$omp atomic
+ y = MIN(y, 8)
+
+!$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IAND(y, 4)
+!$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IOR(y, 5)
+!$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IEOR(y, 6)
+!$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = MAX(y, 7, b, c)
+!$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = MIN(y, 8, a, d)
+
+!$omp atomic
+ !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement
+ y = FRACTION(x)
+!$omp atomic
+ !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement
+ y = REAL(x)
+!$omp atomic update
+ y = IAND(y, 4)
+!$omp atomic update
+ y = IOR(y, 5)
+!$omp atomic update
+ y = IEOR(y, 6)
+!$omp atomic update
+ y = MAX(y, 7)
+!$omp atomic update
+ y = MIN(y, 8)
+
+!$omp atomic update
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IAND(y, 4)
+!$omp atomic update
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IOR(y, 5)
+!$omp atomic update
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IEOR(y, 6)
+!$omp atomic update
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = MAX(y, 7)
+!$omp atomic update
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = MIN(y, 8)
+
+!$omp atomic update
+ !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement
+ y = MOD(y, 9)
+!$omp atomic update
+ !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement
+ x = ABS(x)
+end program OmpAtomic
+
+subroutine conflicting_types()
+ type simple
+ integer :: z
+ end type
+ real x
+ integer :: y, z
+ type(simple) ::s
+ z = 1
+ !$omp atomic
+ !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure
+ z = IAND(s%z, 4)
+end subroutine
diff --git a/flang/test/Semantics/omp-atomic04.f90 b/flang/test/Semantics/omp-atomic04.f90
new file mode 100644
index 0000000000000..15b832cd3bcdc
--- /dev/null
+++ b/flang/test/Semantics/omp-atomic04.f90
@@ -0,0 +1,168 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -fopenmp
+
+! OpenMP Atomic construct
+! section 2.17.7
+! Update assignment must be 'var = var op expr' or 'var = expr op var'
+
+program OmpAtomic
+ use omp_lib
+ real x
+ integer y
+ logical m, n, l
+ x = 5.73
+ y = 3
+ m = .TRUE.
+ n = .FALSE.
+!$omp atomic
+ x = x + 1
+!$omp atomic
+ x = 1 + x
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y + 1
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1 + y
+
+!$omp atomic
+ x = x - 1
+!$omp atomic
+ x = 1 - x
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y - 1
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1 - y
+
+!$omp atomic
+ x = x*1
+!$omp atomic
+ x = 1*x
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y*1
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1*y
+
+!$omp atomic
+ x = x/1
+!$omp atomic
+ x = 1/x
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y/1
+!$omp atomic
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1/y
+
+!$omp atomic
+ m = m .AND. n
+!$omp atomic
+ m = n .AND. m
+!$omp atomic
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .AND. l
+
+!$omp atomic
+ m = m .OR. n
+!$omp atomic
+ m = n .OR. m
+!$omp atomic
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .OR. l
+
+!$omp atomic
+ m = m .EQV. n
+!$omp atomic
+ m = n .EQV. m
+!$omp atomic
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .EQV. l
+
+!$omp atomic
+ m = m .NEQV. n
+!$omp atomic
+ m = n .NEQV. m
+!$omp atomic
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .NEQV. l
+
+!$omp atomic update
+ x = x + 1
+!$omp atomic update
+ x = 1 + x
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y + 1
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1 + y
+
+!$omp atomic update
+ x = x - 1
+!$omp atomic update
+ x = 1 - x
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y - 1
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1 - y
+
+!$omp atomic update
+ x = x*1
+!$omp atomic update
+ x = 1*x
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y*1
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1*y
+
+!$omp atomic update
+ x = x/1
+!$omp atomic update
+ x = 1/x
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = y/1
+!$omp atomic update
+ !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ x = 1/y
+
+!$omp atomic update
+ m = m .AND. n
+!$omp atomic update
+ m = n .AND. m
+!$omp atomic update
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .AND. l
+
+!$omp atomic update
+ m = m .OR. n
+!$omp atomic update
+ m = n .OR. m
+!$omp atomic update
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .OR. l
+
+!$omp atomic update
+ m = m .EQV. n
+!$omp atomic update
+ m = n .EQV. m
+!$omp atomic update
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .EQV. l
+
+!$omp atomic update
+ m = m .NEQV. n
+!$omp atomic update
+ m = n .NEQV. m
+!$omp atomic update
+ !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct
+ m = n .NEQV. l
+
+end program OmpAtomic
diff --git a/flang/test/Semantics/omp-atomic05.f90 b/flang/test/Semantics/omp-atomic05.f90
new file mode 100644
index 0000000000000..1ff13d6cd29ce
--- /dev/null
+++ b/flang/test/Semantics/omp-atomic05.f90
@@ -0,0 +1,26 @@
+! RUN: %python %S/test_errors.py %s %flang -fopenmp
+
+! This tests the various semantics related to the clauses of various OpenMP atomic constructs
+
+program OmpAtomic
+ use omp_lib
+ integer :: g, x
+
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !$omp atomic relaxed, seq_cst
+ x = x + 1
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !$omp atomic read seq_cst, relaxed
+ x = g
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !$omp atomic write relaxed, release
+ x = 2 * 4
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !$omp atomic update release, seq_cst
+ x = 10
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !$omp atomic capture release, seq_cst
+ x = g
+ g = x * 10
+ !$omp end atomic
+end program OmpAtomic
More information about the flang-commits
mailing list