[llvm] e43b3b0 - [Flang][OpenMP] Semantic checks for Atomic construct.

Sameeran joshi via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 13 23:34:52 PST 2020


Author: sameeran joshi
Date: 2020-12-14T13:03:57+05:30
New Revision: e43b3b08ccd60d63d4c3316859e9fec4cdaeaddd

URL: https://github.com/llvm/llvm-project/commit/e43b3b08ccd60d63d4c3316859e9fec4cdaeaddd
DIFF: https://github.com/llvm/llvm-project/commit/e43b3b08ccd60d63d4c3316859e9fec4cdaeaddd.diff

LOG: [Flang][OpenMP] Semantic checks for Atomic construct.

Patch implements restrictions from 2.17.7  of OpenMP 5.0 standard for atomic Construct. Tests for the same are added.

One of the restriction
`OpenMP constructs may not be encountered during execution of an atomic region.`
Is mentioned in 5.0 standard to be a semantic restriction, but given the stricter nature of parser in F18 it's caught at parsing itself.

This patch is a next patch in series from D88965.

Reviewed By: clementval

Differential Revision: https://reviews.llvm.org/D89583

Added: 
    flang/test/Semantics/omp-atomic01.f90

Modified: 
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/openmp-parsers.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/test/Semantics/omp-atomic.f90
    llvm/include/llvm/Frontend/OpenMP/OMP.td

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 791e21fa4b62..0d819f861495 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -551,6 +551,8 @@ class ParseTreeDumper {
   NODE(parser, OpenMPDeclareSimdConstruct)
   NODE(parser, OpenMPDeclareTargetConstruct)
   NODE(parser, OmpMemoryOrderClause)
+  NODE(parser, OmpAtomicClause)
+  NODE(parser, OmpAtomicClauseList)
   NODE(parser, OpenMPFlushConstruct)
   NODE(parser, OpenMPLoopConstruct)
   NODE(parser, OpenMPExecutableAllocate)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index ca73af210c15..5d2909a4142a 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3628,11 +3628,30 @@ struct OpenMPExecutableAllocate {
       t;
 };
 
-// 2.17.7 atomic -> ATOMIC [clause[,]] atomic-clause [[,]clause] |
-//                  ATOMIC [clause]
-//        clause -> memory-order-clause | HINT(hint-expression)
-//        memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED
-//        atomic-clause -> READ | WRITE | UPDATE | CAPTURE
+// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
+//        memory-order-clause -> acq_rel
+//                               release
+//                               acquire
+//                               seq_cst
+//                               relaxed
+struct OmpMemoryOrderClause {
+  WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause);
+  CharBlock source;
+};
+
+// 2.17.7 Atomic construct
+//        atomic-clause -> memory-order-clause | HINT(hint-expression)
+struct OmpAtomicClause {
+  UNION_CLASS_BOILERPLATE(OmpAtomicClause);
+  CharBlock source;
+  std::variant<OmpMemoryOrderClause, OmpClause> u;
+};
+
+// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
+struct OmpAtomicClauseList {
+  WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
+  CharBlock source;
+};
 
 // END ATOMIC
 EMPTY_CLASS(OmpEndAtomic);
@@ -3641,8 +3660,8 @@ EMPTY_CLASS(OmpEndAtomic);
 struct OmpAtomicRead {
   TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
   CharBlock source;
-  std::tuple<OmpClauseList, Verbatim, OmpClauseList, Statement<AssignmentStmt>,
-      std::optional<OmpEndAtomic>>
+  std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
+      Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
       t;
 };
 
