[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