https://github.com/gonzalobg updated 
https://github.com/llvm/llvm-project/pull/187139

>From b5d0171ad5afd677825bb8c8e4f25b1dca108a9a Mon Sep 17 00:00:00 2001
From: Gonzalo Brito Gadeschi <[email protected]>
Date: Tue, 17 Mar 2026 15:24:47 -0700
Subject: [PATCH] [clang] builtins for atomicrmw fminmax/_num

---
 clang/include/clang/Basic/Builtins.td         |  96 ++++++++++++++
 clang/lib/AST/Expr.cpp                        |  16 +++
 clang/lib/CodeGen/CGAtomic.cpp                | 117 +++++++++++++++++-
 clang/lib/Sema/SemaChecking.cpp               |  16 +++
 .../AArch64/atomic-ops-float-check-minmax.c   |  59 +++++++++
 clang/test/Sema/atomic-ops.c                  |  76 ++++++++++++
 clang/test/Sema/scoped-atomic-ops.c           |  32 +++++
 7 files changed, 408 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index a1c99ccba7676..ea4b0cee32213 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2139,6 +2139,30 @@ def AtomicMinFetch : AtomicBuiltin {
   let Prototype = "void(...)";
 }
 
+def AtomicFMinimumFetch : AtomicBuiltin {
+  let Spellings = ["__atomic_fminimum_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFMaximumFetch : AtomicBuiltin {
+  let Spellings = ["__atomic_fmaximum_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFMinimumNumFetch : AtomicBuiltin {
+  let Spellings = ["__atomic_fminimum_num_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFMaximumNumFetch : AtomicBuiltin {
+  let Spellings = ["__atomic_fmaximum_num_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def AtomicNandFetch : AtomicBuiltin {
   let Spellings = ["__atomic_nand_fetch"];
   let Attributes = [CustomTypeChecking];
@@ -2284,6 +2308,30 @@ def ScopedAtomicFetchMax : AtomicBuiltin {
   let Prototype = "void(...)";
 }
 
+def ScopedAtomicFetchFMinimum : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fetch_fminimum"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFetchFMaximum : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fetch_fmaximum"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFetchFMinimumNum : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fetch_fminimum_num"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFetchFMaximumNum : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fetch_fmaximum_num"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def ScopedAtomicAddFetch : AtomicBuiltin {
   let Spellings = ["__scoped_atomic_add_fetch"];
   let Attributes = [CustomTypeChecking];
@@ -2332,6 +2380,30 @@ def ScopedAtomicMaxFetch : AtomicBuiltin {
   let Prototype = "void(...)";
 }
 
+def ScopedAtomicFMinimumFetch : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fminimum_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFMaximumFetch : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fmaximum_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFMinimumNumFetch : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fminimum_num_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def ScopedAtomicFMaximumNumFetch : AtomicBuiltin {
+  let Spellings = ["__scoped_atomic_fmaximum_num_fetch"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def ScopedAtomicUInc : AtomicBuiltin {
   let Spellings = ["__scoped_atomic_fetch_uinc"];
   let Attributes = [CustomTypeChecking];
@@ -2436,6 +2508,30 @@ def AtomicFetchMin : AtomicBuiltin {
   let Prototype = "void(...)";
 }
 
+def AtomicFetchFMinimum : AtomicBuiltin {
+  let Spellings = ["__atomic_fetch_fminimum"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFetchFMaximum : AtomicBuiltin {
+  let Spellings = ["__atomic_fetch_fmaximum"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFetchFMinimumNum : AtomicBuiltin {
+  let Spellings = ["__atomic_fetch_fminimum_num"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
+def AtomicFetchFMaximumNum : AtomicBuiltin {
+  let Spellings = ["__atomic_fetch_fmaximum_num"];
+  let Attributes = [CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def AtomicFetchUInc : AtomicBuiltin {
   let Spellings = ["__atomic_fetch_uinc"];
   let Attributes = [CustomTypeChecking];
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 185e887fb05c3..f05d4c6a495ac 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -5288,8 +5288,16 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
   case AO__atomic_nand_fetch:
   case AO__atomic_min_fetch:
   case AO__atomic_max_fetch:
+  case AO__atomic_fminimum_fetch:
+  case AO__atomic_fmaximum_fetch:
+  case AO__atomic_fminimum_num_fetch:
+  case AO__atomic_fmaximum_num_fetch:
   case AO__atomic_fetch_min:
   case AO__atomic_fetch_max:
+  case AO__atomic_fetch_fminimum:
+  case AO__atomic_fetch_fmaximum:
+  case AO__atomic_fetch_fminimum_num:
+  case AO__atomic_fetch_fmaximum_num:
   case AO__atomic_fetch_uinc:
   case AO__atomic_fetch_udec:
     return 3;
@@ -5311,8 +5319,16 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
   case AO__scoped_atomic_nand_fetch:
   case AO__scoped_atomic_min_fetch:
   case AO__scoped_atomic_max_fetch:
+  case AO__scoped_atomic_fminimum_fetch:
+  case AO__scoped_atomic_fmaximum_fetch:
+  case AO__scoped_atomic_fminimum_num_fetch:
+  case AO__scoped_atomic_fmaximum_num_fetch:
   case AO__scoped_atomic_fetch_min:
   case AO__scoped_atomic_fetch_max:
+  case AO__scoped_atomic_fetch_fminimum:
+  case AO__scoped_atomic_fetch_fmaximum:
+  case AO__scoped_atomic_fetch_fminimum_num:
+  case AO__scoped_atomic_fetch_fmaximum_num:
   case AO__scoped_atomic_exchange_n:
   case AO__scoped_atomic_fetch_uinc:
   case AO__scoped_atomic_fetch_udec:
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 859ab20bb6740..4a4db3039fac8 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -530,10 +530,27 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy 
&Builder,
   const bool IsFP = OldVal->getType()->isFloatingPointTy();
 
   if (IsFP) {
-    llvm::Intrinsic::ID IID = (Op == AtomicExpr::AO__atomic_max_fetch ||
-                               Op == AtomicExpr::AO__scoped_atomic_max_fetch)
-                                  ? llvm::Intrinsic::maxnum
-                                  : llvm::Intrinsic::minnum;
+    llvm::Intrinsic::ID IID;
+    if (Op == AtomicExpr::AO__atomic_max_fetch ||
+        Op == AtomicExpr::AO__scoped_atomic_max_fetch)
+      IID = llvm::Intrinsic::maxnum;
+    else if (Op == AtomicExpr::AO__atomic_min_fetch ||
+             Op == AtomicExpr::AO__scoped_atomic_min_fetch)
+      IID = llvm::Intrinsic::minnum;
+    else if (Op == AtomicExpr::AO__atomic_fmaximum_fetch ||
+             Op == AtomicExpr::AO__scoped_atomic_fmaximum_fetch)
+      IID = llvm::Intrinsic::maximum;
+    else if (Op == AtomicExpr::AO__atomic_fminimum_fetch ||
+             Op == AtomicExpr::AO__scoped_atomic_fminimum_fetch)
+      IID = llvm::Intrinsic::minimum;
+    else if (Op == AtomicExpr::AO__atomic_fmaximum_num_fetch ||
+             Op == AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch)
+      IID = llvm::Intrinsic::maximumnum;
+    else if (Op == AtomicExpr::AO__atomic_fminimum_num_fetch ||
+             Op == AtomicExpr::AO__scoped_atomic_fminimum_num_fetch)
+      IID = llvm::Intrinsic::minimumnum;
+    else
+      llvm_unreachable("Unexpected atomic FP min/max operation");
 
     return Builder.CreateBinaryIntrinsic(IID, OldVal, RHS, llvm::FMFSource(),
                                          "newval");
@@ -545,10 +562,18 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy 
&Builder,
     llvm_unreachable("Unexpected min/max operation");
   case AtomicExpr::AO__atomic_max_fetch:
   case AtomicExpr::AO__scoped_atomic_max_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
     Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT;
     break;
   case AtomicExpr::AO__atomic_min_fetch:
   case AtomicExpr::AO__scoped_atomic_min_fetch:
+  case AtomicExpr::AO__atomic_fminimum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+  case AtomicExpr::AO__atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
     Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT;
     break;
   }
@@ -705,6 +730,28 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr 
*E, Address Dest,
                     : llvm::AtomicRMWInst::UMin);
     break;
 
+  case AtomicExpr::AO__atomic_fminimum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+    PostOpMinMax = true;
+    [[fallthrough]];
+  case AtomicExpr::AO__atomic_fetch_fminimum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
+    assert(E->getValueType()->isFloatingType() &&
+           "fminimum operations only support floating-point types");
+    Op = llvm::AtomicRMWInst::FMinimum;
+    break;
+
+  case AtomicExpr::AO__atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
+    PostOpMinMax = true;
+    [[fallthrough]];
+  case AtomicExpr::AO__atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
+    assert(E->getValueType()->isFloatingType() &&
+           "fminimum_num operations only support floating-point types");
+    Op = llvm::AtomicRMWInst::FMinimumNum;
+    break;
+
   case AtomicExpr::AO__atomic_max_fetch:
   case AtomicExpr::AO__scoped_atomic_max_fetch:
     PostOpMinMax = true;
@@ -721,6 +768,28 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr 
*E, Address Dest,
                     : llvm::AtomicRMWInst::UMax);
     break;
 
+  case AtomicExpr::AO__atomic_fmaximum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+    PostOpMinMax = true;
+    [[fallthrough]];
+  case AtomicExpr::AO__atomic_fetch_fmaximum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
+    assert(E->getValueType()->isFloatingType() &&
+           "fmaximum operations only support floating-point types");
+    Op = llvm::AtomicRMWInst::FMaximum;
+    break;
+
+  case AtomicExpr::AO__atomic_fmaximum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
+    PostOpMinMax = true;
+    [[fallthrough]];
+  case AtomicExpr::AO__atomic_fetch_fmaximum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
+    assert(E->getValueType()->isFloatingType() &&
+           "fmaximum_num operations only support floating-point types");
+    Op = llvm::AtomicRMWInst::FMaximumNum;
+    break;
+
   case AtomicExpr::AO__atomic_and_fetch:
   case AtomicExpr::AO__scoped_atomic_and_fetch:
     PostOp = llvm::Instruction::And;
@@ -1047,10 +1116,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
   case AtomicExpr::AO__scoped_atomic_fetch_max:
   case AtomicExpr::AO__scoped_atomic_fetch_min:
   case AtomicExpr::AO__scoped_atomic_fetch_sub:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
   case AtomicExpr::AO__scoped_atomic_add_fetch:
   case AtomicExpr::AO__scoped_atomic_max_fetch:
   case AtomicExpr::AO__scoped_atomic_min_fetch:
   case AtomicExpr::AO__scoped_atomic_sub_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
     [[fallthrough]];
 
   case AtomicExpr::AO__atomic_fetch_and:
@@ -1093,6 +1170,22 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
   case AtomicExpr::AO__scoped_atomic_exchange_n:
   case AtomicExpr::AO__scoped_atomic_fetch_uinc:
   case AtomicExpr::AO__scoped_atomic_fetch_udec:
+  case AtomicExpr::AO__atomic_fetch_fminimum:
+  case AtomicExpr::AO__atomic_fetch_fmaximum:
+  case AtomicExpr::AO__atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__atomic_fetch_fmaximum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
+  case AtomicExpr::AO__atomic_fminimum_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_fetch:
+  case AtomicExpr::AO__atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
     Val1 = EmitValToTemp(*this, E->getVal1());
     break;
   }
@@ -1292,6 +1385,22 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
     case AtomicExpr::AO__opencl_atomic_fetch_max:
     case AtomicExpr::AO__scoped_atomic_fetch_max:
     case AtomicExpr::AO__scoped_atomic_max_fetch:
+    case AtomicExpr::AO__atomic_fetch_fminimum:
+    case AtomicExpr::AO__atomic_fetch_fmaximum:
+    case AtomicExpr::AO__atomic_fetch_fminimum_num:
+    case AtomicExpr::AO__atomic_fetch_fmaximum_num:
+    case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
+    case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
+    case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
+    case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
+    case AtomicExpr::AO__atomic_fminimum_fetch:
+    case AtomicExpr::AO__atomic_fmaximum_fetch:
+    case AtomicExpr::AO__atomic_fminimum_num_fetch:
+    case AtomicExpr::AO__atomic_fmaximum_num_fetch:
+    case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+    case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+    case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
+    case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
     case AtomicExpr::AO__scoped_atomic_fetch_uinc:
     case AtomicExpr::AO__scoped_atomic_fetch_udec:
     case AtomicExpr::AO__atomic_test_and_set:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 29add9d092e6b..b03ab1c64104c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4705,10 +4705,26 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
   case AtomicExpr::AO__atomic_fetch_min:
   case AtomicExpr::AO__atomic_max_fetch:
   case AtomicExpr::AO__atomic_min_fetch:
+  case AtomicExpr::AO__atomic_fetch_fminimum:
+  case AtomicExpr::AO__atomic_fetch_fmaximum:
+  case AtomicExpr::AO__atomic_fminimum_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_fetch:
+  case AtomicExpr::AO__atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__atomic_fetch_fmaximum_num:
+  case AtomicExpr::AO__atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__atomic_fmaximum_num_fetch:
   case AtomicExpr::AO__scoped_atomic_fetch_max:
   case AtomicExpr::AO__scoped_atomic_fetch_min:
   case AtomicExpr::AO__scoped_atomic_max_fetch:
   case AtomicExpr::AO__scoped_atomic_min_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
+  case AtomicExpr::AO__scoped_atomic_fminimum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
+  case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
+  case AtomicExpr::AO__scoped_atomic_fminimum_num_fetch:
+  case AtomicExpr::AO__scoped_atomic_fmaximum_num_fetch:
   case AtomicExpr::AO__c11_atomic_fetch_max:
   case AtomicExpr::AO__c11_atomic_fetch_min:
   case AtomicExpr::AO__opencl_atomic_fetch_max:
diff --git a/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c 
b/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c
index 4d9b29b789507..d525a6d86f1f1 100644
--- a/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c
+++ b/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c
@@ -115,3 +115,62 @@ void test_minmax_postop(float *f32, _Float16 *f16, __bf16 
*bf16, double *f64) {
   *f16  = __atomic_min_fetch(f16,  42.1, memory_order_release);
   *bf16 = __atomic_min_fetch(bf16, 42.1, memory_order_release);
 }
+
+// CHECK-LABEL: define dso_local void @test_fminimum_fmaximum_postop(
+// CHECK-SAME: ptr noundef [[F32:%.*]], ptr noundef [[F16:%.*]], ptr noundef 
[[BF16:%.*]], ptr noundef [[F64:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK:    [[TMP0:%.*]] = load ptr, ptr [[F64_ADDR]], align 8
+// CHECK:    store double 4.210000e+01, ptr [[DOTATOMICTMP]], align 8
+// CHECK:    [[TMP1:%.*]] = load double, ptr [[DOTATOMICTMP]], align 8
+// CHECK:    [[TMP2:%.*]] = atomicrmw fmaximum ptr [[TMP0]], double [[TMP1]] 
release, align 8
+// CHECK:    [[NEWVAL:%.*]] = call double @llvm.maximum.f64(double [[TMP2]], 
double [[TMP1]])
+// CHECK:    store double [[NEWVAL]], ptr [[ATOMIC_TEMP]], align 8
+// CHECK:    [[TMP3:%.*]] = load double, ptr [[ATOMIC_TEMP]], align 8
+// CHECK:    [[TMP4:%.*]] = load ptr, ptr [[F64_ADDR]], align 8
+// CHECK:    store double [[TMP3]], ptr [[TMP4]], align 8
+void test_fminimum_fmaximum_postop(float *f32, _Float16 *f16, __bf16 *bf16, 
double *f64) {
+  *f64  = __atomic_fmaximum_fetch(f64,  42.1, memory_order_release);
+  *f32  = __atomic_fmaximum_fetch(f32,  42.1, memory_order_release);
+  *f16  = __atomic_fmaximum_fetch(f16,  42.1, memory_order_release);
+  *bf16 = __atomic_fmaximum_fetch(bf16, 42.1, memory_order_release);
+  *f64  = __atomic_fminimum_fetch(f64,  42.1, memory_order_release);
+  *f32  = __atomic_fminimum_fetch(f32,  42.1, memory_order_release);
+  *f16  = __atomic_fminimum_fetch(f16,  42.1, memory_order_release);
+  *bf16 = __atomic_fminimum_fetch(bf16, 42.1, memory_order_release);
+}
+
+// CHECK-LABEL: define dso_local void @test_fminimumnum_fmaximumnum_postop(
+// CHECK-SAME: ptr noundef [[F32:%.*]], ptr noundef [[F16:%.*]], ptr noundef 
[[BF16:%.*]], ptr noundef [[F64:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK:    [[TMP0:%.*]] = load ptr, ptr [[F64_ADDR]], align 8
+// CHECK:    store double 4.210000e+01, ptr [[DOTATOMICTMP]], align 8
+// CHECK:    [[TMP1:%.*]] = load double, ptr [[DOTATOMICTMP]], align 8
+// CHECK:    [[TMP2:%.*]] = atomicrmw fmaximumnum ptr [[TMP0]], double 
[[TMP1]] release, align 8
+// CHECK:    [[NEWVAL:%.*]] = call double @llvm.maximumnum.f64(double 
[[TMP2]], double [[TMP1]])
+// CHECK:    store double [[NEWVAL]], ptr [[ATOMIC_TEMP]], align 8
+// CHECK:    [[TMP3:%.*]] = load double, ptr [[ATOMIC_TEMP]], align 8
+// CHECK:    [[TMP4:%.*]] = load ptr, ptr [[F64_ADDR]], align 8
+// CHECK:    store double [[TMP3]], ptr [[TMP4]], align 8
+void test_fminimumnum_fmaximumnum_postop(float *f32, _Float16 *f16, __bf16 
*bf16, double *f64) {
+  *f64  = __atomic_fmaximum_num_fetch(f64,  42.1, memory_order_release);
+  *f32  = __atomic_fmaximum_num_fetch(f32,  42.1, memory_order_release);
+  *f16  = __atomic_fmaximum_num_fetch(f16,  42.1, memory_order_release);
+  *bf16 = __atomic_fmaximum_num_fetch(bf16, 42.1, memory_order_release);
+  *f64  = __atomic_fminimum_num_fetch(f64,  42.1, memory_order_release);
+  *f32  = __atomic_fminimum_num_fetch(f32,  42.1, memory_order_release);
+  *f16  = __atomic_fminimum_num_fetch(f16,  42.1, memory_order_release);
+  *bf16 = __atomic_fminimum_num_fetch(bf16, 42.1, memory_order_release);
+}
+
+// CHECK-LABEL: define dso_local void @test_fetch_variants(
+// CHECK-SAME: ptr noundef [[F64:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:    [[TMP0:%.*]] = atomicrmw fminimum ptr {{%.*}}, double {{%.*}} 
release, align 8
+// CHECK:    [[TMP1:%.*]] = atomicrmw fmaximum ptr {{%.*}}, double {{%.*}} 
release, align 8
+// CHECK:    [[TMP2:%.*]] = atomicrmw fminimumnum ptr {{%.*}}, double {{%.*}} 
release, align 8
+// CHECK:    [[TMP3:%.*]] = atomicrmw fmaximumnum ptr {{%.*}}, double {{%.*}} 
release, align 8
+void test_fetch_variants(double *f64) {
+  double old1 = __atomic_fetch_fminimum(f64, 42.1, memory_order_release);
+  double old2 = __atomic_fetch_fmaximum(f64, 42.1, memory_order_release);
+  double old3 = __atomic_fetch_fminimum_num(f64, 42.1, memory_order_release);
+  double old4 = __atomic_fetch_fmaximum_num(f64, 42.1, memory_order_release);
+}
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 3318e369f3e0d..29c3cc7f22bcf 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -252,6 +252,18 @@ void f(_Atomic(int) *i, const _Atomic(int) *ci,
   __atomic_fetch_max(D, 3, memory_order_seq_cst);
   __atomic_fetch_max(P, 3, memory_order_seq_cst); // expected-error {{must be 
a pointer to integer or supported floating point type}}
   __atomic_fetch_max(p, 3);                       // expected-error {{too few 
arguments to function call, expected 3, have 2}}
+  __atomic_fetch_fminimum(F, 3, memory_order_seq_cst);
+  __atomic_fetch_fminimum(D, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum(F, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum(D, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum(P, 3, memory_order_seq_cst); // expected-error 
{{must be a pointer to integer or supported floating point type}}
+  __atomic_fetch_fmaximum(p, 3);                       // expected-error {{too 
few arguments to function call, expected 3, have 2}}
+  __atomic_fetch_fminimum_num(F, 3, memory_order_seq_cst);
+  __atomic_fetch_fminimum_num(D, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum_num(F, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum_num(D, 3, memory_order_seq_cst);
+  __atomic_fetch_fmaximum_num(P, 3, memory_order_seq_cst); // expected-error 
{{must be a pointer to integer or supported floating point type}}
+  __atomic_fetch_fmaximum_num(p, 3);                       // expected-error 
{{too few arguments to function call, expected 3, have 2}}
 
   __atomic_fetch_uinc(F, 1, memory_order_seq_cst); // expected-error {{address 
argument to atomic operation must be a pointer to integer}}
   __atomic_fetch_udec(F, 1, memory_order_seq_cst); // expected-error {{address 
argument to atomic operation must be a pointer to integer}}
@@ -601,6 +613,20 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_fetch_min(p, val, memory_order_acq_rel);
   (void)__atomic_fetch_min(p, val, memory_order_seq_cst);
 
+  (void)__atomic_fetch_fminimum(p, val, memory_order_relaxed);
+  (void)__atomic_fetch_fminimum(p, val, memory_order_acquire);
+  (void)__atomic_fetch_fminimum(p, val, memory_order_consume);
+  (void)__atomic_fetch_fminimum(p, val, memory_order_release);
+  (void)__atomic_fetch_fminimum(p, val, memory_order_acq_rel);
+  (void)__atomic_fetch_fminimum(p, val, memory_order_seq_cst);
+
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_relaxed);
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_acquire);
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_consume);
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_release);
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_acq_rel);
+  (void)__atomic_fetch_fminimum_num(p, val, memory_order_seq_cst);
+
   (void)__atomic_fetch_uinc(p, val, memory_order_relaxed);
   (void)__atomic_fetch_uinc(p, val, memory_order_acquire);
   (void)__atomic_fetch_uinc(p, val, memory_order_consume);
@@ -622,6 +648,20 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_fetch_max(p, val, memory_order_acq_rel);
   (void)__atomic_fetch_max(p, val, memory_order_seq_cst);
 
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_relaxed);
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_acquire);
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_consume);
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_release);
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_acq_rel);
+  (void)__atomic_fetch_fmaximum(p, val, memory_order_seq_cst);
+
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_relaxed);
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_acquire);
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_consume);
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_release);
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_acq_rel);
+  (void)__atomic_fetch_fmaximum_num(p, val, memory_order_seq_cst);
+
   (void)__atomic_and_fetch(p, val, memory_order_relaxed);
   (void)__atomic_and_fetch(p, val, memory_order_acquire);
   (void)__atomic_and_fetch(p, val, memory_order_consume);