@@ -3650,8 +3669,8 @@ struct OmpAtomicRead {
 struct OmpAtomicWrite {
   TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
   CharBlock source;
-  std::tuple<OmpClauseList, Verbatim, OmpClauseList, Statement<AssignmentStmt>,
-      std::optional<OmpEndAtomic>>
+  std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
+      Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
       t;
 };
 
@@ -3659,8 +3678,8 @@ struct OmpAtomicWrite {
 struct OmpAtomicUpdate {
   TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
   CharBlock source;
-  std::tuple<OmpClauseList, Verbatim, OmpClauseList, Statement<AssignmentStmt>,
-      std::optional<OmpEndAtomic>>
+  std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
+      Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
       t;
 };
 
@@ -3670,7 +3689,8 @@ struct OmpAtomicCapture {
   CharBlock source;
   WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
   WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
-  std::tuple<OmpClauseList, Verbatim, OmpClauseList, Stmt1, Stmt2, OmpEndAtomic>
+  std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
+      OmpEndAtomic>
       t;
 };
 
@@ -3678,11 +3698,15 @@ struct OmpAtomicCapture {
 struct OmpAtomic {
   TUPLE_CLASS_BOILERPLATE(OmpAtomic);
   CharBlock source;
-  std::tuple<Verbatim, OmpClauseList, Statement<AssignmentStmt>,
+  std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
       std::optional<OmpEndAtomic>>
       t;
 };
 
+// 2.17.7 atomic ->
+//        ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
+//        ATOMIC [atomic-clause-list]
+//        atomic-construct -> READ | WRITE | UPDATE | CAPTURE
 struct OpenMPAtomicConstruct {
   UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
   std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
@@ -3718,14 +3742,6 @@ struct OpenMPCancelConstruct {
   std::tuple<Verbatim, OmpCancelType, std::optional<If>> t;
 };
 
-// 2.17.8 Flush Construct [OpenMP 5.0]
-// memory-order-clause -> acq_rel
-//                        release
-//                        acquire
-struct OmpMemoryOrderClause {
-  WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause);
-  CharBlock source;
-};
 
 // 2.17.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)]
 struct OpenMPFlushConstruct {

diff  --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 69fc4f0e67ee..fd209abc4138 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -318,6 +318,18 @@ TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
         "ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
         "RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>())))))
 
+// 2.17.7 Atomic construct
+//        atomic-clause -> memory-order-clause | HINT(hint-expression)
+TYPE_PARSER(sourced(construct<OmpAtomicClause>(
+    construct<OmpAtomicClause>(Parser<OmpMemoryOrderClause>{}) ||
+    construct<OmpAtomicClause>("HINT" >>
+        sourced(construct<OmpClause>(
+            construct<OmpClause::Hint>(parenthesized(constantExpr))))))))
+
+// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
+TYPE_PARSER(sourced(construct<OmpAtomicClauseList>(
+    many(maybe(","_tok) >> sourced(Parser<OmpAtomicClause>{})))))
+
 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
     maybe(Parser<OmpMemoryOrderClause>{}),
     maybe(parenthesized(Parser<OmpObjectList>{})))))
@@ -409,32 +421,32 @@ TYPE_PARSER(construct<OmpEndAtomic>(startOmpLine >> "END ATOMIC"_tok))
 
 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST]
 TYPE_PARSER("ATOMIC" >>
-    construct<OmpAtomicRead>(Parser<OmpClauseList>{} / maybe(","_tok),
-        verbatim("READ"_tok), Parser<OmpClauseList>{} / endOmpLine,
+    construct<OmpAtomicRead>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
+        verbatim("READ"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
 
 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST]
 TYPE_PARSER("ATOMIC" >>
-    construct<OmpAtomicCapture>(Parser<OmpClauseList>{} / maybe(","_tok),
-        verbatim("CAPTURE"_tok), Parser<OmpClauseList>{} / endOmpLine,
+    construct<OmpAtomicCapture>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
+        verbatim("CAPTURE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
         statement(assignmentStmt), statement(assignmentStmt),
         Parser<OmpEndAtomic>{} / endOmpLine))
 
 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST]
 TYPE_PARSER("ATOMIC" >>
-    construct<OmpAtomicUpdate>(Parser<OmpClauseList>{} / maybe(","_tok),
-        verbatim("UPDATE"_tok), Parser<OmpClauseList>{} / endOmpLine,
+    construct<OmpAtomicUpdate>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
+        verbatim("UPDATE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
 
-// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST]
+// OMP ATOMIC [atomic-clause-list]
 TYPE_PARSER(construct<OmpAtomic>(verbatim("ATOMIC"_tok),
-    Parser<OmpClauseList>{} / endOmpLine, statement(assignmentStmt),
+    Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
     maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
 
 // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST]
 TYPE_PARSER("ATOMIC" >>
-    construct<OmpAtomicWrite>(Parser<OmpClauseList>{} / maybe(","_tok),
-        verbatim("WRITE"_tok), Parser<OmpClauseList>{} / endOmpLine,
+    construct<OmpAtomicWrite>(Parser<OmpAtomicClauseList>{} / maybe(","_tok),
+        verbatim("WRITE"_tok), Parser<OmpAtomicClauseList>{} / endOmpLine,
         statement(assignmentStmt), maybe(Parser<OmpEndAtomic>{} / endOmpLine)))
 
 // Atomic Construct

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index cf843ffb3c9d..c5df6990d102 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2222,10 +2222,12 @@ class UnparseVisitor {
       break;
     }
   }
+  void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }
+
   void Unparse(const OmpAtomic &x) {
     BeginOpenMP();
     Word("!$OMP ATOMIC");
-    Walk(std::get<OmpClauseList>(x.t));
+    Walk(std::get<OmpAtomicClauseList>(x.t));
     Put("\n");
     EndOpenMP();
     Walk(std::get<Statement<AssignmentStmt>>(x.t));
@@ -2448,6 +2450,13 @@ class UnparseVisitor {
     EndOpenMP();
   }
   void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
+  void Unparse(const OmpAtomicClause &x) {
+    std::visit(common::visitors{
+                   [&](const OmpMemoryOrderClause &y) { Walk(y); },
+                   [&](const OmpClause &z) { Walk(z); },
+               },
+        x.u);
+  }
   void Unparse(const OpenMPFlushConstruct &x) {
     BeginOpenMP();
     Word("!$OMP FLUSH ");

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index af76ca5a0a5a..e58e2e509fb8 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -280,6 +280,22 @@ void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) {
   }
 }
 
+void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
+  std::visit(
+      common::visitors{
+          [&](const auto &someAtomicConstruct) {
+            const auto &dir{std::get<parser::Verbatim>(someAtomicConstruct.t)};
+            PushContextAndClauseSets(
+                dir.source, llvm::omp::Directive::OMPD_atomic);
+          },
+      },
+      x.u);
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPAtomicConstruct &) {
+  dirContext_.pop_back();
+}
+
 // Clauses
 // Mainly categorized as
 // 1. Checks on 'OmpClauseList' from 'parse-tree.h'.
@@ -399,6 +415,7 @@ CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
 CHECK_SIMPLE_CLAUSE(SeqCst, OMPC_seq_cst)
 CHECK_SIMPLE_CLAUSE(Release, OMPC_release)
 CHECK_SIMPLE_CLAUSE(Relaxed, OMPC_relaxed)
+CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
 
 CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator)
 CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
@@ -468,7 +485,36 @@ CHECK_SIMPLE_PARSER_CLAUSE(OmpDistScheduleClause, OMPC_dist_schedule)
 CHECK_SIMPLE_PARSER_CLAUSE(OmpNowait, OMPC_nowait)
 CHECK_SIMPLE_PARSER_CLAUSE(OmpProcBindClause, OMPC_proc_bind)
 CHECK_SIMPLE_PARSER_CLAUSE(OmpReductionClause, OMPC_reduction)
-
+// Atomic-clause
+CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read)
+CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write)
+CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicUpdate, OMPC_update)
+CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicCapture, OMPC_capture)
+
+void OmpStructureChecker::Leave(const parser::OmpAtomicRead &) {
+  CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_read,
+      {llvm::omp::Clause::OMPC_release, llvm::omp::Clause::OMPC_acq_rel});
+}
+void OmpStructureChecker::Leave(const parser::OmpAtomicWrite &) {
+  CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_write,
+      {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel});
+}
+void OmpStructureChecker::Leave(const parser::OmpAtomicUpdate &) {
+  CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_update,
+      {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel});
+}
+// OmpAtomic node represents atomic directive without atomic-clause.
+// atomic-clause - READ,WRITE,UPDATE,CAPTURE.
+void OmpStructureChecker::Leave(const parser::OmpAtomic &) {
+  if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acquire)}) {
+    context_.Say(clause->source,
+        "Clause ACQUIRE is not allowed on the ATOMIC directive"_err_en_US);
+  }
+  if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acq_rel)}) {
+    context_.Say(clause->source,
+        "Clause ACQ_REL is not allowed on the ATOMIC directive"_err_en_US);
+  }
+}
 // Restrictions specific to each clause are implemented apart from the
 // generalized restrictions.
 void OmpStructureChecker::Enter(const parser::OmpAlignedClause &x) {

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index e2233a1094c9..a5dd9348ce75 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -121,6 +121,8 @@ class OmpStructureChecker
   void Leave(const parser::OpenMPCancellationPointConstruct &);
   void Enter(const parser::OpenMPCriticalConstruct &);
   void Leave(const parser::OpenMPCriticalConstruct &);
+  void Enter(const parser::OpenMPAtomicConstruct &);
+  void Leave(const parser::OpenMPAtomicConstruct &);
 
   void Leave(const parser::OmpClauseList &);
   void Enter(const parser::OmpClause &);
@@ -161,7 +163,16 @@ class OmpStructureChecker
   void Enter(const parser::OmpClause::Release &);
   void Enter(const parser::OmpClause::Acquire &);
   void Enter(const parser::OmpClause::Relaxed &);
-
+  void Enter(const parser::OmpClause::Hint &);
+
+  void Enter(const parser::OmpAtomicRead &);
+  void Leave(const parser::OmpAtomicRead &);
+  void Enter(const parser::OmpAtomicWrite &);
+  void Leave(const parser::OmpAtomicWrite &);
+  void Enter(const parser::OmpAtomicUpdate &);
+  void Leave(const parser::OmpAtomicUpdate &);
+  void Enter(const parser::OmpAtomicCapture &);
+  void Leave(const parser::OmpAtomic &);
   void Enter(const parser::OmpAlignedClause &);
   void Enter(const parser::OmpAllocateClause &);
   void Enter(const parser::OmpDefaultClause &);

diff  --git a/flang/test/Semantics/omp-atomic.f90 b/flang/test/Semantics/omp-atomic.f90
index 6f48f94331d6..dae0164e3bfa 100644
--- a/flang/test/Semantics/omp-atomic.f90
+++ b/flang/test/Semantics/omp-atomic.f90
@@ -34,6 +34,17 @@
 
   !$omp atomic
   a = a + 1
+  !ERROR: expected 'UPDATE'
+  !ERROR: expected 'WRITE'
+  !ERROR: expected 'CAPTURE'
+  !ERROR: expected 'READ'
+  !$omp atomic num_threads(4)
+  a = a + 1
+
+  !ERROR: expected end of line
+  !ERROR: expected end of line
+  !$omp atomic capture num_threads(4)
+  a = a + 1
 
   !$omp atomic relaxed
   a = a + 1

diff  --git a/flang/test/Semantics/omp-atomic01.f90 b/flang/test/Semantics/omp-atomic01.f90
new file mode 100644
index 000000000000..298f9aec53c2
--- /dev/null
+++ b/flang/test/Semantics/omp-atomic01.f90
@@ -0,0 +1,334 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
+! Semantic checks for OpenMP 5.0 standard 2.17.7 atomic Construct.
+
+use omp_lib
+  implicit none
+  integer :: i, j = 10, k=-100, a
+! 2.17.7.1
+! Handled inside parser.
+! OpenMP constructs may not be encountered during execution of an atomic region
+
+! 2.17.7.2
+! At most one memory-order-clause may appear on the construct.
+
+!READ
+  !ERROR: At most one SEQ_CST clause can appear on the READ directive
+  !$omp atomic seq_cst seq_cst read
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the READ directive
+  !$omp atomic read seq_cst seq_cst
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the READ directive
+  !$omp atomic seq_cst read seq_cst
+    i = j
+
+  !ERROR: At most one ACQUIRE clause can appear on the READ directive
+  !$omp atomic acquire acquire read
+    i = j
+  !ERROR: At most one ACQUIRE clause can appear on the READ directive
+  !$omp atomic read acquire acquire
+    i = j
+  !ERROR: At most one ACQUIRE clause can appear on the READ directive
+  !$omp atomic acquire read acquire
+    i = j
+
+  !ERROR: At most one RELAXED clause can appear on the READ directive
+  !$omp atomic relaxed relaxed read
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the READ directive
+  !$omp atomic read relaxed relaxed
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the READ directive
+  !$omp atomic relaxed read relaxed
+    i = j
+
+!UPDATE
+  !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
+  !$omp atomic seq_cst seq_cst update
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
+  !$omp atomic update seq_cst seq_cst
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive
+  !$omp atomic seq_cst update seq_cst
+    i = j
+
+  !ERROR: At most one RELEASE clause can appear on the UPDATE directive
+  !$omp atomic release release update
+    i = j
+  !ERROR: At most one RELEASE clause can appear on the UPDATE directive
+  !$omp atomic update release release
+    i = j
+  !ERROR: At most one RELEASE clause can appear on the UPDATE directive
+  !$omp atomic release update release
+    i = j
+
+  !ERROR: At most one RELAXED clause can appear on the UPDATE directive
+  !$omp atomic relaxed relaxed update
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the UPDATE directive
+  !$omp atomic update relaxed relaxed
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the UPDATE directive
+  !$omp atomic relaxed update relaxed
+    i = j
+
+!CAPTURE
+  !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: 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: 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: At most one RELEASE clause can appear on the CAPTURE directive
+  !$omp atomic release release capture
+    i = j
+    j = k
+  !$omp end atomic
+
+  !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: At most one RELEASE clause can appear on the CAPTURE directive
+  !$omp atomic release capture release
+    i = j
+    j = k
+  !$omp end atomic
+
+  !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: At most one RELAXED clause can appear on the CAPTURE directive
+  !$omp atomic capture relaxed relaxed
+    i = j
+    j = k
+  !$omp end atomic
+
+  !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: 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: 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: 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: At most one ACQUIRE clause can appear on the CAPTURE directive
+  !$omp atomic acquire acquire capture
+    i = j
+    j = k
+  !$omp end atomic
+
+  !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: At most one ACQUIRE clause can appear on the CAPTURE directive
+  !$omp atomic acquire capture acquire
+    i = j
+    j = k
+  !$omp end atomic
+
+!WRITE
+  !ERROR: At most one SEQ_CST clause can appear on the WRITE directive
+  !$omp atomic seq_cst seq_cst write
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the WRITE directive
+  !$omp atomic write seq_cst seq_cst
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the WRITE directive
+  !$omp atomic seq_cst write seq_cst
+    i = j
+
+  !ERROR: At most one RELEASE clause can appear on the WRITE directive
+  !$omp atomic release release write
+    i = j
+  !ERROR: At most one RELEASE clause can appear on the WRITE directive
+  !$omp atomic write release release
+    i = j
+  !ERROR: At most one RELEASE clause can appear on the WRITE directive
+  !$omp atomic release write release
+    i = j
+
+  !ERROR: At most one RELAXED clause can appear on the WRITE directive
+  !$omp atomic relaxed relaxed write
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the WRITE directive
+  !$omp atomic write relaxed relaxed
+    i = j
+  !ERROR: At most one RELAXED clause can appear on the WRITE directive
+  !$omp atomic relaxed write relaxed
+    i = j
+
+!No atomic-clause
+  !ERROR: At most one RELAXED clause can appear on the ATOMIC directive
+  !$omp atomic relaxed relaxed
+    i = j
+  !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive
+  !$omp atomic seq_cst seq_cst
+    i = j
+  !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
+  !$omp atomic release release
+    i = j
+
+! 2.17.7.3
+! At most one hint clause may appear on the construct.
+
+  !ERROR: At most one HINT clause can appear on the READ directive
+  !$omp atomic hint(omp_sync_hint_speculative) hint(omp_sync_hint_speculative) read
+    i = j
+  !ERROR: At most one HINT clause can appear on the READ directive
+  !$omp atomic hint(omp_sync_hint_nonspeculative) read hint(omp_sync_hint_nonspeculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the READ directive
+  !$omp atomic read hint(omp_sync_hint_uncontended) hint (omp_sync_hint_uncontended)
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended)
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the WRITE directive
+  !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended)
+    i = j
+  !ERROR: At most one HINT clause can appear on the UPDATE directive
+  !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) update
+    i = j
+  !ERROR: At most one HINT clause can appear on the UPDATE directive
+  !$omp atomic hint(omp_sync_hint_nonspeculative) update hint(omp_sync_hint_nonspeculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the UPDATE directive
+  !$omp atomic update hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended)
+    i = j
+  !ERROR: At most one HINT clause can appear on the ATOMIC directive
+  !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the ATOMIC directive
+  !$omp atomic hint(omp_sync_hint_none) hint(omp_sync_hint_nonspeculative)
+    i = j
+  !ERROR: At most one HINT clause can appear on the ATOMIC directive
+  !$omp atomic hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended)
+    i = j
+
+  !ERROR: At most one HINT clause can appear on the CAPTURE directive
+  !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) capture
+    i = j
+    j = k
+  !$omp end atomic
+  !ERROR: At most one HINT clause can appear on the CAPTURE directive
+  !$omp atomic hint(omp_sync_hint_nonspeculative) capture hint(omp_sync_hint_nonspeculative)
+    i = j
+    j = k
+  !$omp end atomic
+  !ERROR: At most one HINT clause can appear on the CAPTURE directive
+  !$omp atomic capture hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended)
+    i = j
+    j = k
+  !$omp end atomic
+! 2.17.7.4
+! If atomic-clause is read then memory-order-clause must not be acq_rel or release.
+
+  !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive
+  !$omp atomic acq_rel read
+    i = j
+  !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive
+  !$omp atomic read acq_rel
+    i = j
+
+  !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive
+  !$omp atomic release read
+    i = j
+  !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive
+  !$omp atomic read release
+    i = j
+
+! 2.17.7.5
+! If atomic-clause is write then memory-order-clause must not be acq_rel or acquire.
+
+  !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive
+  !$omp atomic acq_rel write
+    i = j
+  !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive
+  !$omp atomic write acq_rel
+    i = j
+
+  !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive
+  !$omp atomic acquire write
+    i = j
+  !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive
+  !$omp atomic write acquire
+    i = j
+
+
+! 2.17.7.6
+! If atomic-clause is update or not present then memory-order-clause must not be acq_rel or acquire.
+
+  !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive
+  !$omp atomic acq_rel update
+    i = j
+  !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive
+  !$omp atomic update acq_rel
+    i = j
+
+  !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive
+  !$omp atomic acquire update
+    i = j
+
+  !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive
+  !$omp atomic update acquire
+    i = j
+
+  !ERROR: Clause ACQ_REL is not allowed on the ATOMIC directive
+  !$omp atomic acq_rel
+    i = j
+
+  !ERROR: Clause ACQUIRE is not allowed on the ATOMIC directive
+  !$omp atomic acquire
+    i = j
+end program
+

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 6f16cfe730b7..13aa1381d679 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -468,6 +468,8 @@ def OMP_Atomic : Directive<"atomic"> {
     VersionedClause<OMPC_Write>,
     VersionedClause<OMPC_Update>,
     VersionedClause<OMPC_Capture>,
+  ];
+  let allowedOnceClauses = [
     VersionedClause<OMPC_SeqCst>,
     VersionedClause<OMPC_AcqRel, 50>,
     VersionedClause<OMPC_Acquire, 50>,


        


More information about the llvm-commits mailing list