[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 08:01:01 PDT 2026
https://github.com/VeeEM updated https://github.com/llvm/llvm-project/pull/215654
>From 313ef3865894daa7e63324632226fbddce2d672d 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 | 39 +---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 8 +
mlir/test/Target/LLVMIR/openmp-llvm.mlir | 216 +++++++++++-------
5 files changed, 171 insertions(+), 128 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..8e42e624613c4 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -4103,7 +4103,7 @@ 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 +4124,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..5f5732b742a93 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -1852,16 +1852,14 @@ 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
+// 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):
@@ -1999,19 +1997,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 +2193,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 +2205,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 +2217,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 +2229,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 +2241,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 +2253,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 +2265,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 +2468,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 +2480,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 +2492,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 +2504,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 +2516,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 +2527,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 +2538,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 +2598,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