[flang-commits] [flang] 2b2bf30 - [flang][OpenMP] Support for compare fail (#214179)

via flang-commits flang-commits at lists.llvm.org
Mon Aug 10 00:32:25 PDT 2026


Author: SunilKuravinakop
Date: 2026-08-10T13:02:19+05:30
New Revision: 2b2bf30c00ae068c1edf3c7753c8c14157207f64

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

LOG: [flang][OpenMP] Support for compare fail (#214179)

Support for fail clause in "!omp atomic compare fail".
  
This also Fixes
[#214176](https://github.com/llvm/llvm-project/issues/214176)

Co-authored-by: Sunil Kuravinakop

Added: 
    flang/test/Lower/OpenMP/atomic-compare-fail.f90
    flang/test/Semantics/OpenMP/atomic-compare-fail.f90

Modified: 
    flang/lib/Lower/OpenMP/Atomic.cpp
    flang/lib/Semantics/check-omp-atomic.cpp
    flang/test/Semantics/OpenMP/atomic-compare.f90
    mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
    mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
    mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
    mlir/test/Dialect/OpenMP/invalid.mlir
    mlir/test/Dialect/OpenMP/ops.mlir
    mlir/test/Target/LLVMIR/openmp-llvm.mlir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index 80a07e37d951a..faf170c49149e 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -159,6 +159,24 @@ getMemoryOrderKind(common::OmpMemoryOrderType kind) {
   llvm_unreachable("Unexpected kind");
 }
 
+static mlir::omp::ClauseMemoryOrderKind
+getMemoryOrderKind(omp::clause::Fail::MemoryOrder kind) {
+  using MemoryOrder = omp::clause::Fail::MemoryOrder;
+  switch (kind) {
+  case MemoryOrder::AcqRel:
+    return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
+  case MemoryOrder::Acquire:
+    return mlir::omp::ClauseMemoryOrderKind::Acquire;
+  case MemoryOrder::Relaxed:
+    return mlir::omp::ClauseMemoryOrderKind::Relaxed;
+  case MemoryOrder::Release:
+    return mlir::omp::ClauseMemoryOrderKind::Release;
+  case MemoryOrder::SeqCst:
+    return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
+  }
+  llvm_unreachable("Unexpected memory order");
+}
+
 static std::optional<mlir::omp::ClauseMemoryOrderKind>
 getMemoryOrderKind(llvm::omp::Clause clauseId) {
   switch (clauseId) {
@@ -564,15 +582,23 @@ void Fortran::lower::omp::lowerAtomic(
     // e : expecteVal
     // d : desiredVal
 
-    // Check for compound clauses (fail, capture) that are not yet
-    // supported with atomic compare.
+    // Atomic compare with capture is not yet supported.
     if (llvm::any_of(clauses, [](const omp::Clause &clause) {
-          return clause.id == llvm::omp::Clause::OMPC_fail ||
-                 clause.id == llvm::omp::Clause::OMPC_capture;
+          return clause.id == llvm::omp::Clause::OMPC_capture;
         })) {
       TODO(loc, "Compound clauses of OpenMP ATOMIC COMPARE");
     }
 
+    // The `fail` clause sets the memory ordering for a failed compare;
+    // extract its argument to attach to the omp.atomic.compare op below.
+    std::optional<mlir::omp::ClauseMemoryOrderKind> failMemOrder;
+    for (const omp::Clause &clause : clauses) {
+      if (const auto *fail = std::get_if<omp::clause::Fail>(&clause.u)) {
+        failMemOrder = getMemoryOrderKind(fail->v);
+        break;
+      }
+    }
+
     common::RelationalOperator relOpr = common::RelationalOperator::EQ;
     std::optional<semantics::SomeExpr> expectedExprStorage;
     bool isUnsigned = false;
@@ -624,7 +650,8 @@ void Fortran::lower::omp::lowerAtomic(
     }
     mlir::Operation *atomicOp = mlir::omp::AtomicCompareOp::create(
         builder, loc, atomAddr, weakAttr, hint,
-        makeMemOrderAttr(converter, memOrder));
+        makeMemOrderAttr(converter, memOrder),
+        makeMemOrderAttr(converter, failMemOrder));
     mlir::Block *block = builder.createBlock(&atomicOp->getRegion(0));
     mlir::Value blockArg = block->addArgument(elemTypeOfX, loc);
     builder.setInsertionPointToEnd(block);

diff  --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index ec307be469982..810d91a54d710 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -1648,6 +1648,21 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
 
   checkIncompatibleMemoryOrderClause(context_, x, atomic, memoryOrder);
 
+  // OpenMP 5.2 [15.8.3] extended-atomic Clauses: acq_rel and release cannot
+  // be specified as arguments to the fail clause, so its memory order argument
+  // must be SEQ_CST, ACQUIRE, or RELAXED.
+  for (const parser::OmpClause &clause : dirSpec.Clauses().v) {
+    if (const auto *fail{std::get_if<parser::OmpClause::Fail>(&clause.u)}) {
+      common::OmpMemoryOrderType ord{fail->v.v};
+      if (ord != common::OmpMemoryOrderType::Seq_Cst &&
+          ord != common::OmpMemoryOrderType::Acquire &&
+          ord != common::OmpMemoryOrderType::Relaxed) {
+        context_.Say(clause.source,
+            "The argument of the FAIL clause must be SEQ_CST, ACQUIRE, or RELAXED"_err_en_US);
+      }
+    }
+  }
+
   switch (kind) {
   case llvm::omp::Clause::OMPC_read:
     CheckAtomicRead(x);

diff  --git a/flang/test/Lower/OpenMP/atomic-compare-fail.f90 b/flang/test/Lower/OpenMP/atomic-compare-fail.f90
new file mode 100644
index 0000000000000..5f63ffa4890fd
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-compare-fail.f90
@@ -0,0 +1,43 @@
+! This test checks lowering of the OpenMP `fail` clause on a (non-capturing)
+! atomic compare construct. The fail memory order is attached as the
+! `fail_memory_order` attribute on omp.atomic.compare.
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s
+! RUN: bbc -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPfail_acquire
+subroutine fail_acquire(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare fail(acquire)
+  if (x == e) x = d
+end
+! CHECK: omp.atomic.compare memory_order(relaxed) %{{.*}} : !fir.ref<i32> {
+! CHECK: ^bb0(%[[XVAL:.*]]: i32):
+! CHECK:   arith.cmpi eq, %[[XVAL]], %{{.*}} : i32
+! CHECK:   omp.yield
+! CHECK: } {fail_memory_order = #omp<memoryorderkind acquire>}
+
+! CHECK-LABEL: func.func @_QPfail_relaxed
+subroutine fail_relaxed(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare fail(relaxed)
+  if (x == e) x = d
+end
+! CHECK: } {fail_memory_order = #omp<memoryorderkind relaxed>}
+
+! CHECK-LABEL: func.func @_QPfail_seqcst
+subroutine fail_seqcst(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare fail(seq_cst)
+  if (x == e) x = d
+end
+! CHECK: } {fail_memory_order = #omp<memoryorderkind seq_cst>}
+
+! CHECK-LABEL: func.func @_QPseqcst_fail_relaxed
+subroutine seqcst_fail_relaxed(x, e, d)
+  integer :: x, e, d
+  !$omp atomic seq_cst compare fail(relaxed)
+  if (x == e) x = d
+end
+! CHECK: omp.atomic.compare memory_order(seq_cst) %{{.*}} : !fir.ref<i32> {
+! CHECK: } {fail_memory_order = #omp<memoryorderkind relaxed>}

diff  --git a/flang/test/Semantics/OpenMP/atomic-compare-fail.f90 b/flang/test/Semantics/OpenMP/atomic-compare-fail.f90
new file mode 100644
index 0000000000000..10522dd3d950e
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/atomic-compare-fail.f90
@@ -0,0 +1,27 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52
+
+! OpenMP 5.2 [15.8.3] extended-atomic Clauses: acq_rel and release cannot be
+! specified as arguments to the fail clause, so the argument must be SEQ_CST,
+! ACQUIRE, or RELAXED.
+
+subroutine valid(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare fail(seq_cst)
+  if (x == e) x = d
+  !$omp atomic compare fail(acquire)
+  if (x == e) x = d
+  !$omp atomic compare fail(relaxed)
+  if (x == e) x = d
+  !$omp atomic seq_cst compare fail(relaxed)
+  if (x == e) x = d
+end
+
+subroutine invalid(x, e, d)
+  integer :: x, e, d
+  !ERROR: The argument of the FAIL clause must be SEQ_CST, ACQUIRE, or RELAXED
+  !$omp atomic compare fail(release)
+  if (x == e) x = d
+  !ERROR: The argument of the FAIL clause must be SEQ_CST, ACQUIRE, or RELAXED
+  !$omp atomic compare fail(acq_rel)
+  if (x == e) x = d
+end

diff  --git a/flang/test/Semantics/OpenMP/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90
index 10da3e13d0992..64b2c2b3a9225 100644
--- a/flang/test/Semantics/OpenMP/atomic-compare.f90
+++ b/flang/test/Semantics/OpenMP/atomic-compare.f90
@@ -36,11 +36,11 @@
   if (b .eq. a) b = c
   !$omp end atomic
 
-  !$omp atomic hint(1) acq_rel compare fail(release)
+  !$omp atomic hint(1) acq_rel compare fail(acquire)
   if (c .eq. a) a = b
   !$omp end atomic
 
-  !$omp atomic compare fail(release)
+  !$omp atomic compare fail(acquire)
   if (c .eq. a) a = b
   !$omp end atomic
 
@@ -90,7 +90,7 @@
   if (b .eq. c) b = a
 
   !ERROR: At most one FAIL clause can appear on ATOMIC directive
-  !$omp atomic fail(release) compare fail(release)
+  !$omp atomic fail(acquire) compare fail(acquire)
   if (c .eq. a) a = b
   !$omp end atomic
 

diff  --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 70597b85902c5..23f4711c9c355 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -2047,13 +2047,20 @@ def AtomicCompareOp : OpenMP_Op<"atomic.compare", traits = [
         omp.yield
       }
     ```
+
+    The optional `fail_memory_order` attribute specifies the memory ordering
+    to use for the comparison when the atomic conditional update fails (i.e.
+    the value of `x` is not updated). It corresponds to the OpenMP `fail`
+    clause and overrides the failure ordering that would otherwise be derived
+    from the construct's memory ordering.
   }] # clausesDescription;
 
   let arguments = !con(
       (ins Arg<OpenMP_PointerLikeType,
                "Address of variable to be compared/updated", [MemRead, MemWrite]>:$x,
            UnitAttr:$weak),
-      clausesArgs);
+      clausesArgs,
+      (ins OptionalAttr<MemoryOrderKindAttr>:$fail_memory_order));
 
   // Override region definition.
   let regions = (region SizedRegion<1>:$region);

diff  --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index d941b62d13414..4a9444ca40a30 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -5008,6 +5008,16 @@ LogicalResult AtomicCaptureOp::verifyRegions() {
 LogicalResult AtomicCompareOp::verify() {
   if (verifyCommon().failed())
     return mlir::failure();
+  // OpenMP 5.2 [15.8.3]: the fail clause argument must be one of seq_cst,
+  // acquire or relaxed ('release' and 'acq_rel' are not valid failure
+  // orderings and map to invalid cmpxchg failure orderings).
+  if (auto failOrder = getFailMemoryOrder()) {
+    if (*failOrder != ClauseMemoryOrderKind::Seq_cst &&
+        *failOrder != ClauseMemoryOrderKind::Acquire &&
+        *failOrder != ClauseMemoryOrderKind::Relaxed)
+      return emitOpError(
+          "fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'");
+  }
   return verifySynchronizationHint(*this, getHint());
 }
 

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 4c4f8ba9bce3d..6f692e0c14db2 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -6122,8 +6122,14 @@ convertOmpAtomicCompare(omp::AtomicCompareOp atomicCompareOp,
     llvm::Value *dInt =
         builder.CreateAlignedLoad(intTy, dAlloca, maxAlign, "cmplx.d.int");
 
+    // Honor the `fail` clause ordering when present (the verifier guarantees
+    // it is a valid cmpxchg failure ordering); otherwise derive it from the
+    // success ordering.
     llvm::AtomicOrdering failOrdering =
-        llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(atomicOrdering);
+        atomicCompareOp.getFailMemoryOrder()
+            ? convertAtomicOrdering(atomicCompareOp.getFailMemoryOrder())
+            : llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(
+                  atomicOrdering);
     auto *cmpXchg = builder.CreateAtomicCmpXchg(llvmX, eInt, dInt, maxAlign,
                                                 atomicOrdering, failOrdering);
     cmpXchg->setWeak(atomicCompareOp.getWeak());
@@ -6211,10 +6217,19 @@ convertOmpAtomicCompare(omp::AtomicCompareOp atomicCompareOp,
   bool isWeak = atomicCompareOp.getWeak();
 
   bool savedHandleFPNegZero = ompBuilder->setHandleFPNegZero(true);
-  llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP =
-      ompBuilder->createAtomicCompare(ompLoc, llvmAtomicX, vOpVal, rOpVal, eVal,
-                                      dVal, atomicOrdering, compareOp,
-                                      isXBinopExpr, false, false, isWeak);
+  llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP = [&]() {
+    if (auto failOrder = atomicCompareOp.getFailMemoryOrder()) {
+      llvm::AtomicOrdering failureOrdering = convertAtomicOrdering(*failOrder);
+      return ompBuilder->createAtomicCompare(
+          ompLoc, llvmAtomicX, vOpVal, rOpVal, eVal, dVal, atomicOrdering,
+          compareOp, isXBinopExpr, /*IsPostfixUpdate=*/false,
+          /*IsFailOnly=*/false, failureOrdering, isWeak);
+    }
+    return ompBuilder->createAtomicCompare(
+        ompLoc, llvmAtomicX, vOpVal, rOpVal, eVal, dVal, atomicOrdering,
+        compareOp, isXBinopExpr, /*IsPostfixUpdate=*/false,
+        /*IsFailOnly=*/false, isWeak);
+  }();
   ompBuilder->setHandleFPNegZero(savedHandleFPNegZero);
 
   if (failed(handleError(afterIP, *atomicCompareOp)))

diff  --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 56dae56f2fb8c..c43e4c4107452 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -1465,6 +1465,34 @@ func.func @omp_atomic_compare_invalid_hint2(%x: memref<i32>, %e: i32, %d: i32) {
   return
 }
 
+// -----
+// OpenMP 5.2 [15.8.3]: 'release' is not a valid argument to the fail clause.
+
+func.func @omp_atomic_compare_invalid_fail_release(%x: memref<i32>, %e: i32, %d: i32) {
+  // expected-error @below {{fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'}}
+  omp.atomic.compare %x : memref<i32> {
+  ^bb0(%xval: i32):
+    %cmp = llvm.icmp "eq" %xval, %e : i32
+    %sel = llvm.select %cmp, %d, %xval : i1, i32
+    omp.yield(%sel : i32)
+  } {fail_memory_order = #omp<memoryorderkind release>}
+  return
+}
+
+// -----
+// OpenMP 5.2 [15.8.3]: 'acq_rel' is not a valid argument to the fail clause.
+
+func.func @omp_atomic_compare_invalid_fail_acq_rel(%x: memref<i32>, %e: i32, %d: i32) {
+  // expected-error @below {{fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'}}
+  omp.atomic.compare %x : memref<i32> {
+  ^bb0(%xval: i32):
+    %cmp = llvm.icmp "eq" %xval, %e : i32
+    %sel = llvm.select %cmp, %d, %xval : i1, i32
+    omp.yield(%sel : i32)
+  } {fail_memory_order = #omp<memoryorderkind acq_rel>}
+  return
+}
+
 // -----
 // float comparison operators mentionend in ArithBase.td not permitted for
 //     !omp atomic compare

diff  --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 00b975c371d1b..a035205a4d2b4 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -2134,6 +2134,24 @@ func.func @omp_atomic_compare(%x: memref<i32>, %e: i32, %d: i32) {
   return
 }
 
+// CHECK-LABEL: omp_atomic_compare_fail
+// CHECK-SAME: (%[[X:.*]]: memref<i32>, %[[E:.*]]: i32, %[[D:.*]]: i32)
+func.func @omp_atomic_compare_fail(%x: memref<i32>, %e: i32, %d: i32) {
+  // CHECK: omp.atomic.compare memory_order(seq_cst) %[[X]] : memref<i32> {
+  // CHECK-NEXT: ^bb0(%[[XVAL:.*]]: i32):
+  // CHECK-NEXT:   %[[CMP:.*]] = arith.cmpi eq, %[[XVAL]], %[[E]] : i32
+  // CHECK-NEXT:   %[[SEL:.*]] = arith.select %[[CMP]], %[[D]], %[[XVAL]] : i32
+  // CHECK-NEXT:   omp.yield(%[[SEL]] : i32)
+  // CHECK-NEXT: } {fail_memory_order = #omp<memoryorderkind acquire>}
+  omp.atomic.compare memory_order(seq_cst) %x : memref<i32> {
+  ^bb0(%xval: i32):
+    %cmp = arith.cmpi eq, %xval, %e : i32
+    %sel = arith.select %cmp, %d, %xval : i32
+    omp.yield(%sel : i32)
+  } {fail_memory_order = #omp<memoryorderkind acquire>}
+  return
+}
+
 // CHECK-LABEL: omp_sectionsop
 func.func @omp_sectionsop(%data_var1 : memref<i32>, %data_var2 : memref<i32>,
                      %data_var3 : memref<i32>, %redn_var : !llvm.ptr) {

diff  --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index e867dd8afcb9b..1a9e6ac0a2bdd 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -2811,6 +2811,79 @@ llvm.func @omp_atomic_compare_weak(%x : !llvm.ptr, %e : i32, %d : i32) {
 
 // -----
 
+// CHECK-LABEL: @omp_atomic_compare_fail
+// CHECK-SAME: (ptr %[[X:.*]], i32 %[[E:.*]], i32 %[[D:.*]])
+llvm.func @omp_atomic_compare_fail(%x : !llvm.ptr, %e : i32, %d : i32) {
+  // The fail clause sets the cmpxchg failure ordering independently of the
+  // success ordering. Relaxed success + acquire failure.
+  // CHECK: cmpxchg ptr %[[X]], i32 %[[E]], i32 %[[D]] monotonic acquire
+  omp.atomic.compare %x : !llvm.ptr {
+  ^bb0(%xval : i32):
+    %cmp = llvm.icmp "eq" %xval, %e : i32
+    %sel = llvm.select %cmp, %d, %xval : i1, i32
+    omp.yield(%sel : i32)
+  } {fail_memory_order = #omp<memoryorderkind acquire>}
+
+  // Seq_cst success + relaxed failure. The seq_cst success ordering still
+  // requires the flush on the new fail_memory_order code path.
+  // CHECK: cmpxchg ptr %[[X]], i32 %[[E]], i32 %[[D]] seq_cst monotonic
+  // CHECK: call void @__kmpc_flush(ptr @{{.*}})
+  omp.atomic.compare memory_order(seq_cst) %x : !llvm.ptr {
+  ^bb0(%xval : i32):
+    %cmp = llvm.icmp "eq" %xval, %e : i32
+    %sel = llvm.select %cmp, %d, %xval : i1, i32
+    omp.yield(%sel : i32)
+  } {fail_memory_order = #omp<memoryorderkind relaxed>}
+
+  llvm.return
+}
+
+// -----
+
+// CHECK-LABEL: @omp_atomic_compare_complex_fail
+// CHECK-SAME: (ptr %[[X:.*]], ptr %[[E:.*]], ptr %[[D:.*]])
+// The complex (struct) compare path must honor the fail clause ordering too,
+// not just derive the failure ordering from the success ordering.
+llvm.func @omp_atomic_compare_complex_fail(%x: !llvm.ptr, %e: !llvm.ptr, %d: !llvm.ptr) {
+  %e0 = llvm.load %e : !llvm.ptr -> !llvm.struct<(f32, f32)>
+  // Relaxed success + acquire failure.
+  // CHECK: cmpxchg ptr %[[X]], i64 %{{.*}}, i64 %{{.*}} monotonic acquire
+  omp.atomic.compare memory_order(relaxed) %x : !llvm.ptr {
+  ^bb0(%xval: !llvm.struct<(f32, f32)>):
+    %xr = llvm.extractvalue %xval[0] : !llvm.struct<(f32, f32)>
+    %er = llvm.extractvalue %e0[0] : !llvm.struct<(f32, f32)>
+    %cr = llvm.fcmp "oeq" %xr, %er : f32
+    %xi = llvm.extractvalue %xval[1] : !llvm.struct<(f32, f32)>
+    %ei = llvm.extractvalue %e0[1] : !llvm.struct<(f32, f32)>
+    %ci = llvm.fcmp "oeq" %xi, %ei : f32
+    %cmp = llvm.and %cr, %ci : i1
+    %dval = llvm.load %d : !llvm.ptr -> !llvm.struct<(f32, f32)>
+    %sel = llvm.select %cmp, %dval, %xval : i1, !llvm.struct<(f32, f32)>
+    omp.yield(%sel : !llvm.struct<(f32, f32)>)
+  } {fail_memory_order = #omp<memoryorderkind acquire>}
+
+  // Seq_cst success + relaxed failure still emits the flush on the complex path.
+  // CHECK: cmpxchg ptr %[[X]], i64 %{{.*}}, i64 %{{.*}} seq_cst monotonic
+  // CHECK: call void @__kmpc_flush(ptr @{{.*}})
+  omp.atomic.compare memory_order(seq_cst) %x : !llvm.ptr {
+  ^bb0(%xval: !llvm.struct<(f32, f32)>):
+    %xr = llvm.extractvalue %xval[0] : !llvm.struct<(f32, f32)>
+    %er = llvm.extractvalue %e0[0] : !llvm.struct<(f32, f32)>
+    %cr = llvm.fcmp "oeq" %xr, %er : f32
+    %xi = llvm.extractvalue %xval[1] : !llvm.struct<(f32, f32)>
+    %ei = llvm.extractvalue %e0[1] : !llvm.struct<(f32, f32)>
+    %ci = llvm.fcmp "oeq" %xi, %ei : f32
+    %cmp = llvm.and %cr, %ci : i1
+    %dval = llvm.load %d : !llvm.ptr -> !llvm.struct<(f32, f32)>
+    %sel = llvm.select %cmp, %dval, %xval : i1, !llvm.struct<(f32, f32)>
+    omp.yield(%sel : !llvm.struct<(f32, f32)>)
+  } {fail_memory_order = #omp<memoryorderkind relaxed>}
+
+  llvm.return
+}
+
+// -----
+
 // CHECK-LABEL: @omp_atomic_compare_float_neg_zero
 // CHECK-SAME: (ptr %[[XF:.*]], float %[[EF:.*]], float %[[DF:.*]])
 // Verify NaN guard + ±0.0 handling.


        


More information about the flang-commits mailing list