@@ -664,6 +704,34 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_min_fetch(p, val, memory_order_acq_rel);
   (void)__atomic_min_fetch(p, val, memory_order_seq_cst);
 
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_relaxed);
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_acquire);
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_consume);
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_release);
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_acq_rel);
+  (void)__atomic_fmaximum_fetch(p, val, memory_order_seq_cst);
+
+  (void)__atomic_fminimum_fetch(p, val, memory_order_relaxed);
+  (void)__atomic_fminimum_fetch(p, val, memory_order_acquire);
+  (void)__atomic_fminimum_fetch(p, val, memory_order_consume);
+  (void)__atomic_fminimum_fetch(p, val, memory_order_release);
+  (void)__atomic_fminimum_fetch(p, val, memory_order_acq_rel);
+  (void)__atomic_fminimum_fetch(p, val, memory_order_seq_cst);
+
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_relaxed);
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_acquire);
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_consume);
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_release);
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_acq_rel);
+  (void)__atomic_fmaximum_num_fetch(p, val, memory_order_seq_cst);
+
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_relaxed);
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_acquire);
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_consume);
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_release);
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_acq_rel);
+  (void)__atomic_fminimum_num_fetch(p, val, memory_order_seq_cst);
+
   (void)__atomic_exchange_n(p, val, memory_order_relaxed);
   (void)__atomic_exchange_n(p, val, memory_order_acquire);
   (void)__atomic_exchange_n(p, val, memory_order_consume);
