[flang-commits] [flang] [llvm] [mlir] [Flang][OpenMP]Handling restrictions of using Memory-Order-Clause with Atomic-Clause (PR #199636)

via flang-commits flang-commits at lists.llvm.org
Fri May 29 03:04:42 PDT 2026


https://github.com/SunilKuravinakop updated https://github.com/llvm/llvm-project/pull/199636

>From 1b94c4eeef6d712dbc343c3c836f7dd4b5466c59 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe31.hpc.amslabs.hpecorp.net>
Date: Tue, 26 May 2026 03:49:24 -0500
Subject: [PATCH 1/2] Adhering to the restrictions of using Memory-Order-Clause
 with Atomic-Clause. Added warnings to indicate the transformations that will
 done internally in flang.

---
 flang/lib/Lower/OpenMP/Atomic.cpp             |  21 +++-
 flang/lib/Semantics/check-omp-atomic.cpp      |  53 +++++++++
 .../OpenMP/atomic-capture-release.f90         |  44 ++++++++
 .../Integration/OpenMP/atomic-compare.f90     |   8 +-
 .../OpenMP/atomic-mem-order-transform.f90     |  52 +++++++++
 .../OpenMP/atomic-requires-conflict-v50-3.f90 |   2 +-
 .../OpenMP/atomic-requires-conflict-v50-4.f90 |   2 +-
 .../test/Semantics/OpenMP/atomic-compare.f90  |   6 ++
 .../Semantics/OpenMP/atomic-mem-order.f90     | 101 ++++++++++++++++++
 flang/test/Semantics/OpenMP/atomic01.f90      |  20 ++++
 flang/test/Semantics/OpenMP/atomic05.f90      |   1 +
 .../OpenMP/omp-atomic-assignment-stmt.f90     |   1 +
 llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp     |  21 +++-
 13 files changed, 320 insertions(+), 12 deletions(-)
 create mode 100644 flang/test/Integration/OpenMP/atomic-capture-release.f90
 create mode 100644 flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
 create mode 100644 flang/test/Semantics/OpenMP/atomic-mem-order.f90

diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index cbca2fc52b93f..72c086b87511e 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -244,9 +244,16 @@ makeValidForAction(std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
   using Analysis = parser::OpenMPAtomicConstruct::Analysis;
   // Figure out the main action (i.e. disregard a potential capture operation)
   int action = action0;
-  if (action1 != Analysis::None)
+  bool isCapture = action1 != Analysis::None;
+  if (isCapture)
     action = action0 == Analysis::Read ? action1 : action0;
 
+  // All orderings are valid for capture operations per the OpenMP spec.
+  // The individual sub-operations (read/write/update) inside the capture
+  // will have their orderings handled separately.
+  if (isCapture)
+    return memOrder;
+
   // Avaliable orderings: acquire, acq_rel, relaxed, release, seq_cst
 
   if (action == Analysis::Read) {
@@ -259,7 +266,7 @@ makeValidForAction(std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
       return mlir::omp::ClauseMemoryOrderKind::Release;
   }
 
-  if (version > 50) {
+  if (version >= 50) {
     if (action == Analysis::Read) {
       // "release" prohibited
       if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release)
@@ -270,6 +277,13 @@ makeValidForAction(std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
       if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
         return mlir::omp::ClauseMemoryOrderKind::Relaxed;
     }
+    if (action == Analysis::Update) {
+      // "acquire" prohibited, "acq_rel" decays to "release"
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
+        return mlir::omp::ClauseMemoryOrderKind::Relaxed;
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
+        return mlir::omp::ClauseMemoryOrderKind::Release;
+    }
   } else {
     if (action == Analysis::Read) {
       // "release" prohibited
@@ -537,8 +551,7 @@ void Fortran::lower::omp::lowerAtomic(
   unsigned version = semaCtx.langOptions().OpenMPVersion;
   int action0 = analysis.op0.what & analysis.Action;
   int action1 = analysis.op1.what & analysis.Action;
-  if (canOverride)
-    memOrder = makeValidForAction(memOrder, action0, action1, version);
+  memOrder = makeValidForAction(memOrder, action0, action1, version);
 
   if (auto *cond = get(analysis.cond)) {
     // atomic compare: if (x == e) x = d
diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index f722de8d8dc46..ef6cb4ba360fa 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -1587,6 +1587,59 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
   checkExclusive(atomic, "atomic", dirSpec.Clauses());
   checkExclusive(memoryOrder, "memory-order", dirSpec.Clauses());
 
+  // Check for incompatible memory orderings on specific atomic operations.
+  // Per OpenMP 5.0+:
+  //   - atomic read: release and acq_rel are not allowed
+  //   - atomic write: acquire and acq_rel are not allowed
+  //   - atomic update (without capture): acquire and acq_rel are not allowed
+  unsigned version{context_.langOptions().OpenMPVersion};
+  if (version >= 50) {
+    const parser::OmpClause *memOrderClause{nullptr};
+    for (const parser::OmpClause &clause : dirSpec.Clauses().v) {
+      if (llvm::is_contained(memoryOrder, clause.Id())) {
+        memOrderClause = &clause;
+        break;
+      }
+    }
+    if (memOrderClause) {
+      llvm::omp::Clause memOrd{memOrderClause->Id()};
+      bool isCapture{x.IsCapture()};
+      if (kind == llvm::omp::Clause::OMPC_read) {
+        if (memOrd == llvm::omp::Clause::OMPC_release) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED"_warn_en_US);
+        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE"_warn_en_US);
+        }
+      } else if (kind == llvm::omp::Clause::OMPC_write && !isCapture) {
+        if (memOrd == llvm::omp::Clause::OMPC_acquire) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED"_warn_en_US);
+        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE"_warn_en_US);
+        }
+      } else if (kind == llvm::omp::Clause::OMPC_update && !isCapture) {
+        if (memOrd == llvm::omp::Clause::OMPC_acquire) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED"_warn_en_US);
+        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE"_warn_en_US);
+        }
+      } else if (isCapture) {
+        if (memOrd == llvm::omp::Clause::OMPC_release) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation"_warn_en_US);
+        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+          context_.Say(memOrderClause->source,
+              "An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation"_warn_en_US);
+        }
+      }
+    }
+  }
+
   switch (kind) {
   case llvm::omp::Clause::OMPC_read:
     CheckAtomicRead(x);
diff --git a/flang/test/Integration/OpenMP/atomic-capture-release.f90 b/flang/test/Integration/OpenMP/atomic-capture-release.f90
new file mode 100644
index 0000000000000..872d7b1394e36
--- /dev/null
+++ b/flang/test/Integration/OpenMP/atomic-capture-release.f90
@@ -0,0 +1,44 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+!RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s
+
+! Real(4) capture with release ordering: the initial load in the cmpxchg loop
+! must use monotonic (not release, which is invalid for loads in LLVM IR).
+!CHECK: define void {{.*}}test_capture_release_(
+!CHECK-SAME: ptr noalias %[[A:.*]], ptr noalias %[[B:.*]], ptr noalias %[[C:.*]])
+!CHECK: [[ENTRY:.*]]:
+!CHECK: [[ATOMIC_LOAD:.*]] = load atomic i32, ptr %[[A]] monotonic, align 4
+!CHECK: [[CONT:.*]]:
+!CHECK: cmpxchg ptr %[[A]], i32 %{{.*}}, i32 %{{.*}} release monotonic
+!CHECK: [[EXIT:.*]]:
+!CHECK: call void {{.*}}__kmpc_flush{{.*}}
+!CHECK: ret
+subroutine test_capture_release(a,b,c)
+  real(4) :: a, b, c
+  !$omp atomic capture release
+  c = a
+  a = a + b
+  !$omp end atomic
+end subroutine
+
+! Integer(4) capture with acq_rel ordering: uses atomicrmw (valid with acq_rel).
+!CHECK: define void {{.*}}test_capture_acq_rel_(
+!CHECK-SAME: ptr noalias %[[A:.*]], ptr noalias %[[B:.*]], ptr noalias %[[C:.*]])
+!CHECK: %[[TMP1:.*]] = load {{.*}}, ptr %[[B]]
+!CHECK: [[ENTRY:.*]]:
+!CHECK: %[[TMP2:.*]] = atomicrmw add ptr %[[A]], i32 %[[TMP1]] acq_rel
+!CHECK: call void {{.*}}__kmpc_flush{{.*}}
+!CHECK: ret
+subroutine test_capture_acq_rel(a,b,c)
+  integer(4) :: a, b, c
+  !$omp atomic capture acq_rel
+  c = a
+  a = a + b
+  !$omp end atomic
+end subroutine
diff --git a/flang/test/Integration/OpenMP/atomic-compare.f90 b/flang/test/Integration/OpenMP/atomic-compare.f90
index 7a30223ad1e73..ed06f36807bd0 100644
--- a/flang/test/Integration/OpenMP/atomic-compare.f90
+++ b/flang/test/Integration/OpenMP/atomic-compare.f90
@@ -34,12 +34,12 @@ subroutine atomic_compare_seq_cst(x, e, d)
   if (x == e) x = d
 end
 
-! acquire ordering → cmpxchg acquire
+! acquire ordering on non-capture compare (update) → demoted to monotonic
 !CHECK-LABEL: define void @atomic_compare_acquire_(
 !CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]], ptr noalias %[[D:.*]])
 !CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
 !CHECK: %[[DVAL:.*]] = load i32, ptr %[[D]], align 4
-!CHECK: cmpxchg ptr %[[X]], i32 %[[EVAL]], i32 %[[DVAL]] acquire acquire
+!CHECK: cmpxchg ptr %[[X]], i32 %[[EVAL]], i32 %[[DVAL]] monotonic monotonic
 subroutine atomic_compare_acquire(x, e, d)
   integer :: x, e, d
   !$omp atomic compare acquire
@@ -94,11 +94,11 @@ subroutine atomic_compare_lt_seq_cst(x, e)
   if (x < e) x = e
 end
 
-! Less-than with acquire → atomicrmw max acquire (signed)
+! Less-than with acquire on non-capture compare (update) → demoted to monotonic
 !CHECK-LABEL: define void @atomic_compare_lt_acquire_(
 !CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]])
 !CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
-!CHECK: atomicrmw max ptr %[[X]], i32 %[[EVAL]] acquire
+!CHECK: atomicrmw max ptr %[[X]], i32 %[[EVAL]] monotonic
 subroutine atomic_compare_lt_acquire(x, e)
   integer :: x, e
   !$omp atomic compare acquire
diff --git a/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90 b/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
new file mode 100644
index 0000000000000..461bc3f87cfe5
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
@@ -0,0 +1,52 @@
+!RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=50 %s -o - 2>&1 | FileCheck %s
+
+! Test that incompatible memory orderings on atomic operations are
+! transformed to valid orderings during lowering.
+
+! read + release -> relaxed
+!CHECK: omp.atomic.read %{{.*}} = %{{.*}} memory_order(relaxed)
+subroutine test_read_release(x, v)
+  integer :: x, v
+  !$omp atomic read release
+  v = x
+end
+
+! read + acq_rel -> acquire
+!CHECK: omp.atomic.read %{{.*}} = %{{.*}} memory_order(acquire)
+subroutine test_read_acq_rel(x, v)
+  integer :: x, v
+  !$omp atomic read acq_rel
+  v = x
+end
+
+! write + acquire -> relaxed
+!CHECK: omp.atomic.write %{{.*}} = %{{.*}} memory_order(relaxed)
+subroutine test_write_acquire(x, v)
+  integer :: x, v
+  !$omp atomic write acquire
+  x = v
+end
+
+! write + acq_rel -> release
+!CHECK: omp.atomic.write %{{.*}} = %{{.*}} memory_order(release)
+subroutine test_write_acq_rel(x, v)
+  integer :: x, v
+  !$omp atomic write acq_rel
+  x = v
+end
+
+! update + acquire -> relaxed
+!CHECK: omp.atomic.update memory_order(relaxed)
+subroutine test_update_acquire(x)
+  integer :: x
+  !$omp atomic update acquire
+  x = x + 1
+end
+
+! update + acq_rel -> release
+!CHECK: omp.atomic.update memory_order(release)
+subroutine test_update_acq_rel(x)
+  integer :: x
+  !$omp atomic update acq_rel
+  x = x + 1
+end
diff --git a/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-3.f90 b/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-3.f90
index bc7529c69340a..4a265e851fce4 100644
--- a/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-3.f90
+++ b/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-3.f90
@@ -1,7 +1,7 @@
 !RUN: bbc %openmp_flags -fopenmp-version=50 -emit-hlfir %s -o - | FileCheck %s
 !RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=50 %s -o - | FileCheck %s
 
-!CHECK: omp.atomic.update memory_order(relaxed)
+!CHECK: omp.atomic.update memory_order(release)
 
 subroutine f05(x, v)
   integer :: x, v
diff --git a/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-4.f90 b/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-4.f90
index 5cffb1ac9d6c4..81678771a69cd 100644
--- a/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-4.f90
+++ b/flang/test/Lower/OpenMP/atomic-requires-conflict-v50-4.f90
@@ -1,7 +1,7 @@
 !RUN: bbc %openmp_flags -fopenmp-version=50 -emit-hlfir %s -o - | FileCheck %s
 !RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=50 %s -o - | FileCheck %s
 
-!CHECK: omp.atomic.capture memory_order(relaxed)
+!CHECK: omp.atomic.capture memory_order(acquire)
 
 subroutine f06(x, v)
   integer :: x, v
diff --git a/flang/test/Semantics/OpenMP/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90
index 0e53729c2f02a..56297cbb835a5 100644
--- a/flang/test/Semantics/OpenMP/atomic-compare.f90
+++ b/flang/test/Semantics/OpenMP/atomic-compare.f90
@@ -23,6 +23,7 @@
   if (a .eq. b) a = c
   !$omp end atomic
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic compare acquire hint(OMP_LOCK_HINT_CONTENDED)
   if (b .eq. a) b = c
 
@@ -32,10 +33,12 @@
   !$omp atomic compare seq_cst
   if (b .eq. c) b = a
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic hint(1) acq_rel compare
   if (b .eq. a) b = c
   !$omp end atomic
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic hint(1) acq_rel compare fail(release)
   if (c .eq. a) a = b
   !$omp end atomic
@@ -70,12 +73,15 @@
   if (b .eq. c) b = a
 
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire acquire compare
   if (b .eq. c) b = a
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic compare acquire acquire
   if (b .eq. c) b = a
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire compare acquire
   if (b .eq. c) b = a
 
diff --git a/flang/test/Semantics/OpenMP/atomic-mem-order.f90 b/flang/test/Semantics/OpenMP/atomic-mem-order.f90
new file mode 100644
index 0000000000000..cabe64574b635
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/atomic-mem-order.f90
@@ -0,0 +1,101 @@
+! REQUIRES: openmp_runtime
+
+! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
+! Semantic checks for incompatible memory orderings on atomic operations.
+
+subroutine test_atomic_read_mem_order()
+  integer :: x, v
+
+  ! Valid orderings for read
+  !$omp atomic read seq_cst
+  v = x
+  !$omp atomic read acquire
+  v = x
+  !$omp atomic read relaxed
+  v = x
+
+  ! Invalid orderings for read
+  !WARNING: An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED
+  !$omp atomic read release
+  v = x
+  !WARNING: An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE
+  !$omp atomic read acq_rel
+  v = x
+end subroutine
+
+subroutine test_atomic_write_mem_order()
+  integer :: x, v
+
+  ! Valid orderings for write
+  !$omp atomic write seq_cst
+  x = v
+  !$omp atomic write release
+  x = v
+  !$omp atomic write relaxed
+  x = v
+
+  ! Invalid orderings for write
+  !WARNING: An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED
+  !$omp atomic write acquire
+  x = v
+  !WARNING: An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE
+  !$omp atomic write acq_rel
+  x = v
+end subroutine
+
+subroutine test_atomic_update_mem_order()
+  integer :: x
+
+  ! Valid orderings for update
+  !$omp atomic update seq_cst
+  x = x + 1
+  !$omp atomic update release
+  x = x + 1
+  !$omp atomic update relaxed
+  x = x + 1
+
+  ! Invalid orderings for update
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
+  !$omp atomic update acquire
+  x = x + 1
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
+  !$omp atomic update acq_rel
+  x = x + 1
+end subroutine
+
+subroutine test_atomic_capture_mem_order()
+  integer :: x, v
+
+  ! Valid orderings for capture (all are allowed, but some produce warnings)
+  !$omp atomic capture seq_cst
+  v = x
+  x = x + 1
+  !$omp end atomic
+  !$omp atomic capture acquire
+  v = x
+  x = x + 1
+  !$omp end atomic
+  !$omp atomic capture relaxed
+  v = x
+  x = x + 1
+  !$omp end atomic
+
+  ! Capture with release/acq_rel: valid but read uses weaker ordering
+  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
+  !$omp atomic capture release
+  v = x
+  x = x + 1
+  !$omp end atomic
+  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
+  !$omp atomic capture acq_rel
+  v = x
+  x = x + 1
+  !$omp end atomic
+
+  ! Trigger an error so test_errors.py captures stderr
+  !ERROR: ATOMIC READ cannot have COMPARE or CAPTURE clauses
+  !$omp atomic read capture
+  v = x
+  x = x + 1
+  !$omp end atomic
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/atomic01.f90 b/flang/test/Semantics/OpenMP/atomic01.f90
index f700c381cadd0..13b77f07067ae 100644
--- a/flang/test/Semantics/OpenMP/atomic01.f90
+++ b/flang/test/Semantics/OpenMP/atomic01.f90
@@ -103,18 +103,21 @@
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic release release capture
     i = j
     j = k
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic capture release release
     i = j
     j = k
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic release capture release
     i = j
     j = k
@@ -139,18 +142,21 @@
   !$omp end atomic
 
   !ERROR: At most one ACQ_REL clause can appear on the ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$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 ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$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 ATOMIC directive
+  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$omp atomic acq_rel capture acq_rel
     i = j
     j = k
@@ -292,26 +298,34 @@
 ! 2.17.7.4
 ! If atomic-clause is read then memory-order-clause must not be acq_rel or release.
 
+  !WARNING: An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE
   !$omp atomic acq_rel read
     i = j
+  !WARNING: An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE
   !$omp atomic read acq_rel
     i = j
 
+  !WARNING: An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED
   !$omp atomic release read
     i = j
+  !WARNING: An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED
   !$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.
 
+  !WARNING: An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic acq_rel write
     i = j
+  !WARNING: An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic write acq_rel
     i = j
 
+  !WARNING: An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire write
     i = j
+  !WARNING: An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic write acquire
     i = j
 
@@ -319,25 +333,31 @@
 ! 2.17.7.6
 ! If atomic-clause is update or not present then memory-order-clause must not be acq_rel or acquire.
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic acq_rel update
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic update acq_rel
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire update
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic update acquire
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic acq_rel
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
 
+  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire
   !ERROR: The atomic variable i should appear as an argument in the update operation
     i = j
diff --git a/flang/test/Semantics/OpenMP/atomic05.f90 b/flang/test/Semantics/OpenMP/atomic05.f90
index e0103be4cae4a..5b6873b22280f 100644
--- a/flang/test/Semantics/OpenMP/atomic05.f90
+++ b/flang/test/Semantics/OpenMP/atomic05.f90
@@ -22,6 +22,7 @@ program OmpAtomic
     !ERROR: This is not a valid ATOMIC UPDATE operation
         x = 10
     !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct
+    !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
     !$omp atomic capture release, seq_cst
         x = g
         g = x * 10
diff --git a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
index 4843e44dd2535..1bdf5e09e941a 100644
--- a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
+++ b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
@@ -85,6 +85,7 @@ program sample
         x = x + 1
     !$omp end atomic
 
+    !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
     !$omp atomic release capture
         v = x
     ! This ends up being "x = b + x".
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index ecff0c9b0aac4..6fb25f898f393 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -10918,6 +10918,21 @@ Value *OpenMPIRBuilder::emitRMWOpAsInstruction(Value *Src1, Value *Src2,
   llvm_unreachable("Unsupported atomic update operation");
 }
 
+static AtomicOrdering TransformReleaseAcquireRelease(AtomicOrdering AO) {
+  // Loads cannot use Release or AcquireRelease ordering. This load is
+  // just the initial value for the cmpxchg loop; the cmpxchg itself
+  // retains the original ordering.
+  AtomicOrdering LoadAO = AO;
+
+  if (AO == AtomicOrdering::Release) {
+    LoadAO = AtomicOrdering::Monotonic;
+  } else if (AO == AtomicOrdering::AcquireRelease) {
+    LoadAO = AtomicOrdering::Acquire;
+  }
+
+  return LoadAO;
+}
+
 Expected<std::pair<Value *, Value *>> OpenMPIRBuilder::emitAtomicUpdate(
     InsertPointTy AllocaIP, Value *X, Type *XElemTy, Value *Expr,
     AtomicOrdering AO, AtomicRMWInst::BinOp RMWOp,
@@ -10968,7 +10983,8 @@ Expected<std::pair<Value *, Value *>> OpenMPIRBuilder::emitAtomicUpdate(
   } else if (XElemTy->isStructTy()) {
     LoadInst *OldVal =
         Builder.CreateLoad(XElemTy, X, X->getName() + ".atomic.load");
-    OldVal->setAtomic(AO);
+    AtomicOrdering LoadAO = TransformReleaseAcquireRelease(AO);
+    OldVal->setAtomic(LoadAO);
     const DataLayout &LoadDL = OldVal->getModule()->getDataLayout();
     unsigned LoadSize = LoadDL.getTypeStoreSize(XElemTy);
 
@@ -11019,7 +11035,8 @@ Expected<std::pair<Value *, Value *>> OpenMPIRBuilder::emitAtomicUpdate(
         IntegerType::get(M.getContext(), XElemTy->getScalarSizeInBits());
     LoadInst *OldVal =
         Builder.CreateLoad(IntCastTy, X, X->getName() + ".atomic.load");
-    OldVal->setAtomic(AO);
+    AtomicOrdering LoadAO = TransformReleaseAcquireRelease(AO);
+    OldVal->setAtomic(LoadAO);
     // CurBB
     // |     /---\
     // ContBB    |

>From 1423a831c771e742ca04e00937f8fa0615c4841d Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe31.hpc.amslabs.hpecorp.net>
Date: Fri, 29 May 2026 04:53:37 -0500
Subject: [PATCH 2/2] Handling memory-order-clause differences between OpenMP
 5.0 and OpenMP 5.1, for read, write and update. Limitations of Capture are
 not being handled in this commit, in    
 flang/lib/Semantics/check-omp-atomic.cpp    
 flang/lib/Lower/OpenMP/Atomic.cpp.

---
 flang/lib/Lower/OpenMP/Atomic.cpp             | 45 ++++++++++---------
 flang/lib/Semantics/check-omp-atomic.cpp      | 21 ++++-----
 .../Integration/OpenMP/atomic-compare.f90     |  8 ++--
 .../OpenMP/atomic-mem-order-transform.f90     | 15 +++++--
 .../Lower/OpenMP/requires-admo-acqrel.f90     |  4 +-
 .../test/Semantics/OpenMP/atomic-compare.f90  |  6 ---
 .../Semantics/OpenMP/atomic-mem-order.f90     | 12 ++---
 flang/test/Semantics/OpenMP/atomic01.f90      |  6 ---
 flang/test/Semantics/OpenMP/atomic05.f90      |  1 -
 .../OpenMP/omp-atomic-assignment-stmt.f90     |  1 -
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  | 43 +++++++++++++-----
 mlir/test/Dialect/OpenMP/invalid.mlir         |  8 ++--
 12 files changed, 91 insertions(+), 79 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index 72c086b87511e..5aa073fbbed3e 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -252,18 +252,26 @@ makeValidForAction(std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
   // The individual sub-operations (read/write/update) inside the capture
   // will have their orderings handled separately.
   if (isCapture)
-    return memOrder;
+     return memOrder;
 
   // Avaliable orderings: acquire, acq_rel, relaxed, release, seq_cst
 
-  if (action == Analysis::Read) {
-    // "acq_rel" decays to "acquire"
-    if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
-      return mlir::omp::ClauseMemoryOrderKind::Acquire;
-  } else if (action == Analysis::Write) {
-    // "acq_rel" decays to "release"
-    if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
-      return mlir::omp::ClauseMemoryOrderKind::Release;
+  if (version == 50) {
+    if (action == Analysis::Read) {
+      // "acq_rel" decays to "acquire" for read
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
+        return mlir::omp::ClauseMemoryOrderKind::Acquire;
+    } else if (action == Analysis::Write) {
+      // "acq_rel" decays to "release" for write
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
+        return mlir::omp::ClauseMemoryOrderKind::Release;
+    } else if (action == Analysis::Update) {
+      // "acquire" decays to "relaxed", "acq_rel" decays to "release"
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
+        return mlir::omp::ClauseMemoryOrderKind::Relaxed;
+      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
+        return mlir::omp::ClauseMemoryOrderKind::Release;
+    }
   }
 
   if (version >= 50) {
@@ -277,13 +285,6 @@ makeValidForAction(std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
       if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
         return mlir::omp::ClauseMemoryOrderKind::Relaxed;
     }
-    if (action == Analysis::Update) {
-      // "acquire" prohibited, "acq_rel" decays to "release"
-      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
-        return mlir::omp::ClauseMemoryOrderKind::Relaxed;
-      if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
-        return mlir::omp::ClauseMemoryOrderKind::Release;
-    }
   } else {
     if (action == Analysis::Read) {
       // "release" prohibited
@@ -335,8 +336,10 @@ genAtomicRead(lower::AbstractConverter &converter,
     if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release) {
       // Reset it back to the default.
       memOrder = getDefaultAtomicMemOrder(semaCtx);
-    } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
-      // The MLIR verifier doesn't like acq_rel either.
+    } else if (semaCtx.langOptions().OpenMPVersion <= 50 &&
+               *memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
+      // In OpenMP 5.0, acq_rel is not allowed on read; decay to acquire.
+      // In OpenMP 5.1+, acq_rel is permitted on read.
       memOrder = mlir::omp::ClauseMemoryOrderKind::Acquire;
     }
   }
@@ -394,8 +397,10 @@ genAtomicWrite(lower::AbstractConverter &converter,
     if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire) {
       // Reset it back to the default.
       memOrder = getDefaultAtomicMemOrder(semaCtx);
-    } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
-      // The MLIR verifier doesn't like acq_rel either.
+    } else if (semaCtx.langOptions().OpenMPVersion <= 50 &&
+               *memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
+      // In OpenMP 5.0, acq_rel is not allowed on write; decay to release.
+      // In OpenMP 5.1+, acq_rel is permitted on write.
       memOrder = mlir::omp::ClauseMemoryOrderKind::Release;
     }
   }
diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index ef6cb4ba360fa..a1a8a007f6ead 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -1588,10 +1588,14 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
   checkExclusive(memoryOrder, "memory-order", dirSpec.Clauses());
 
   // Check for incompatible memory orderings on specific atomic operations.
-  // Per OpenMP 5.0+:
+  // Per OpenMP 5.0:
   //   - atomic read: release and acq_rel are not allowed
   //   - atomic write: acquire and acq_rel are not allowed
   //   - atomic update (without capture): acquire and acq_rel are not allowed
+  // Per OpenMP 5.1+:
+  //   - atomic read: release is not allowed
+  //   - atomic write: acquire is not allowed
+  //   (no restrictions on update)
   unsigned version{context_.langOptions().OpenMPVersion};
   if (version >= 50) {
     const parser::OmpClause *memOrderClause{nullptr};
@@ -1608,7 +1612,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
         if (memOrd == llvm::omp::Clause::OMPC_release) {
           context_.Say(memOrderClause->source,
               "An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED"_warn_en_US);
-        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+        } else if (version < 51 && memOrd == llvm::omp::Clause::OMPC_acq_rel) {
           context_.Say(memOrderClause->source,
               "An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE"_warn_en_US);
         }
@@ -1616,11 +1620,12 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
         if (memOrd == llvm::omp::Clause::OMPC_acquire) {
           context_.Say(memOrderClause->source,
               "An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED"_warn_en_US);
-        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
+        } else if (version < 51 && memOrd == llvm::omp::Clause::OMPC_acq_rel) {
           context_.Say(memOrderClause->source,
               "An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE"_warn_en_US);
         }
-      } else if (kind == llvm::omp::Clause::OMPC_update && !isCapture) {
+      } else if (version == 50 && kind == llvm::omp::Clause::OMPC_update &&
+          !isCapture) {
         if (memOrd == llvm::omp::Clause::OMPC_acquire) {
           context_.Say(memOrderClause->source,
               "An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED"_warn_en_US);
@@ -1628,14 +1633,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
           context_.Say(memOrderClause->source,
               "An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE"_warn_en_US);
         }
-      } else if (isCapture) {
-        if (memOrd == llvm::omp::Clause::OMPC_release) {
-          context_.Say(memOrderClause->source,
-              "An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation"_warn_en_US);
-        } else if (memOrd == llvm::omp::Clause::OMPC_acq_rel) {
-          context_.Say(memOrderClause->source,
-              "An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation"_warn_en_US);
-        }
       }
     }
   }
diff --git a/flang/test/Integration/OpenMP/atomic-compare.f90 b/flang/test/Integration/OpenMP/atomic-compare.f90
index ed06f36807bd0..92d6726996eab 100644
--- a/flang/test/Integration/OpenMP/atomic-compare.f90
+++ b/flang/test/Integration/OpenMP/atomic-compare.f90
@@ -34,12 +34,12 @@ subroutine atomic_compare_seq_cst(x, e, d)
   if (x == e) x = d
 end
 
-! acquire ordering on non-capture compare (update) → demoted to monotonic
+! acquire ordering on compare (update) is valid in OpenMP 5.1
 !CHECK-LABEL: define void @atomic_compare_acquire_(
 !CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]], ptr noalias %[[D:.*]])
 !CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
 !CHECK: %[[DVAL:.*]] = load i32, ptr %[[D]], align 4
