[flang-commits] [flang] [llvm] [mlir] Revert "Revert "[Flang] [OpenMP] atomic compare (#184761)"" (PR #198978)

via flang-commits flang-commits at lists.llvm.org
Thu May 21 01:07:08 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: CHANDRA GHALE (chandraghale)

<details>
<summary>Changes</summary>

Reverts llvm/llvm-project#<!-- -->198848

Reverting the reverted PR [https://github.com/llvm/llvm-project/pull/198848](https://github.com/llvm/llvm-project/pull/198848) , since the actual issue was different and the original PR [https://github.com/llvm/llvm-project/pull/184761](https://github.com/llvm/llvm-project/pull/184761) was reverted incorrectly.

Ref :
https://github.com/llvm/llvm-project/pull/184761#issuecomment-4501760965


---

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


19 Files Affected:

- (modified) flang/include/flang/Lower/ConvertType.h (+8) 
- (modified) flang/lib/Lower/ConvertExprToHLFIR.cpp (+9-51) 
- (modified) flang/lib/Lower/ConvertType.cpp (+66) 
- (modified) flang/lib/Lower/OpenMP/Atomic.cpp (+142-2) 
- (added) flang/test/Integration/OpenMP/atomic-compare.f90 (+250) 
- (modified) flang/test/Lower/OpenMP/Todo/atomic-compare-fail.f90 (+19-2) 
- (removed) flang/test/Lower/OpenMP/Todo/atomic-compare.f90 (-11) 
- (added) flang/test/Lower/OpenMP/atomic-compare.f90 (+142) 
- (modified) flang/test/Semantics/OpenMP/atomic-compare.f90 (+71) 
- (modified) llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h (+12) 
- (modified) llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp (+234-63) 
- (modified) mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.h (+1) 
- (modified) mlir/include/mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.td (+171) 
- (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+49-3) 
- (modified) mlir/lib/Dialect/OpenACCMPCommon/Interfaces/CMakeLists.txt (+2) 
- (modified) mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp (+26) 
- (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+359) 
- (modified) mlir/test/Dialect/OpenMP/invalid.mlir (+517) 
- (modified) mlir/test/Target/LLVMIR/openmp-llvm.mlir (+209) 


``````````diff
diff --git a/flang/include/flang/Lower/ConvertType.h b/flang/include/flang/Lower/ConvertType.h
index 3c726595c0f76..16b299e2ab319 100644
--- a/flang/include/flang/Lower/ConvertType.h
+++ b/flang/include/flang/Lower/ConvertType.h
@@ -23,6 +23,7 @@
 
 #include "flang/Evaluate/type.h"
 #include "flang/Support/Fortran.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/IR/BuiltinTypes.h"
 
 namespace mlir {
@@ -130,6 +131,13 @@ class ComponentReverseIterator {
   name_iterator componentIt{};
   name_iterator componentItEnd{};
 };
+
+mlir::arith::CmpIPredicate
+translateSignedRelational(Fortran::common::RelationalOperator rop);
+mlir::arith::CmpIPredicate
+translateUnsignedRelational(Fortran::common::RelationalOperator rop);
+mlir::arith::CmpFPredicate
+translateFloatRelational(Fortran::common::RelationalOperator rop);
 } // namespace lower
 } // namespace Fortran
 
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index a57fce53c0ca5..21436bd1b8d15 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1191,52 +1191,6 @@ translateSignedRelational(Fortran::common::RelationalOperator rop) {
   llvm_unreachable("unhandled INTEGER relational operator");
 }
 
-static mlir::arith::CmpIPredicate
-translateUnsignedRelational(Fortran::common::RelationalOperator rop) {
-  switch (rop) {
-  case Fortran::common::RelationalOperator::LT:
-    return mlir::arith::CmpIPredicate::ult;
-  case Fortran::common::RelationalOperator::LE:
-    return mlir::arith::CmpIPredicate::ule;
-  case Fortran::common::RelationalOperator::EQ:
-    return mlir::arith::CmpIPredicate::eq;
-  case Fortran::common::RelationalOperator::NE:
-    return mlir::arith::CmpIPredicate::ne;
-  case Fortran::common::RelationalOperator::GT:
-    return mlir::arith::CmpIPredicate::ugt;
-  case Fortran::common::RelationalOperator::GE:
-    return mlir::arith::CmpIPredicate::uge;
-  }
-  llvm_unreachable("unhandled UNSIGNED relational operator");
-}
-
-/// Convert parser's REAL relational operators to MLIR.
-/// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018
-/// requirements in the IEEE context (table 17.1 of F2018). This choice is
-/// also applied in other contexts because it is easier and in line with
-/// other Fortran compilers.
-/// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not
-/// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee
-/// whether the comparison will signal or not in case of quiet NaN argument.
-static mlir::arith::CmpFPredicate
-translateFloatRelational(Fortran::common::RelationalOperator rop) {
-  switch (rop) {
-  case Fortran::common::RelationalOperator::LT:
-    return mlir::arith::CmpFPredicate::OLT;
-  case Fortran::common::RelationalOperator::LE:
-    return mlir::arith::CmpFPredicate::OLE;
-  case Fortran::common::RelationalOperator::EQ:
-    return mlir::arith::CmpFPredicate::OEQ;
-  case Fortran::common::RelationalOperator::NE:
-    return mlir::arith::CmpFPredicate::UNE;
-  case Fortran::common::RelationalOperator::GT:
-    return mlir::arith::CmpFPredicate::OGT;
-  case Fortran::common::RelationalOperator::GE:
-    return mlir::arith::CmpFPredicate::OGE;
-  }
-  llvm_unreachable("unhandled REAL relational operator");
-}
-
 template <int KIND>
 struct BinaryOp<Fortran::evaluate::Relational<
     Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> {
@@ -1247,7 +1201,8 @@ struct BinaryOp<Fortran::evaluate::Relational<
                                          const Op &op, hlfir::Entity lhs,
                                          hlfir::Entity rhs) {
     auto cmp = mlir::arith::CmpIOp::create(
-        builder, loc, translateSignedRelational(op.opr), lhs, rhs);
+        builder, loc, Fortran::lower::translateSignedRelational(op.opr), lhs,
+        rhs);
     return hlfir::EntityWithAttributes{cmp};
   }
 };
