[flang-commits] [flang] [llvm] [mlir] [openmp][mlir] Expand use of atomicrmw for atomic update (PR #215654)

Ville-Markus Yli-Suutala via flang-commits flang-commits at lists.llvm.org
Thu Aug 13 10:46:25 PDT 2026


https://github.com/VeeEM updated https://github.com/llvm/llvm-project/pull/215654

>From 69950d6eb49ae382c825bbd2331b296a09c429d8 Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Sun, 9 Aug 2026 13:42:43 +0300
Subject: [PATCH] [openmp][mlir] Expand use of atomicrmw for atomic update

Use atomicrmw for single and double precision floats in the following
operations:

- fadd
- fsub
- smax
- smin
- umax
- umin
- fmax
- fmin
- fmaximum
- fminimum
---
 .../OpenMP/atomic-capture-release.f90         |   2 +-
 llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp     |  34 ++-
 .../Frontend/OpenMPIRBuilderTest.cpp          |  40 +---
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      |   8 +
 mlir/test/Target/LLVMIR/openmp-llvm.mlir      | 212 +++++++++++-------
 5 files changed, 171 insertions(+), 125 deletions(-)

diff --git a/flang/test/Integration/OpenMP/atomic-capture-release.f90 b/flang/test/Integration/OpenMP/atomic-capture-release.f90
index d0090f7e6ee02..2a3c074539d15 100644
--- a/flang/test/Integration/OpenMP/atomic-capture-release.f90
+++ b/flang/test/Integration/OpenMP/atomic-capture-release.f90
@@ -24,7 +24,7 @@ subroutine test_capture_release(a,b,c)
   real(4) :: a, b, c
   !$omp atomic capture release
   c = a
-  a = a + b
+  a = a * b
   !$omp end atomic
 end subroutine
 
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index a227397b06f4e..c994d5ffef00c 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -11105,9 +11105,6 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createAtomicUpdate(
     assert((XElemTy->isFloatingPointTy() || XElemTy->isIntegerTy() ||
             XElemTy->isPointerTy() || XElemTy->isStructTy()) &&
            "OMP atomic update expected a scalar or struct type");
-    assert((RMWOp != AtomicRMWInst::Max) && (RMWOp != AtomicRMWInst::Min) &&
-           (RMWOp != AtomicRMWInst::UMax) && (RMWOp != AtomicRMWInst::UMin) &&
-           "OpenMP atomic does not support LT or GT operations");
   });
 
   Expected<std::pair<Value *, Value *>> AtomicResult = emitAtomicUpdate(
@@ -11135,18 +11132,28 @@ Value *OpenMPIRBuilder::emitRMWOpAsInstruction(Value *Src1, Value *Src2,
     return Builder.CreateOr(Src1, Src2);
   case AtomicRMWInst::Xor:
     return Builder.CreateXor(Src1, Src2);
-  case AtomicRMWInst::Xchg:
-  case AtomicRMWInst::FAdd:
-  case AtomicRMWInst::FSub:
-  case AtomicRMWInst::BAD_BINOP:
   case AtomicRMWInst::Max:
+    return Builder.CreateBinaryIntrinsic(Intrinsic::smax, Src1, Src2);
   case AtomicRMWInst::Min:
+    return Builder.CreateBinaryIntrinsic(Intrinsic::smin, Src1, Src2);
   case AtomicRMWInst::UMax:
+    return Builder.CreateBinaryIntrinsic(Intrinsic::umax, Src1, Src2);
   case AtomicRMWInst::UMin:
+    return Builder.CreateBinaryIntrinsic(Intrinsic::umin, Src1, Src2);
+  case AtomicRMWInst::FAdd:
+    return Builder.CreateFAdd(Src1, Src2);
+  case AtomicRMWInst::FSub:
+    return Builder.CreateFSub(Src1, Src2);
   case AtomicRMWInst::FMax:
+    return Builder.CreateMaxNum(Src1, Src2);
   case AtomicRMWInst::FMin:
+    return Builder.CreateMinNum(Src1, Src2);
   case AtomicRMWInst::FMaximum:
+    return Builder.CreateMaximum(Src1, Src2);
   case AtomicRMWInst::FMinimum:
+    return Builder.CreateMinimum(Src1, Src2);
+  case AtomicRMWInst::Xchg:
+  case AtomicRMWInst::BAD_BINOP:
   case AtomicRMWInst::FMaximumNum:
   case AtomicRMWInst::FMinimumNum:
   case AtomicRMWInst::UIncWrap:
@@ -11187,15 +11194,26 @@ Expected<std::pair<Value *, Value *>> OpenMPIRBuilder::emitAtomicUpdate(
   case AtomicRMWInst::Or:
   case AtomicRMWInst::Xor:
   case AtomicRMWInst::Xchg:
+  case AtomicRMWInst::Max:
+  case AtomicRMWInst::Min:
+  case AtomicRMWInst::UMax:
+  case AtomicRMWInst::UMin:
+  case AtomicRMWInst::FAdd:
+  case AtomicRMWInst::FMax:
+  case AtomicRMWInst::FMin:
+  case AtomicRMWInst::FMaximum:
+  case AtomicRMWInst::FMinimum:
     emitRMWOp = XElemTy;
     break;
   case AtomicRMWInst::Sub:
+  case AtomicRMWInst::FSub:
     emitRMWOp = (IsXBinopExpr && XElemTy);
     break;
   default:
     emitRMWOp = false;
   }
-  emitRMWOp &= XElemTy->isIntegerTy();
+  emitRMWOp &=
+      (XElemTy->isIntegerTy() || XElemTy->isFloatTy() || XElemTy->isDoubleTy());
 
   std::pair<Value *, Value *> Res;
   if (emitRMWOp) {
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index b96103c82c185..6c947d71dc3c9 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -4103,7 +4103,8 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateIntr) {
   Type *IntTy = Type::getInt32Ty(M->getContext());
   AllocaInst *XVal = Builder.CreateAlloca(IntTy);
   XVal->setName("AtomicVar");
-  Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0), XVal);
+  StoreInst *Init =
+      Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0), XVal);
   OpenMPIRBuilder::AtomicOpValue X = {XVal, IntTy, false, false};
   AtomicOrdering AO = AtomicOrdering::Monotonic;
   Constant *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1);