-!CHECK: cmpxchg ptr %[[X]], i32 %[[EVAL]], i32 %[[DVAL]] monotonic monotonic
+!CHECK: cmpxchg ptr %[[X]], i32 %[[EVAL]], i32 %[[DVAL]] acquire acquire
 subroutine atomic_compare_acquire(x, e, d)
   integer :: x, e, d
   !$omp atomic compare acquire
@@ -94,11 +94,11 @@ subroutine atomic_compare_lt_seq_cst(x, e)
   if (x < e) x = e
 end
 
-! Less-than with acquire on non-capture compare (update) → demoted to monotonic
+! Less-than with acquire on compare (update) is valid in OpenMP 5.1
 !CHECK-LABEL: define void @atomic_compare_lt_acquire_(
 !CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]])
 !CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
-!CHECK: atomicrmw max ptr %[[X]], i32 %[[EVAL]] monotonic
+!CHECK: atomicrmw max ptr %[[X]], i32 %[[EVAL]] acquire
 subroutine atomic_compare_lt_acquire(x, e)
   integer :: x, e
   !$omp atomic compare acquire
diff --git a/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90 b/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
index 461bc3f87cfe5..d5139352d541d 100644
--- a/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
+++ b/flang/test/Lower/OpenMP/atomic-mem-order-transform.f90
@@ -1,18 +1,21 @@
 !RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=50 %s -o - 2>&1 | FileCheck %s