@@ -1269,7 +1224,8 @@ struct BinaryOp<Fortran::evaluate::Relational<
     mlir::Value lhsSL = builder.createConvert(loc, signlessType, lhs);
     mlir::Value rhsSL = builder.createConvert(loc, signlessType, rhs);
     auto cmp = mlir::arith::CmpIOp::create(
-        builder, loc, translateUnsignedRelational(op.opr), lhsSL, rhsSL);
+        builder, loc, Fortran::lower::translateUnsignedRelational(op.opr),
+        lhsSL, rhsSL);
     return hlfir::EntityWithAttributes{cmp};
   }
 };
@@ -1284,7 +1240,8 @@ struct BinaryOp<Fortran::evaluate::Relational<
                                          const Op &op, hlfir::Entity lhs,
                                          hlfir::Entity rhs) {
     auto cmp = mlir::arith::CmpFOp::create(
-        builder, loc, translateFloatRelational(op.opr), lhs, rhs);
+        builder, loc, Fortran::lower::translateFloatRelational(op.opr), lhs,
+        rhs);
     return hlfir::EntityWithAttributes{cmp};
   }
 };
@@ -1298,8 +1255,9 @@ struct BinaryOp<Fortran::evaluate::Relational<
                                          fir::FirOpBuilder &builder,
                                          const Op &op, hlfir::Entity lhs,
                                          hlfir::Entity rhs) {
-    auto cmp = fir::CmpcOp::create(builder, loc,
-                                   translateFloatRelational(op.opr), lhs, rhs);
+    auto cmp = fir::CmpcOp::create(
+        builder, loc, Fortran::lower::translateFloatRelational(op.opr), lhs,
+        rhs);
     return hlfir::EntityWithAttributes{cmp};
   }
 };
diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index d2a5a978756fd..974fcd44e3b05 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -671,3 +671,69 @@ void Fortran::lower::ComponentReverseIterator::setCurrentType(
 using namespace Fortran::evaluate;
 using namespace Fortran::common;
 FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::TypeBuilder, )
