[flang-commits] [flang] [mlir] [Flang] [OpenMP] atomic compare (PR #184761)

via flang-commits flang-commits at lists.llvm.org
Thu Mar 5 01:58:16 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (SunilKuravinakop)

<details>
<summary>Changes</summary>

Support for `omp atomic compare` in flang. 
Multiple clauses like capture with compare are not supported

An issue for this was raised earlier at [181116](https://github.com/llvm/llvm-project/issues/181116)

---

Patch is 35.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/184761.diff


10 Files Affected:

- (modified) flang/lib/Lower/OpenMP/Atomic.cpp (+143-2) 
- (added) flang/test/Integration/OpenMP/atomic-compare.f90 (+116) 
- (modified) flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 (+1-1) 
- (removed) flang/test/Lower/OpenMP/Todo/atomic-compare.f90 (-11) 
- (added) flang/test/Lower/OpenMP/atomic-compare.f90 (+123) 
- (modified) flang/test/Semantics/OpenMP/atomic-compare.f90 (+71) 
- (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+47-2) 
- (modified) mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp (+24) 
- (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+163-1) 
- (modified) mlir/test/Target/LLVMIR/openmp-llvm.mlir (+67) 


``````````diff
diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index f31de82fc2a5f..78c2f618fbad4 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -485,6 +485,47 @@ genAtomicOperation(lower::AbstractConverter &converter,
   }
 }
 
+/// Map a Fortran relational operator to an MLIR integer comparison predicate.
+static mlir::arith::CmpIPredicate
+mapRelationalOpToIntPredicate(Fortran::common::RelationalOperator relOpr) {
+  switch (relOpr) {
+  case Fortran::common::RelationalOperator::EQ:
+    return mlir::arith::CmpIPredicate::eq;
+  case Fortran::common::RelationalOperator::NE:
+    return mlir::arith::CmpIPredicate::ne;
+  case Fortran::common::RelationalOperator::LT:
+    return mlir::arith::CmpIPredicate::slt;
+  case Fortran::common::RelationalOperator::LE:
+    return mlir::arith::CmpIPredicate::sle;
+  case Fortran::common::RelationalOperator::GT:
+    return mlir::arith::CmpIPredicate::sgt;
+  case Fortran::common::RelationalOperator::GE:
+    return mlir::arith::CmpIPredicate::sge;
+  }
+  llvm_unreachable("unexpected relational operator");
+}
+
+/// Map a Fortran relational operator to an MLIR floating-point comparison
+/// predicate (ordered).
+static mlir::arith::CmpFPredicate
+mapRelationalOpToFPPredicate(Fortran::common::RelationalOperator relOpr) {
+  switch (relOpr) {
+  case Fortran::common::RelationalOperator::EQ:
+    return mlir::arith::CmpFPredicate::OEQ;
+  case Fortran::common::RelationalOperator::NE:
+    return mlir::arith::CmpFPredicate::ONE;
+  case Fortran::common::RelationalOperator::LT:
+    return mlir::arith::CmpFPredicate::OLT;
+  case Fortran::common::RelationalOperator::LE:
+    return mlir::arith::CmpFPredicate::OLE;
+  case Fortran::common::RelationalOperator::GT:
+    return mlir::arith::CmpFPredicate::OGT;
+  case Fortran::common::RelationalOperator::GE:
+    return mlir::arith::CmpFPredicate::OGE;
+  }
+  llvm_unreachable("unexpected relational operator");
+}
+
 void Fortran::lower::omp::lowerAtomic(
     AbstractConverter &converter, SymMap &symTable,
     semantics::SemanticsContext &semaCtx, pft::Evaluation &eval,
@@ -521,8 +562,108 @@ void Fortran::lower::omp::lowerAtomic(
     memOrder = makeValidForAction(memOrder, action0, action1, version);
 
   if (auto *cond = get(analysis.cond)) {
-    (void)cond;
-    TODO(loc, "OpenMP ATOMIC COMPARE");
+    // atomic compare: if (x == e) x = d
+    // e : expecteVal
+    // d : desiredVal
+
+    // Check for compound clauses (fail, capture, weak) that are not yet
+    // supported with atomic compare.
+    if (llvm::any_of(clauses, [](const omp::Clause &clause) {
+          return clause.id == llvm::omp::Clause::OMPC_fail ||
+                 clause.id == llvm::omp::Clause::OMPC_capture ||
+                 clause.id == llvm::omp::Clause::OMPC_weak;
+        })) {
+      TODO(loc, "Compound clauses of OpenMP ATOMIC COMPARE");
+    }
+
+    Fortran::common::RelationalOperator relOpr =
+        Fortran::common::RelationalOperator::EQ;
+    std::optional<semantics::SomeExpr> expectedExprStorage;
+
+    if (const auto *rel = Fortran::evaluate::UnwrapExpr<
+            Fortran::evaluate::Relational<Fortran::evaluate::SomeType>>(
+            *cond)) {
+      std::visit(
+          [&](const auto &relImpl) {
+            relOpr = relImpl.opr;
+            using Operand = typename std::decay_t<decltype(relImpl)>::Operand;
+            expectedExprStorage = Fortran::evaluate::AsGenericExpr(
+                Fortran::evaluate::Expr<Operand>{relImpl.right()});
+          },
+          rel->u);
+    }
+    if (!expectedExprStorage) {
+      mlir::emitError(loc, "internal error: atomic compare condition is not a "
+                           "recognized relational expression");
+      return;
+    }
+
+    mlir::UnitAttr weakAttr = nullptr;
+    mlir::Operation *atomicOp = mlir::omp::AtomicCompareOp::create(
+        builder, loc, atomAddr, weakAttr, hint,
+        makeMemOrderAttr(converter, memOrder));
+    mlir::Type elemTypeOfX = fir::unwrapRefType(atomAddr.getType());
+    mlir::Block *block = builder.createBlock(&atomicOp->getRegion(0));
+    mlir::Value blockArg = block->addArgument(elemTypeOfX, loc);
+    builder.setInsertionPointToEnd(block);
+
+    mlir::Value expectedVal = fir::getBase(
+        converter.genExprValue(*expectedExprStorage, stmtCtx, &loc));
+    if (expectedVal.getType() != elemTypeOfX) {
+      expectedVal = builder.createConvert(loc, elemTypeOfX, expectedVal);
+    }
+
+    // Generate comparison: e.g. x == e
+    mlir::Value cmpResult;
+    if (mlir::isa<mlir::IntegerType>(elemTypeOfX)) {
+      auto pred = mapRelationalOpToIntPredicate(relOpr);
+      cmpResult = mlir::arith::CmpIOp::create(builder, loc, pred, blockArg,
+                                              expectedVal);
+    } else if (mlir::isa<mlir::FloatType>(elemTypeOfX)) {
+      auto pred = mapRelationalOpToFPPredicate(relOpr);
+      cmpResult = mlir::arith::CmpFOp::create(builder, loc, pred, blockArg,
+                                              expectedVal);
+    } else {
+      llvm_unreachable("unsupported type for atomic compare");
+    }
+
+    // Check for presence of Assignment (x = d) and wether it is being invoked
+    // only for IfTrue condition.
+
+    // writeActionCond is a bitmask combining the following flags:
+    //  1) the action type (Read/Write/Update)
+    //  2) condition (IfTrue/IfFalse)
+    int writeActionCond = 0;
+    const evaluate::Assignment *writeAssign = nullptr;
+    if (analysis.op0.what & analysis.Write) {
+      writeAssign = get(analysis.op0.assign);
+      writeActionCond = analysis.op0.what;
+    }
+    if (!writeAssign && (analysis.op1.what & analysis.Write)) {
+      writeAssign = get(analysis.op1.assign);
+      writeActionCond = analysis.op1.what;
+    }
+    if (!writeAssign) {
+      mlir::emitError(loc,
+                      "internal error: atomic compare has no write assignment");
+      return;
+    }
+    assert((writeActionCond & analysis.IfTrue) &&
+           "atomic compare write should be conditioned on IfTrue");
+
+    // Generate new/desired value of x e.g. x = d
+    mlir::Value desiredVal =
+        fir::getBase(converter.genExprValue(writeAssign->rhs, stmtCtx, &loc));
+    if (desiredVal.getType() != elemTypeOfX)
+      desiredVal = builder.createConvert(loc, elemTypeOfX, desiredVal);
+    mlir::Value newVal = mlir::arith::SelectOp::create(builder, loc, cmpResult,
+                                                       desiredVal, blockArg);
+
+    // Generate omp.yield
+    mlir::omp::YieldOp::create(builder, loc, newVal);
+    builder.setInsertionPointAfter(atomicOp);
+
+    // END omp atomic compare
   } else {
     mlir::Operation *captureOp = nullptr;
     fir::FirOpBuilder::InsertPoint preAt = builder.saveInsertionPoint();
diff --git a/flang/test/Integration/OpenMP/atomic-compare.f90 b/flang/test/Integration/OpenMP/atomic-compare.f90
new file mode 100644
index 0000000000000..c5be037b7533f
--- /dev/null
+++ b/flang/test/Integration/OpenMP/atomic-compare.f90
@@ -0,0 +1,116 @@
+!===----------------------------------------------------------------------===!
+! 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
+
+! Int "==" → cmpxchg, default (monotonic) ordering
+!CHECK-LABEL: define void @atomic_compare_integer_(
+!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
+subroutine atomic_compare_integer(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare
+  if (x == e) x = d
+end
+
+! seq_cst ordering → cmpxchg seq_cst + flush
+!CHECK-LABEL: define void @atomic_compare_seq_cst_(
+!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]] seq_cst seq_cst
+!CHECK: call void @__kmpc_flush(
+subroutine atomic_compare_seq_cst(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare seq_cst
+  if (x == e) x = d
+end
+
+! acquire ordering → cmpxchg acquire
+!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
+subroutine atomic_compare_acquire(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare acquire
+  if (x == e) x = d
+end
+
+! release ordering → cmpxchg release + flush
+!CHECK-LABEL: define void @atomic_compare_release_(
+!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]] release monotonic
+!CHECK: call void @__kmpc_flush(
+subroutine atomic_compare_release(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare release
+  if (x == e) x = d
+end
+
+! relaxed ordering → cmpxchg monotonic
+!CHECK-LABEL: define void @atomic_compare_relaxed_(
+!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
+subroutine atomic_compare_relaxed(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare relaxed
+  if (x == e) x = d
+end
+
+! Less-than comparison → atomicrmw umax
+!CHECK-LABEL: define void @atomic_compare_lt_(
+!CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]])
+!CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
+!CHECK: atomicrmw umax ptr %[[X]], i32 %[[EVAL]] monotonic
+subroutine atomic_compare_lt(x, e)
+  integer :: x, e
+  !$omp atomic compare
+  if (x < e) x = e
+end
+
+! Less-than with seq_cst → atomicrmw umax seq_cst + flush
+!CHECK-LABEL: define void @atomic_compare_lt_seq_cst_(
+!CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]])
+!CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
+!CHECK: atomicrmw umax ptr %[[X]], i32 %[[EVAL]] seq_cst
+!CHECK: call void @__kmpc_flush(
+subroutine atomic_compare_lt_seq_cst(x, e)
+  integer :: x, e
+  !$omp atomic compare seq_cst
+  if (x < e) x = e
+end
+
+! Less-than with acquire → atomicrmw umax acquire
+!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 umax ptr %[[X]], i32 %[[EVAL]] acquire
+subroutine atomic_compare_lt_acquire(x, e)
+  integer :: x, e
+  !$omp atomic compare acquire
+  if (x < e) x = e
+end
+
+! Greater-than comparison → atomicrmw umin
+!CHECK-LABEL: define void @atomic_compare_gt_(
+!CHECK-SAME: ptr noalias %[[X:.*]], ptr noalias %[[E:.*]])
+!CHECK: %[[EVAL:.*]] = load i32, ptr %[[E]], align 4
+!CHECK: atomicrmw umin ptr %[[X]], i32 %[[EVAL]] monotonic
+subroutine atomic_compare_gt(x, e)
+  integer :: x, e
+  !$omp atomic compare
+  if (x > e) x = e
+end
diff --git a/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 b/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90
index 6f58e0939a787..3369a6223cf73 100644
--- a/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90
+++ b/flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90
@@ -1,6 +1,6 @@
 ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
 
-! CHECK: not yet implemented: OpenMP ATOMIC COMPARE
+! CHECK: not yet implemented: Compound clauses of OpenMP ATOMIC COMPARE
 program p
   integer :: x
   logical :: r
diff --git a/flang/test/Lower/OpenMP/Todo/atomic-compare.f90 b/flang/test/Lower/OpenMP/Todo/atomic-compare.f90
deleted file mode 100644
index 6729be6e5cf8b..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/atomic-compare.f90
+++ /dev/null
@@ -1,11 +0,0 @@
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: OpenMP ATOMIC COMPARE
-program p
-  integer :: x
-  logical :: r
-  !$omp atomic compare
-  if (x .eq. 0) then
-     x = 2
-  end if
-end program p
diff --git a/flang/test/Lower/OpenMP/atomic-compare.f90 b/flang/test/Lower/OpenMP/atomic-compare.f90
new file mode 100644
index 0000000000000..e69c0b55d5351
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-compare.f90
@@ -0,0 +1,123 @@
+! REQUIRES: openmp_runtime
+
+! This test checks lowering of atomic compare constructs.
+! RUN: bbc %openmp_flags -fopenmp-version=51 -emit-hlfir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 %s -o - | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPatomic_compare_int_eq(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<i32> {fir.bindc_name = "e"},
+! CHECK-SAME:    %[[D:.*]]: !fir.ref<i32> {fir.bindc_name = "d"})
+! CHECK:         %[[D_DECL:.*]]:2 = hlfir.declare %[[D]] {{.*}}
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<i32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: i32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[CMP:.*]] = arith.cmpi eq, %[[XVAL]], %[[EVAL]] : i32
+! CHECK:           %[[DVAL:.*]] = fir.load %[[D_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[DVAL]], %[[XVAL]] : i32
+! CHECK:           omp.yield(%[[SEL]] : i32)
+! CHECK:         }
+subroutine atomic_compare_int_eq(x, e, d)
+  integer :: x, e, d
+  !$omp atomic compare
+  if (x .eq. e) x = d
+end
+
+! CHECK-LABEL: func.func @_QPatomic_compare_float_eq(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<f32> {fir.bindc_name = "e"},
+! CHECK-SAME:    %[[D:.*]]: !fir.ref<f32> {fir.bindc_name = "d"})
+! CHECK:         %[[D_DECL:.*]]:2 = hlfir.declare %[[D]] {{.*}}
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<f32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: f32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[CMP:.*]] = arith.cmpf oeq, %[[XVAL]], %[[EVAL]] fastmath<contract> : f32
+! CHECK:           %[[DVAL:.*]] = fir.load %[[D_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[DVAL]], %[[XVAL]] : f32
+! CHECK:           omp.yield(%[[SEL]] : f32)
+! CHECK:         }
+subroutine atomic_compare_float_eq(x, e, d)
+  real :: x, e, d
+  !$omp atomic compare
+  if (x .eq. e) x = d
+end
+
+! CHECK-LABEL: func.func @_QPatomic_compare_int_lt(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<i32> {fir.bindc_name = "e"})
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<i32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: i32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[CMP:.*]] = arith.cmpi slt, %[[XVAL]], %[[EVAL]] : i32
+! CHECK:           %[[EVAL2:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[EVAL2]], %[[XVAL]] : i32
+! CHECK:           omp.yield(%[[SEL]] : i32)
+! CHECK:         }
+subroutine atomic_compare_int_lt(x, e)
+  integer :: x, e
+  !$omp atomic compare
+  if (x .lt. e) x = e
+end
+
+! CHECK-LABEL: func.func @_QPatomic_compare_int_gt(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<i32> {fir.bindc_name = "e"})
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<i32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: i32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[CMP:.*]] = arith.cmpi sgt, %[[XVAL]], %[[EVAL]] : i32
+! CHECK:           %[[EVAL2:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<i32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[EVAL2]], %[[XVAL]] : i32
+! CHECK:           omp.yield(%[[SEL]] : i32)
+! CHECK:         }
+subroutine atomic_compare_int_gt(x, e)
+  integer :: x, e
+  !$omp atomic compare
+  if (x .gt. e) x = e
+end
+
+! CHECK-LABEL: func.func @_QPatomic_compare_float_lt(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<f32> {fir.bindc_name = "e"})
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<f32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: f32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[CMP:.*]] = arith.cmpf olt, %[[XVAL]], %[[EVAL]] fastmath<contract> : f32
+! CHECK:           %[[EVAL2:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[EVAL2]], %[[XVAL]] : f32
+! CHECK:           omp.yield(%[[SEL]] : f32)
+! CHECK:         }
+subroutine atomic_compare_float_lt(x, e)
+  real :: x, e
+  !$omp atomic compare
+  if (x .lt. e) x = e
+end
+
+! CHECK-LABEL: func.func @_QPatomic_compare_float_gt(
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<f32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[E:.*]]: !fir.ref<f32> {fir.bindc_name = "e"})
+! CHECK:         %[[E_DECL:.*]]:2 = hlfir.declare %[[E]] {{.*}}
+! CHECK:         %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {{.*}}
+! CHECK:         omp.atomic.compare memory_order(relaxed) %[[X_DECL]]#0 : !fir.ref<f32> {
+! CHECK:         ^bb0(%[[XVAL:.*]]: f32):
+! CHECK:           %[[EVAL:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[CMP:.*]] = arith.cmpf ogt, %[[XVAL]], %[[EVAL]] fastmath<contract> : f32
+! CHECK:           %[[EVAL2:.*]] = fir.load %[[E_DECL]]#0 : !fir.ref<f32>
+! CHECK:           %[[SEL:.*]] = arith.select %[[CMP]], %[[EVAL2]], %[[XVAL]] : f32
+! CHECK:           omp.yield(%[[SEL]] : f32)
+! CHECK:         }
+subroutine atomic_compare_float_gt(x, e)
+  real :: x, e
+  !$omp atomic compare
+  if (x .gt. e) x = e
+end
diff --git a/flang/test/Semantics/OpenMP/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90
index 6a4fbe7ffe81b..0e53729c2f02a 100644
--- a/flang/test/Semantics/OpenMP/atomic-compare.f90
+++ b/flang/test/Semantics/OpenMP/atomic-compare.f90
@@ -8,6 +8,7 @@
 
 
   real a, b, c
+  logical :: r, s
   a = 1.0
   b = 2.0
   c = 3.0
@@ -43,6 +44,20 @@
   if (c .eq. a) a = b
   !$omp end atomic
 
+  ! Less-than comparison.
+  !$omp atomic compare
+  if (b .lt. a) b = c
+
+  ! Greater-than comparison.
+  !$omp atomic compare
+  if (b .gt. a) b = c
+
+  ! Two-statement form: r = cond; if (r) update.
+  !$omp atomic compare
+  r = b .eq. a
+  if (r) b = c
+  !$omp end atomic
+
   ! Check for error conditions:
   !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive
   !$omp atomic seq_cst seq_cst compare
@@ -79,5 +94,61 @@
   if (c .eq. a) a = b
   !$omp end atomic
 
+  ! The /= operator is not valid for atomic compare.
+  !$omp atomic compare
+  !ERROR: The /= operator is not a valid condition for ATOMIC operation
+  if (b .ne. ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/184761


More information about the flang-commits mailing list