+!RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK51
 
 ! Test that incompatible memory orderings on atomic operations are
 ! transformed to valid orderings during lowering.
 
 ! read + release -> relaxed
 !CHECK: omp.atomic.read %{{.*}} = %{{.*}} memory_order(relaxed)
+!CHECK51: omp.atomic.read %{{.*}} = %{{.*}} memory_order(relaxed)
 subroutine test_read_release(x, v)
   integer :: x, v
   !$omp atomic read release
   v = x
 end
 
-! read + acq_rel -> acquire
+! read + acq_rel -> acquire (5.0 only; untouched in 5.1)
 !CHECK: omp.atomic.read %{{.*}} = %{{.*}} memory_order(acquire)
+!CHECK51: omp.atomic.read %{{.*}} = %{{.*}} memory_order(acq_rel)
 subroutine test_read_acq_rel(x, v)
   integer :: x, v
   !$omp atomic read acq_rel
@@ -21,30 +24,34 @@ subroutine test_read_acq_rel(x, v)
 
 ! write + acquire -> relaxed
 !CHECK: omp.atomic.write %{{.*}} = %{{.*}} memory_order(relaxed)
+!CHECK51: omp.atomic.write %{{.*}} = %{{.*}} memory_order(relaxed)
 subroutine test_write_acquire(x, v)
   integer :: x, v
   !$omp atomic write acquire
   x = v
 end
 