+
+/// Convert parser's INTEGER relational operators to MLIR.
+mlir::arith::CmpIPredicate
+Fortran::lower::translateSignedRelational(RelationalOperator rop) {
+  switch (rop) {
+  case RelationalOperator::LT:
+    return mlir::arith::CmpIPredicate::slt;
+  case RelationalOperator::LE:
+    return mlir::arith::CmpIPredicate::sle;
+  case RelationalOperator::EQ:
+    return mlir::arith::CmpIPredicate::eq;
+  case RelationalOperator::NE:
+    return mlir::arith::CmpIPredicate::ne;
+  case RelationalOperator::GT:
+    return mlir::arith::CmpIPredicate::sgt;
+  case RelationalOperator::GE:
+    return mlir::arith::CmpIPredicate::sge;
+  }
+  llvm_unreachable("unhandled INTEGER relational operator");
+}
+
+mlir::arith::CmpIPredicate
+Fortran::lower::translateUnsignedRelational(RelationalOperator rop) {
+  switch (rop) {
+  case RelationalOperator::LT:
+    return mlir::arith::CmpIPredicate::ult;
+  case RelationalOperator::LE:
+    return mlir::arith::CmpIPredicate::ule;
+  case RelationalOperator::EQ:
+    return mlir::arith::CmpIPredicate::eq;
+  case RelationalOperator::NE:
+    return mlir::arith::CmpIPredicate::ne;
+  case RelationalOperator::GT:
+    return mlir::arith::CmpIPredicate::ugt;
+  case RelationalOperator::GE:
+    return mlir::arith::CmpIPredicate::uge;
+  }
+  llvm_unreachable("unhandled UNSIGNED relational operator");
+}
+
+/// Convert parser's REAL relational operators to MLIR.
+/// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018
+/// requirements in the IEEE context (table 17.1 of F2018). This choice is
+/// also applied in other contexts because it is easier and in line with
+/// other Fortran compilers.
+/// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not
+/// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee
+/// whether the comparison will signal or not in case of quiet NaN argument.
+mlir::arith::CmpFPredicate
+Fortran::lower::translateFloatRelational(RelationalOperator rop) {
+  switch (rop) {
+  case RelationalOperator::LT:
+    return mlir::arith::CmpFPredicate::OLT;
+  case RelationalOperator::LE:
+    return mlir::arith::CmpFPredicate::OLE;
+  case RelationalOperator::EQ:
+    return mlir::arith::CmpFPredicate::OEQ;
+  case RelationalOperator::NE:
+    return mlir::arith::CmpFPredicate::UNE;
+  case RelationalOperator::GT:
+    return mlir::arith::CmpFPredicate::OGT;
+  case RelationalOperator::GE:
+    return mlir::arith::CmpFPredicate::OGE;
+  }
+  llvm_unreachable("unhandled REAL relational operator");
+}
diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index f31de82fc2a5f..cbca2fc52b93f 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -13,6 +13,7 @@
 #include "flang/Evaluate/traverse.h"
 #include "flang/Evaluate/type.h"
 #include "flang/Lower/AbstractConverter.h"
+#include "flang/Lower/ConvertType.h"
 #include "flang/Lower/OpenMP/Clauses.h"
 #include "flang/Lower/PFTBuilder.h"
 #include "flang/Lower/StatementContext.h"
@@ -485,6 +486,25 @@ genAtomicOperation(lower::AbstractConverter &converter,
   }
 }
 
