[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