-! write + acq_rel -> release
+! write + acq_rel -> release (5.0 only; untouched in 5.1)
 !CHECK: omp.atomic.write %{{.*}} = %{{.*}} memory_order(release)
+!CHECK51: omp.atomic.write %{{.*}} = %{{.*}} memory_order(acq_rel)
 subroutine test_write_acq_rel(x, v)
   integer :: x, v
   !$omp atomic write acq_rel
   x = v
 end
 
-! update + acquire -> relaxed
+! update + acquire -> relaxed (5.0 only; untouched in 5.1)
 !CHECK: omp.atomic.update memory_order(relaxed)
+!CHECK51: omp.atomic.update memory_order(acquire)
 subroutine test_update_acquire(x)
   integer :: x
   !$omp atomic update acquire
   x = x + 1
 end
 
-! update + acq_rel -> release
+! update + acq_rel -> release (5.0 only; untouched in 5.1)
 !CHECK: omp.atomic.update memory_order(release)
+!CHECK51: omp.atomic.update memory_order(acq_rel)
 subroutine test_update_acq_rel(x)
   integer :: x
   !$omp atomic update acq_rel
diff --git a/flang/test/Lower/OpenMP/requires-admo-acqrel.f90 b/flang/test/Lower/OpenMP/requires-admo-acqrel.f90
index 525a846f410d8..7691e03362d31 100644
--- a/flang/test/Lower/OpenMP/requires-admo-acqrel.f90
+++ b/flang/test/Lower/OpenMP/requires-admo-acqrel.f90
@@ -7,11 +7,11 @@ module m
 
 subroutine f00(x, v)
   integer :: x, v