+/// Reverse a relational operator as if the operands were swapped.
+/// e.g. LT becomes GT, LE becomes GE. Symmetric operators (EQ, NE)
+/// are returned unchanged.
+static common::RelationalOperator reverseRelOp(common::RelationalOperator op) {
+  using RO = common::RelationalOperator;
+  switch (op) {
+  case RO::LT:
+    return RO::GT;
+  case RO::LE:
+    return RO::GE;
+  case RO::GT:
+    return RO::LT;
+  case RO::GE:
+    return RO::LE;
+  default:
+    return op;
+  }
+}
+
 void Fortran::lower::omp::lowerAtomic(
     AbstractConverter &converter, SymMap &symTable,
     semantics::SemanticsContext &semaCtx, pft::Evaluation &eval,
@@ -521,8 +541,128 @@ 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");
+    }
+
+    common::RelationalOperator relOpr = common::RelationalOperator::EQ;
+    std::optional<semantics::SomeExpr> expectedExprStorage;
+    bool isUnsigned = false;
+
+    if (const auto *rel =
+            evaluate::UnwrapExpr<evaluate::Relational<evaluate::SomeType>>(
+                *cond)) {
+      std::visit(
+          [&](const auto &relImpl) {
+            relOpr = relImpl.opr;
+            using Operand = typename std::decay_t<decltype(relImpl)>::Operand;
+            isUnsigned = Operand::category == common::TypeCategory::Unsigned;
+            auto leftExpr = evaluate::AsGenericExpr(
+                evaluate::Expr<Operand>{relImpl.left()});
+            auto rightExpr = evaluate::AsGenericExpr(
+                evaluate::Expr<Operand>{relImpl.right()});
+            if (evaluate::IsSameOrConvertOf(rightExpr, atom)) {
+              // e.g. e == x  (atom is on the right)
+              // left operand is expected value (e)
+              // reverse the operator so that the comparison becomes
+              // x <reversed-op> e.
+              expectedExprStorage = std::move(leftExpr);
+              relOpr = reverseRelOp(relOpr);
+            } else {
+              // Form: x == e  (atom is on the left, or default)
+              expectedExprStorage = std::move(rightExpr);
+            }
+          },
+          rel->u);
+    }
+    if (!expectedExprStorage) {
+      mlir::emitError(loc, "internal error: atomic compare condition is not a "
+                           "recognized relational expression");
+      return;
+    }
+
+    mlir::Type elemTypeOfX = fir::unwrapRefType(atomAddr.getType());
+    mlir::Value expectedVal = fir::getBase(
+        converter.genExprValue(*expectedExprStorage, stmtCtx, &loc));
+    if (expectedVal.getType() != elemTypeOfX) {
+      expectedVal = builder.createConvert(loc, elemTypeOfX, expectedVal);
+    }
+
+    mlir::UnitAttr weakAttr = nullptr;
+    mlir::Operation *atomicOp = mlir::omp::AtomicCompareOp::create(
+        builder, loc, atomAddr, weakAttr, hint,
+        makeMemOrderAttr(converter, memOrder));
+    mlir::Block *block = builder.createBlock(&atomicOp->getRegion(0));
+    mlir::Value blockArg = block->addArgument(elemTypeOfX, loc);
+    builder.setInsertionPointToEnd(block);
+
+    // Generate comparison: e.g. x == e
+    mlir::Value cmpResult;
+    if (mlir::isa<mlir::IntegerType>(elemTypeOfX)) {
+      auto pred = isUnsigned ? lower::translateUnsignedRelational(relOpr)
+                             : lower::translateSignedRelational(relOpr);
+      cmpResult = mlir::arith::CmpIOp::create(builder, loc, pred, blockArg,
+                                              expectedVal);
+    } else if (mlir::isa<mlir::FloatType>(elemTypeOfX)) {
+      auto pred = lower::translateFloatRelational(relOpr);
+      cmpResult = mlir::arith::CmpFOp::create(builder, loc, pred, blockArg,
+                                              expectedVal);
+    } else if (fir::isa_complex(elemTypeOfX)) {
+      auto pred = lower::translateFloatRelational(relOpr);
+      cmpResult =
+          fir::CmpcOp::create(builder, loc, pred, blockArg, expectedVal);
+    } else {
+      mlir::emitError(loc, "unsupported type for atomic compare");
+      return;
+    }
+
+    // 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..247f79d243c83
--- /dev/null
+++ b/flang/test/Integration/OpenMP/atomic-compare.f90
@@ -0,0 +1,250 @@
+!===----------------------------------------------------------------------===!
+! 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.
+!===----------------------------------------------------------------------===!
+
+!REQUIRES: x86-registered-target
+!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 max (signed)
+!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 max 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 max seq_cst + flush (signed)
+!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 max 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 max acquire (signed)
+!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
+subroutine atomic_compare_lt_acquire(x, e)
+  integer :: x, e
+  !$omp atomic compare acquire
+  if (x < e) x = e
+end
+
+! Greater-than comparison → atomicrmw min (signed)
+!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 min ptr %[[X]], i32 %[[EVAL]] monotonic
+subroutine atomic_compare_gt(x, e)
+  integer :: x, e
+  !$omp atomic compare
+  if (x > e) x = e
+end
+
+! Real "==" → NaN gua...
[truncated]

``````````

</details>


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


More information about the flang-commits mailing list