@@ -851,6 +919,14 @@ void nullPointerWarning(void) {
   (void)__atomic_fetch_min((int*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
   (void)__atomic_fetch_max((volatile int*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
   (void)__atomic_fetch_max((int*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
+  (void)__atomic_fetch_fminimum((volatile float*)0, 42, memory_order_relaxed); 
// expected-warning {{null passed to a callee that requires a non-null 
argument}}
+  (void)__atomic_fetch_fminimum((float*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
+  (void)__atomic_fetch_fmaximum((volatile float*)0, 42, memory_order_relaxed); 
// expected-warning {{null passed to a callee that requires a non-null 
argument}}
+  (void)__atomic_fetch_fmaximum((float*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
+  (void)__atomic_fetch_fminimum_num((volatile float*)0, 42, 
memory_order_relaxed); // expected-warning {{null passed to a callee that 
requires a non-null argument}}
+  (void)__atomic_fetch_fminimum_num((float*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
+  (void)__atomic_fetch_fmaximum_num((volatile float*)0, 42, 
memory_order_relaxed); // expected-warning {{null passed to a callee that 
requires a non-null argument}}
+  (void)__atomic_fetch_fmaximum_num((float*)0, 42, memory_order_relaxed); // 
expected-warning {{null passed to a callee that requires a non-null argument}}
 
   // These don't warn: the "desired" parameter is passed by value. Even for
   // atomic pointers the "desired" result can be NULL.
diff --git a/clang/test/Sema/scoped-atomic-ops.c 
b/clang/test/Sema/scoped-atomic-ops.c
index 49ddc64ce23eb..71e95df6e732b 100644
--- a/clang/test/Sema/scoped-atomic-ops.c
+++ b/clang/test/Sema/scoped-atomic-ops.c
@@ -93,6 +93,38 @@ void fi3e(float *a, float *b, float *c, float *d, float *e, 
float *f) {
   *e = __scoped_atomic_fetch_udec(e, 1u, __ATOMIC_RELAXED, 42); // 
expected-error {{address argument to atomic operation must be a pointer to 
integer ('float *' invalid)}}
 }
 
+void fi3f(float *a, float *b, float *c, float *d, double *e, double *f, double 
*g, double *h) {
+  *a = __scoped_atomic_fetch_fminimum(a, 1.0f, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *b = __scoped_atomic_fetch_fmaximum(b, 1.0f, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *c = __scoped_atomic_fetch_fminimum_num(c, 1.0f, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *d = __scoped_atomic_fetch_fmaximum_num(d, 1.0f, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *e = __scoped_atomic_fetch_fminimum(e, 1.0, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *f = __scoped_atomic_fetch_fmaximum(f, 1.0, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *g = __scoped_atomic_fetch_fminimum_num(g, 1.0, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  *h = __scoped_atomic_fetch_fmaximum_num(h, 1.0, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+}
+
+void fi3g(float *a, float *b, float *c, float *d) {
+  *a = __scoped_atomic_fetch_fminimum(a, 1.0f, __ATOMIC_RELAXED); // 
expected-error {{too few arguments to function call, expected 4, have 3}}
+  *b = __scoped_atomic_fetch_fmaximum(b, 1.0f, __ATOMIC_RELAXED); // 
expected-error {{too few arguments to function call, expected 4, have 3}}
+  *c = __scoped_atomic_fetch_fminimum_num(c, 1.0f, __ATOMIC_RELAXED); // 
expected-error {{too few arguments to function call, expected 4, have 3}}
+  *d = __scoped_atomic_fetch_fmaximum_num(d, 1.0f, __ATOMIC_RELAXED); // 
expected-error {{too few arguments to function call, expected 4, have 3}}
+}
+
+void fi3h(float *a, float *b, float *c, float *d) {
+  *a = __scoped_atomic_fetch_fminimum(a, 1.0f, __ATOMIC_RELAXED, 42); // 
expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *b = __scoped_atomic_fetch_fmaximum(b, 1.0f, __ATOMIC_RELAXED, 42); // 
expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *c = __scoped_atomic_fetch_fminimum_num(c, 1.0f, __ATOMIC_RELAXED, 42); // 
expected-error {{synchronization scope argument to atomic operation is invalid}}
+  *d = __scoped_atomic_fetch_fmaximum_num(d, 1.0f, __ATOMIC_RELAXED, 42); // 
expected-error {{synchronization scope argument to atomic operation is invalid}}
+}
+
+void fi3i(int *a, int *b, int *c, int *d) {
+  *a = __scoped_atomic_fetch_fminimum(a, 1, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic 
operation must be a pointer to floating point type}}
+  *b = __scoped_atomic_fetch_fmaximum(b, 1, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic 
operation must be a pointer to floating point type}}
+  *c = __scoped_atomic_fetch_fminimum_num(c, 1, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic 
operation must be a pointer to floating point type}}
+  *d = __scoped_atomic_fetch_fmaximum_num(d, 1, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic 
operation must be a pointer to floating point type}}
+}
+
 int fi4a(int *i) {
   int cmp = 0;
   int desired = 1;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to