-!CHECK: omp.atomic.read %{{[ %#=0-9]+}} memory_order(acquire)
+!CHECK: omp.atomic.read %{{[ %#=0-9]+}} memory_order(acq_rel)
   !$omp atomic read
     v = x
 
-!CHECK: omp.atomic.write %{{[ %#=0-9]+}} memory_order(release)
+!CHECK: omp.atomic.write %{{[ %#=0-9]+}} memory_order(acq_rel)
   !$omp atomic write
     x = v
 end
diff --git a/flang/test/Semantics/OpenMP/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90
index 56297cbb835a5..0e53729c2f02a 100644
--- a/flang/test/Semantics/OpenMP/atomic-compare.f90
+++ b/flang/test/Semantics/OpenMP/atomic-compare.f90
@@ -23,7 +23,6 @@
   if (a .eq. b) a = c
   !$omp end atomic
 
-  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic compare acquire hint(OMP_LOCK_HINT_CONTENDED)
   if (b .eq. a) b = c
 
@@ -33,12 +32,10 @@
   !$omp atomic compare seq_cst
   if (b .eq. c) b = a
 
-  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic hint(1) acq_rel compare
   if (b .eq. a) b = c
   !$omp end atomic
 
-  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic hint(1) acq_rel compare fail(release)
   if (c .eq. a) a = b
   !$omp end atomic
@@ -73,15 +70,12 @@
   if (b .eq. c) b = a
 
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire acquire compare
   if (b .eq. c) b = a
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic compare acquire acquire
   if (b .eq. c) b = a
   !ERROR: At most one ACQUIRE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic acquire compare acquire
   if (b .eq. c) b = a
 
diff --git a/flang/test/Semantics/OpenMP/atomic-mem-order.f90 b/flang/test/Semantics/OpenMP/atomic-mem-order.f90
index cabe64574b635..cdf2242f88799 100644
--- a/flang/test/Semantics/OpenMP/atomic-mem-order.f90
+++ b/flang/test/Semantics/OpenMP/atomic-mem-order.f90
@@ -1,6 +1,6 @@
 ! REQUIRES: openmp_runtime
 
-! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
+! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=51
 ! Semantic checks for incompatible memory orderings on atomic operations.
 
 subroutine test_atomic_read_mem_order()
@@ -18,7 +18,6 @@ subroutine test_atomic_read_mem_order()
   !WARNING: An ATOMIC READ operation must not have RELEASE as the memory order, using RELAXED
   !$omp atomic read release
   v = x
-  !WARNING: An ATOMIC READ operation must not have ACQ_REL as the memory order, using ACQUIRE
   !$omp atomic read acq_rel
   v = x
 end subroutine
@@ -38,7 +37,6 @@ subroutine test_atomic_write_mem_order()
   !WARNING: An ATOMIC WRITE operation must not have ACQUIRE as the memory order, using RELAXED
   !$omp atomic write acquire
   x = v
-  !WARNING: An ATOMIC WRITE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic write acq_rel
   x = v
 end subroutine
@@ -54,11 +52,9 @@ subroutine test_atomic_update_mem_order()
   !$omp atomic update relaxed
   x = x + 1
 
-  ! Invalid orderings for update
-  !WARNING: An ATOMIC UPDATE operation must not have ACQUIRE as the memory order, using RELAXED
+  ! No restrictions on update in OpenMP 5.1
   !$omp atomic update acquire
   x = x + 1
-  !WARNING: An ATOMIC UPDATE operation must not have ACQ_REL as the memory order, using RELEASE
   !$omp atomic update acq_rel
   x = x + 1
 end subroutine
@@ -80,13 +76,11 @@ subroutine test_atomic_capture_mem_order()
   x = x + 1
   !$omp end atomic
 
-  ! Capture with release/acq_rel: valid but read uses weaker ordering
-  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
+  ! Capture with release/acq_rel: valid, no restrictions
   !$omp atomic capture release
   v = x
   x = x + 1
   !$omp end atomic
-  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$omp atomic capture acq_rel
   v = x
   x = x + 1
diff --git a/flang/test/Semantics/OpenMP/atomic01.f90 b/flang/test/Semantics/OpenMP/atomic01.f90
index 13b77f07067ae..1ef985de67aeb 100644
--- a/flang/test/Semantics/OpenMP/atomic01.f90
+++ b/flang/test/Semantics/OpenMP/atomic01.f90
@@ -103,21 +103,18 @@
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic release release capture
     i = j
     j = k
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic capture release release
     i = j
     j = k
   !$omp end atomic
 
   !ERROR: At most one RELEASE clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
   !$omp atomic release capture release
     i = j
     j = k
@@ -142,21 +139,18 @@
   !$omp end atomic
 
   !ERROR: At most one ACQ_REL clause can appear on the ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$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 ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$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 ATOMIC directive
-  !WARNING: An ATOMIC CAPTURE with ACQ_REL ordering will use ACQUIRE ordering for the read operation
   !$omp atomic acq_rel capture acq_rel
     i = j
     j = k
diff --git a/flang/test/Semantics/OpenMP/atomic05.f90 b/flang/test/Semantics/OpenMP/atomic05.f90
index 5b6873b22280f..e0103be4cae4a 100644
--- a/flang/test/Semantics/OpenMP/atomic05.f90
+++ b/flang/test/Semantics/OpenMP/atomic05.f90
@@ -22,7 +22,6 @@ program OmpAtomic
     !ERROR: This is not a valid ATOMIC UPDATE operation
         x = 10
     !ERROR: At most one clause from the 'memory-order' group is allowed on ATOMIC construct
-    !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
     !$omp atomic capture release, seq_cst
         x = g
         g = x * 10
diff --git a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
index 1bdf5e09e941a..4843e44dd2535 100644
--- a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
+++ b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
@@ -85,7 +85,6 @@ program sample
         x = x + 1
     !$omp end atomic
 
-    !WARNING: An ATOMIC CAPTURE with RELEASE ordering will use MONOTONIC ordering for the read operation
     !$omp atomic release capture
         v = x
     ! This ends up being "x = b + x".
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 7cef23bdfef18..db5fd8f2e3230 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -4507,11 +4507,19 @@ LogicalResult AtomicReadOp::verify() {
   if (verifyCommon().failed())
     return mlir::failure();
 
+  int64_t version = 50;
+  if (auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
+    if (Attribute verAttr = moduleOp->getAttr("omp.version"))
+      version = llvm::cast<VersionAttr>(verAttr).getVersion();
+
   if (auto mo = getMemoryOrder()) {
-    if (*mo == ClauseMemoryOrderKind::Acq_rel ||
-        *mo == ClauseMemoryOrderKind::Release) {
-      return emitError(
-          "memory-order must not be acq_rel or release for atomic reads");
+    if (*mo == ClauseMemoryOrderKind::Release) {
+      return emitError("memory-order must not be release for atomic reads");
+    }
+    if (*mo == ClauseMemoryOrderKind::Acq_rel) {
+      // acq_rel is prohibited on read only in OpenMP 5.0; allowed in 5.1+.
+      if (version < 51)
+        return emitError("memory-order must not be acq_rel for atomic reads");
     }
   }
   return verifySynchronizationHint(*this, getHint());
@@ -4525,11 +4533,19 @@ LogicalResult AtomicWriteOp::verify() {
   if (verifyCommon().failed())
     return mlir::failure();
 
+  int64_t version = 50;
+  if (auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
+    if (Attribute verAttr = moduleOp->getAttr("omp.version"))
+      version = llvm::cast<VersionAttr>(verAttr).getVersion();
+
   if (auto mo = getMemoryOrder()) {
-    if (*mo == ClauseMemoryOrderKind::Acq_rel ||
-        *mo == ClauseMemoryOrderKind::Acquire) {
-      return emitError(
-          "memory-order must not be acq_rel or acquire for atomic writes");
+    if (*mo == ClauseMemoryOrderKind::Acquire) {
+      return emitError("memory-order must not be acquire for atomic writes");
+    }
+    if (*mo == ClauseMemoryOrderKind::Acq_rel) {
+      // acq_rel is prohibited on write only in OpenMP 5.0; allowed in 5.1+.
+      if (version < 51)
+        return emitError("memory-order must not be acq_rel for atomic writes");
     }
   }
   return verifySynchronizationHint(*this, getHint());
@@ -4557,11 +4573,18 @@ LogicalResult AtomicUpdateOp::verify() {
   if (verifyCommon().failed())
     return mlir::failure();
 
+  int64_t version = 50;
+  if (auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
+    if (Attribute verAttr = moduleOp->getAttr("omp.version"))
+      version = llvm::cast<VersionAttr>(verAttr).getVersion();
+
   if (auto mo = getMemoryOrder()) {
     if (*mo == ClauseMemoryOrderKind::Acq_rel ||
         *mo == ClauseMemoryOrderKind::Acquire) {
-      return emitError(
-          "memory-order must not be acq_rel or acquire for atomic updates");
+      // This restriction applies only to OpenMP 5.0; removed in 5.1.
+      if (version < 51)
+        return emitError(
+            "memory-order must not be acq_rel or acquire for atomic updates");
     }
   }
 
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 06ad3d60ea635..7ff4755174053 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -962,7 +962,7 @@ func.func @omp_atomic_read2(%x: memref<i32>, %v: memref<i32>) {
 // -----
 
 func.func @omp_atomic_read3(%x: memref<i32>, %v: memref<i32>) {
-  // expected-error @below {{memory-order must not be acq_rel or release for atomic reads}}
+  // expected-error @below {{memory-order must not be acq_rel for atomic reads}}
   omp.atomic.read %v = %x memory_order(acq_rel) : memref<i32>, memref<i32>, i32
   return
 }
@@ -970,7 +970,7 @@ func.func @omp_atomic_read3(%x: memref<i32>, %v: memref<i32>) {
 // -----
 
 func.func @omp_atomic_read4(%x: memref<i32>, %v: memref<i32>) {
-  // expected-error @below {{memory-order must not be acq_rel or release for atomic reads}}
+  // expected-error @below {{memory-order must not be release for atomic reads}}
   omp.atomic.read %v = %x memory_order(release) : memref<i32>, memref<i32>, i32
   return
 }
@@ -1010,7 +1010,7 @@ func.func @omp_atomic_write1(%addr : memref<i32>, %val : i32) {
 // -----
 
 func.func @omp_atomic_write2(%addr : memref<i32>, %val : i32) {
-  // expected-error @below {{memory-order must not be acq_rel or acquire for atomic writes}}
+  // expected-error @below {{memory-order must not be acq_rel for atomic writes}}
   omp.atomic.write  %addr = %val memory_order(acq_rel) : memref<i32>, i32
   return
 }
@@ -1018,7 +1018,7 @@ func.func @omp_atomic_write2(%addr : memref<i32>, %val : i32) {
 // -----
 
 func.func @omp_atomic_write3(%addr : memref<i32>, %val : i32) {
-  // expected-error @below {{memory-order must not be acq_rel or acquire for atomic writes}}
+  // expected-error @below {{memory-order must not be acquire for atomic writes}}
   omp.atomic.write  %addr = %val memory_order(acquire) : memref<i32>, i32
   return
 }



More information about the flang-commits mailing list