[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
Tue Aug 11 13:46:12 PDT 2026
https://github.com/VeeEM updated https://github.com/llvm/llvm-project/pull/215654
>From 765f050069db77ad7ff9f31f791ab4bdb0c784e6 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 +++++++++---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 8 +++
mlir/test/Target/LLVMIR/openmp-llvm.mlir | 53 +++++++------------
4 files changed, 53 insertions(+), 44 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/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..42df31ea28a4b 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -1852,16 +1852,19 @@ llvm.func @atomic_update_float_multi_step(%x: !llvm.ptr, %a: f32, %b: f32) {
// -----
+// TODO: Maybe add a test here with different op
// Non-struct types with BAD_BINOP (unrecognized) ops still
// use the cmpxchg fallback path.
//
// CHECK-LABEL: @atomic_update_float_intrinsic
// CHECK-SAME: (ptr %[[x:.*]], float %[[expr:.*]])
-// 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: cmpxchg ptr %[[x]], i32 %[[phi]], i32 %{{.*}} monotonic monotonic
+// CHCK: %[[load:.*]] = load atomic i32, ptr %[[x]] monotonic
+// CHCK: %[[phi:.*]] = phi i32
+// CHCK: %[[fltCast:.*]] = bitcast i32 %[[phi]] to float
+// CHCK: %[[res:.*]] = call float @llvm.maxnum.f32(float %[[fltCast]], float %[[expr]])
+// CHCK: cmpxchg ptr %[[x]], i32 %[[phi]], i32 %{{.*}} monotonic monotonic
+ // CHECK: %[[res:.*]] = atomicrmw fmax ptr %[[x]], float %[[expr]] monotonic
+ // CHECK-NEXT: %[[newval:.*]] = call float @llvm.maxnum.f32(float %[[res]], float %[[expr]])
llvm.func @atomic_update_float_intrinsic(%x: !llvm.ptr, %expr: f32) {
omp.atomic.update %x : !llvm.ptr {
^bb0(%xval: f32):
@@ -2259,11 +2262,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 +2274,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 {
@@ -2504,13 +2501,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 +2512,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 {
@@ -2552,12 +2539,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