https://github.com/gonzalobg updated https://github.com/llvm/llvm-project/pull/187139
>From a2a06e97bfd861b2e0db0ab2db5d22e70ce932d0 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/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/AST/Expr.cpp | 16 +++ clang/lib/CodeGen/CGAtomic.cpp | 109 +++++++++++++++++- clang/lib/Sema/SemaChecking.cpp | 34 ++++-- .../AArch64/atomic-ops-float-check-minmax.c | 59 ++++++++++ clang/test/Sema/atomic-ops.c | 76 ++++++++++++ clang/test/Sema/scoped-atomic-ops.c | 32 +++++ 8 files changed, 413 insertions(+), 12 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/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d4d09a8ecef36..9fde954f84ca4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9630,6 +9630,9 @@ def err_atomic_op_needs_atomic_int_or_fp : Error< def err_atomic_op_needs_atomic_int : Error< "address argument to atomic operation must be a pointer to " "%select{|atomic }0integer (%1 invalid)">; +def err_atomic_op_needs_atomic_fp : Error< + "address argument to atomic operation must be a pointer to " + "%select{|atomic }0floating point type (%1 invalid)">; def warn_atomic_op_has_invalid_memory_order : Warning< "%select{|success |failure }0memory order argument to atomic operation is invalid">, InGroup<DiagGroup<"atomic-memory-ordering">>; 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..4f02b27eb4f31 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,14 @@ 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__atomic_fminimum_fetch: + case AtomicExpr::AO__atomic_fmaximum_fetch: + case AtomicExpr::AO__atomic_fminimum_num_fetch: + case AtomicExpr::AO__atomic_fmaximum_num_fetch: Val1 = EmitValToTemp(*this, E->getVal1()); break; } @@ -1292,6 +1377,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..a292a1eff2eba 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: @@ -4893,7 +4909,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, &Context.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended(); if (ValType->isIntegerType()) - return true; + return AllowedType != AOEVT_FP; if (ValType->isPointerType()) return AllowedType & AOEVT_Pointer; if (!(ValType->isFloatingType() && (AllowedType & AOEVT_FP))) @@ -4904,13 +4920,15 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, return true; }; if (!IsAllowedValueType(ValType, ArithAllows)) { - auto DID = ArithAllows & AOEVT_FP - ? (ArithAllows & AOEVT_Pointer - ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp - : diag::err_atomic_op_needs_atomic_int_or_fp) - : (ArithAllows & AOEVT_Pointer - ? diag::err_atomic_op_needs_atomic_int_or_ptr - : diag::err_atomic_op_needs_atomic_int); + auto DID = ArithAllows == AOEVT_FP + ? diag::err_atomic_op_needs_atomic_fp + : (ArithAllows & AOEVT_FP + ? (ArithAllows & AOEVT_Pointer + ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp + : diag::err_atomic_op_needs_atomic_int_or_fp) + : (ArithAllows & AOEVT_Pointer + ? diag::err_atomic_op_needs_atomic_int_or_ptr + : diag::err_atomic_op_needs_atomic_int)); Diag(ExprRange.getBegin(), DID) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); 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