@@ -4124,37 +4125,12 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateIntr) {
                        OMPBuilder.createAtomicUpdate(Builder, AllocaIP, X, Expr,
                                                      AO, RMWOp, UpdateOp,
                                                      IsXLHSInRHSPart));
-  Builder.restoreIP(AfterIP);
-  BasicBlock *ContBB = EntryBB->getSingleSuccessor();
-  CondBrInst *ContTI = dyn_cast<CondBrInst>(ContBB->getTerminator());
-  EXPECT_NE(ContTI, nullptr);
-  BasicBlock *EndBB = ContTI->getSuccessor(0);
-  EXPECT_EQ(ContTI->getSuccessor(1), ContBB);
-  EXPECT_NE(EndBB, nullptr);
-
-  PHINode *Phi = dyn_cast<PHINode>(&ContBB->front());
-  EXPECT_NE(Phi, nullptr);
-  EXPECT_EQ(Phi->getNumIncomingValues(), 2U);
-  EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB);
-  EXPECT_EQ(Phi->getIncomingBlock(1), ContBB);
-
-  EXPECT_TRUE(Sub->hasOneUse());
-  StoreInst *St = dyn_cast<StoreInst>(Sub->user_back());
-  AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand());
-
-  ExtractValueInst *ExVI1 =
-      dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB));
-  EXPECT_NE(ExVI1, nullptr);
-  AtomicCmpXchgInst *CmpExchg =
-      dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand());
-  EXPECT_NE(CmpExchg, nullptr);
-  EXPECT_EQ(CmpExchg->getPointerOperand(), XVal);
-  EXPECT_EQ(CmpExchg->getCompareOperand(), Phi);
-  EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic);
-
-  LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand());
-  EXPECT_NE(Ld, nullptr);
-  EXPECT_EQ(UpdateTemp, Ld->getPointerOperand());
+  EXPECT_EQ(EntryBB->getParent()->size(), 1U);
+  AtomicRMWInst *ARWM = dyn_cast<AtomicRMWInst>(Init->getNextNode());
+  EXPECT_NE(ARWM, nullptr);
+  EXPECT_EQ(ARWM->getPointerOperand(), XVal);
+  EXPECT_EQ(ARWM->getOperation(), RMWOp);
+  EXPECT_EQ(ARWM->getValOperand(), Expr);
 
   Builder.CreateRetVoid();
   OMPBuilder.finalize();
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 1c50ff192c3d5..de8e852ba194f 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -5568,10 +5568,18 @@ static llvm::AtomicRMWInst::BinOp convertBinOpToAtomic(Operation &op) {
       .Case([&](LLVM::AndOp) { return llvm::AtomicRMWInst::BinOp::And; })
       .Case([&](LLVM::OrOp) { return llvm::AtomicRMWInst::BinOp::Or; })
       .Case([&](LLVM::XOrOp) { return llvm::AtomicRMWInst::BinOp::Xor; })
+      .Case([&](LLVM::SMaxOp) { return llvm::AtomicRMWInst::BinOp::Max; })
+      .Case([&](LLVM::SMinOp) { return llvm::AtomicRMWInst::BinOp::Min; })
       .Case([&](LLVM::UMaxOp) { return llvm::AtomicRMWInst::BinOp::UMax; })
       .Case([&](LLVM::UMinOp) { return llvm::AtomicRMWInst::BinOp::UMin; })
       .Case([&](LLVM::FAddOp) { return llvm::AtomicRMWInst::BinOp::FAdd; })
       .Case([&](LLVM::FSubOp) { return llvm::AtomicRMWInst::BinOp::FSub; })
+      .Case([&](LLVM::MaxNumOp) { return llvm::AtomicRMWInst::BinOp::FMax; })
+      .Case([&](LLVM::MinNumOp) { return llvm::AtomicRMWInst::BinOp::FMin; })
+      .Case(
+          [&](LLVM::MaximumOp) { return llvm::AtomicRMWInst::BinOp::FMaximum; })
+      .Case(
+          [&](LLVM::MinimumOp) { return llvm::AtomicRMWInst::BinOp::FMinimum; })
       .Default(llvm::AtomicRMWInst::BinOp::BAD_BINOP);
 }
 
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index e867dd8afcb9b..b075484eec63c 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -1860,12 +1860,12 @@ llvm.func @atomic_update_float_multi_step(%x: !llvm.ptr, %a: f32, %b: f32) {
 // CHECK: %[[load:.*]] = load atomic i32, ptr %[[x]] monotonic
 // CHECK: %[[phi:.*]] = phi i32
 // CHECK: %[[fltCast:.*]] = bitcast i32 %[[phi]] to float
-// CHECK: %[[res:.*]] = call float @llvm.maxnum.f32(float %[[fltCast]], float %[[expr]])
+// CHECK: %[[res:.*]] = call float @llvm.fmuladd.f32(float %[[fltCast]], float %[[expr]], float %[[expr]])
 // CHECK: cmpxchg ptr %[[x]], i32 %[[phi]], i32 %{{.*}} monotonic monotonic
 llvm.func @atomic_update_float_intrinsic(%x: !llvm.ptr, %expr: f32) {
   omp.atomic.update %x : !llvm.ptr {
   ^bb0(%xval: f32):
-    %newval = "llvm.intr.maxnum"(%xval, %expr) : (f32, f32) -> f32
+    %newval = "llvm.intr.fmuladd"(%xval, %expr, %expr) : (f32, f32, f32) -> f32
     omp.yield(%newval : f32)
   }
   llvm.return
@@ -1999,19 +1999,15 @@ llvm.func @omp_atomic_update_ordering(%x:!llvm.ptr, %expr: i32) {
 // CHECK-LABEL: @omp_atomic_update_intrinsic
 // CHECK-SAME: (ptr %[[x:.*]], i32 %[[expr:.*]])
 llvm.func @omp_atomic_update_intrinsic(%x:!llvm.ptr, %expr: i32) {
-  // CHECK: %[[t1:.*]] = call i32 @llvm.smax.i32(i32 %[[x_old:.*]], i32 %[[expr]])
-  // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
-  // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
-  // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
+  // CHECK: %[[res:.*]] = atomicrmw max ptr %[[x]], i32 %[[expr]]
+  // CHECK: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[res]], i32 %[[expr]])
   omp.atomic.update %x : !llvm.ptr {
   ^bb0(%xval: i32):
     %newval = "llvm.intr.smax"(%xval, %expr) : (i32, i32) -> i32
     omp.yield(%newval : i32)
   }
-  // CHECK: %[[t1:.*]] = call i32 @llvm.umax.i32(i32 %[[x_old:.*]], i32 %[[expr]])
-  // CHECK: store i32 %[[t1]], ptr %[[x_new:.*]]
-  // CHECK: %[[t2:.*]] = load i32, ptr %[[x_new]]
-  // CHECK: cmpxchg ptr %[[x]], i32 %[[x_old]], i32 %[[t2]]
+  // CHECK: %[[res:.*]] = atomicrmw umax ptr %[[x]], i32 %[[expr]]
+  // CHECK: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[res]], i32 %[[expr]])
   omp.atomic.update %x : !llvm.ptr {
   ^bb0(%xval: i32):
     %newval = "llvm.intr.umax"(%xval, %expr) : (i32, i32) -> i32
@@ -2199,11 +2195,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw max ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[res]], i32 %[[expr]])
   // CHECK: store i32 %[[newval]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.update %x : !llvm.ptr {
@@ -2214,11 +2207,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw min ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[res]], i32 %[[expr]])
   // CHECK: store i32 %[[newval]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.update %x : !llvm.ptr {
@@ -2229,11 +2219,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw umax ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[res]], i32 %[[expr]])
   // CHECK: store i32 %[[newval]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.update %x : !llvm.ptr {
@@ -2244,11 +2231,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw umin ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[res]], i32 %[[expr]])
   // CHECK: store i32 %[[newval]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.update %x : !llvm.ptr {
@@ -2259,11 +2243,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK: %[[newval:.*]] = fadd float %{{.*}}, %[[exprf]]
-  // CHECK: store float %[[newval]], ptr %{{.*}}
-  // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw fadd ptr %[[xf]], float %[[exprf]] monotonic
+  // CHECK-NEXT: %[[newval:.*]] = fadd float %[[res]], %[[exprf]]
   // CHECK: store float %[[newval]], ptr %[[vf]]
   omp.atomic.capture {
     omp.atomic.update %xf : !llvm.ptr {
@@ -2274,11 +2255,8 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK: %[[newval:.*]] = fsub float %{{.*}}, %[[exprf]]
-  // CHECK: store float %[[newval]], ptr %{{.*}}
-  // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
+  // CHECK: %[[res:.*]] = atomicrmw fsub ptr %[[xf]], float %[[exprf]] monotonic
+  // CHECK-NEXT: %[[newval:.*]] = fsub float %[[res]], %[[exprf]]
   // CHECK: store float %[[newval]], ptr %[[vf]]
   omp.atomic.capture {
     omp.atomic.update %xf : !llvm.ptr {
@@ -2289,6 +2267,54 @@ llvm.func @omp_atomic_capture_prefix_update(
     omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
   }
 
+  // CHECK: %[[res:.*]] = atomicrmw fmax ptr %[[xf]], float %[[exprf]]
+  // CHECK-NEXT: %[[newval:.*]] = call float @llvm.maxnum.f32(float %[[res]], float %[[exprf]])
+  // CHECK: store float %[[newval]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.maxnum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fmin ptr %[[xf]], float %[[exprf]]
+  // CHECK-NEXT: %[[newval:.*]] = call float @llvm.minnum.f32(float %[[res]], float %[[exprf]])
+  // CHECK: store float %[[newval]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.minnum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fmaximum ptr %[[xf]], float %[[exprf]]
+  // CHECK-NEXT: %[[newval:.*]] = call float @llvm.maximum.f32(float %[[res]], float %[[exprf]])
+  // CHECK: store float %[[newval]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.maximum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fminimum ptr %[[xf]], float %[[exprf]]
+  // CHECK-NEXT: %[[newval:.*]] = call float @llvm.minimum.f32(float %[[res]], float %[[exprf]])
+  // CHECK: store float %[[newval]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.minimum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+  }
+
   llvm.return
 }
 
@@ -2444,12 +2470,9 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store i32 %[[xval]], ptr %[[v]]
+  // CHECK: %[[res:.*]] = atomicrmw max ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smax.i32(i32 %[[res]], i32 %[[expr]])
+  // CHECK: store i32 %[[res]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
     omp.atomic.update %x : !llvm.ptr {
@@ -2459,12 +2482,9 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store i32 %[[xval]], ptr %[[v]]
+  // CHECK: %[[res:.*]] = atomicrmw min ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.smin.i32(i32 %[[res]], i32 %[[expr]])
+  // CHECK: store i32 %[[res]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
     omp.atomic.update %x : !llvm.ptr {
@@ -2474,12 +2494,9 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store i32 %[[xval]], ptr %[[v]]
+  // CHECK: %[[res:.*]] = atomicrmw umax ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umax.i32(i32 %[[res]], i32 %[[expr]])
+  // CHECK: store i32 %[[res]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
     omp.atomic.update %x : !llvm.ptr {
@@ -2489,12 +2506,9 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[xval]], i32 %[[expr]])
-  // CHECK-NEXT: store i32 %[[newval]], ptr %{{.*}}
-  // CHECK-NEXT: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK-NEXT: %{{.*}} = cmpxchg ptr %[[x]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store i32 %[[xval]], ptr %[[v]]
+  // CHECK: %[[res:.*]] = atomicrmw umin ptr %[[x]], i32 %[[expr]]
+  // CHECK-NEXT: %[[newval:.*]] = call i32 @llvm.umin.i32(i32 %[[res]], i32 %[[expr]])
+  // CHECK: store i32 %[[res]], ptr %[[v]]
   omp.atomic.capture {
     omp.atomic.read %v = %x : !llvm.ptr, !llvm.ptr, i32
     omp.atomic.update %x : !llvm.ptr {
@@ -2504,13 +2518,8 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
-  // CHECK: %[[newval:.*]] = fadd float %{{.*}}, %[[exprf]]
-  // CHECK: store float %[[newval]], ptr %{{.*}}
-  // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store float %[[xvalf]], ptr %[[vf]]
+  // CHECK: %[[res:.*]] = atomicrmw fadd ptr %[[xf]], float %[[exprf]] monotonic
+  // CHECK: store float %[[res]], ptr %[[vf]]
   omp.atomic.capture {
     omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
     omp.atomic.update %xf : !llvm.ptr {
@@ -2520,13 +2529,8 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
-  // CHECK: %[[newval:.*]] = fsub float %{{.*}}, %[[exprf]]
-  // CHECK: store float %[[newval]], ptr %{{.*}}
-  // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store float %[[xvalf]], ptr %[[vf]]
+  // CHECK: %[[res:.*]] = atomicrmw fsub ptr %[[xf]], float %[[exprf]] monotonic
+  // CHECK: store float %[[res]], ptr %[[vf]]
   omp.atomic.capture {
     omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
     omp.atomic.update %xf : !llvm.ptr {
@@ -2536,6 +2540,50 @@ llvm.func @omp_atomic_capture_postfix_update(
     }
   }
 
+  // CHECK: %[[res:.*]] = atomicrmw fmax ptr %[[xf]], float %[[exprf]]
+  // CHECK: store float %[[res]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.maxnum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fmin ptr %[[xf]], float %[[exprf]]
+  // CHECK: store float %[[res]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.minnum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fmaximum ptr %[[xf]], float %[[exprf]]
+  // CHECK: store float %[[res]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.maximum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+  }
+
+  // CHECK: %[[res:.*]] = atomicrmw fminimum ptr %[[xf]], float %[[exprf]]
+  // CHECK: store float %[[res]], ptr %[[vf]]
+  omp.atomic.capture {
+    omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
+    omp.atomic.update %xf : !llvm.ptr {
+    ^bb0(%xval: f32):
+      %newval = "llvm.intr.minimum"(%xval, %exprf) : (f32, f32) -> f32
+      omp.yield(%newval : f32)
+    }
+  }
+
   llvm.return
 }
 
@@ -2552,12 +2600,8 @@ llvm.func @omp_atomic_capture_misc(
     omp.atomic.write %x = %expr : !llvm.ptr, i32
   }
 
-  // CHECK: %[[xval:.*]] = phi i32
-  // CHECK: %[[xvalf:.*]] = bitcast i32 %[[xval]] to float
-  // CHECK: store float %[[exprf]], ptr %{{.*}}
-  // CHECK: %[[newval_:.*]] = load i32, ptr %{{.*}}
-  // CHECK: %{{.*}} = cmpxchg ptr %[[xf]], i32 %[[xval]], i32 %[[newval_]] monotonic monotonic
-  // CHECK: store float %[[xvalf]], ptr %[[vf]]
+  // CHECK: %[[xval:.*]] = atomicrmw xchg ptr %[[xf]], float %[[exprf]] monotonic
+  // CHECK: store float %[[xval]], ptr %[[vf]]
   omp.atomic.capture{
     omp.atomic.read %vf = %xf : !llvm.ptr, !llvm.ptr, f32
     omp.atomic.write %xf = %exprf : !llvm.ptr, f32



More information about the flang-commits mailing list