https://github.com/Amichaxx updated https://github.com/llvm/llvm-project/pull/160330
>From a8043a7fd01823f05246b857f29b0957484b5222 Mon Sep 17 00:00:00 2001 From: Amichaxx <[email protected]> Date: Mon, 22 Sep 2025 15:55:57 +0000 Subject: [PATCH 1/2] [Clang] Add support for fp when using min_fetch/max_fetch atomics Previously when using min_fetch/max_fetch atomics with floating point types, LLVM would emit a crash. This patch updates the EmitPostAtomicMinMax function in CGAtomic.cpp to take floating point types. Included is a clang CodeGen test atomic-ops-float-check-minmax.c --- clang/lib/CodeGen/CGAtomic.cpp | 18 ++- .../AArch64/atomic-ops-float-check-minmax.c | 125 ++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index 9106c4cd8e139..99a06e527033b 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -507,20 +507,32 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder, bool IsSigned, llvm::Value *OldVal, llvm::Value *RHS) { + llvm::Type *ValTy = OldVal->getType(); + llvm::CmpInst::Predicate Pred; + bool IsFP = ValTy->isFloatingPointTy(); + switch (Op) { default: llvm_unreachable("Unexpected min/max operation"); + case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__scoped_atomic_max_fetch: - Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT; + Pred = IsFP ? llvm::CmpInst::FCMP_OGT + : (IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT); break; + case AtomicExpr::AO__atomic_min_fetch: case AtomicExpr::AO__scoped_atomic_min_fetch: - Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT; + Pred = IsFP ? llvm::CmpInst::FCMP_OLT + : (IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT); break; } - llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst"); + + llvm::Value *Cmp = IsFP + ? static_cast<llvm::Value*>(Builder.CreateFCmp(Pred, OldVal, RHS, "tst")) + : static_cast<llvm::Value*>(Builder.CreateICmp(Pred, OldVal, RHS, "tst")); + return Builder.CreateSelect(Cmp, OldVal, RHS, "newval"); } diff --git a/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c b/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c new file mode 100644 index 0000000000000..e871f6a00e145 --- /dev/null +++ b/clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c @@ -0,0 +1,125 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -triple=aarch64-linux-gnu -pthread -target-feature +bf16 | FileCheck %s + +#include <stdint.h> +#include <stdatomic.h> + +// CHECK-LABEL: define dso_local void @test_minmax_postop( +// CHECK-SAME: ptr noundef [[F32:%.*]], ptr noundef [[F16:%.*]], ptr noundef [[BF16:%.*]], ptr noundef [[F64:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[F32_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[F16_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[BF16_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[F64_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[DOTATOMICTMP1:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP2:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[DOTATOMICTMP5:%.*]] = alloca half, align 2 +// CHECK-NEXT: [[ATOMIC_TEMP6:%.*]] = alloca half, align 2 +// CHECK-NEXT: [[DOTATOMICTMP9:%.*]] = alloca bfloat, align 2 +// CHECK-NEXT: [[ATOMIC_TEMP10:%.*]] = alloca bfloat, align 2 +// CHECK-NEXT: [[DOTATOMICTMP13:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP14:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[DOTATOMICTMP17:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP18:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[DOTATOMICTMP21:%.*]] = alloca half, align 2 +// CHECK-NEXT: [[ATOMIC_TEMP22:%.*]] = alloca half, align 2 +// CHECK-NEXT: [[DOTATOMICTMP25:%.*]] = alloca bfloat, align 2 +// CHECK-NEXT: [[ATOMIC_TEMP26:%.*]] = alloca bfloat, align 2 +// CHECK-NEXT: store ptr [[F32]], ptr [[F32_ADDR]], align 8 +// CHECK-NEXT: store ptr [[F16]], ptr [[F16_ADDR]], align 8 +// CHECK-NEXT: store ptr [[BF16]], ptr [[BF16_ADDR]], align 8 +// CHECK-NEXT: store ptr [[F64]], ptr [[F64_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[F64_ADDR]], align 8 +// CHECK-NEXT: store double 4.210000e+01, ptr [[DOTATOMICTMP]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[DOTATOMICTMP]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw fmax ptr [[TMP0]], double [[TMP1]] release, align 8 +// CHECK-NEXT: [[TST:%.*]] = fcmp ogt double [[TMP2]], [[TMP1]] +// CHECK-NEXT: [[NEWVAL:%.*]] = select i1 [[TST]], double [[TMP2]], double [[TMP1]] +// CHECK-NEXT: store double [[NEWVAL]], ptr [[ATOMIC_TEMP]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[ATOMIC_TEMP]], align 8 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[F64_ADDR]], align 8 +// CHECK-NEXT: store double [[TMP3]], ptr [[TMP4]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[F32_ADDR]], align 8 +// CHECK-NEXT: store float 0x40450CCCC0000000, ptr [[DOTATOMICTMP1]], align 4 +// CHECK-NEXT: [[TMP6:%.*]] = load float, ptr [[DOTATOMICTMP1]], align 4 +// CHECK-NEXT: [[TMP7:%.*]] = atomicrmw fmax ptr [[TMP5]], float [[TMP6]] release, align 4 +// CHECK-NEXT: [[TST3:%.*]] = fcmp ogt float [[TMP7]], [[TMP6]] +// CHECK-NEXT: [[NEWVAL4:%.*]] = select i1 [[TST3]], float [[TMP7]], float [[TMP6]] +// CHECK-NEXT: store float [[NEWVAL4]], ptr [[ATOMIC_TEMP2]], align 4 +// CHECK-NEXT: [[TMP8:%.*]] = load float, ptr [[ATOMIC_TEMP2]], align 4 +// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[F32_ADDR]], align 8 +// CHECK-NEXT: store float [[TMP8]], ptr [[TMP9]], align 4 +// CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[F16_ADDR]], align 8 +// CHECK-NEXT: store half 0xH5143, ptr [[DOTATOMICTMP5]], align 2 +// CHECK-NEXT: [[TMP11:%.*]] = load half, ptr [[DOTATOMICTMP5]], align 2 +// CHECK-NEXT: [[TMP12:%.*]] = atomicrmw fmax ptr [[TMP10]], half [[TMP11]] release, align 2 +// CHECK-NEXT: [[TST7:%.*]] = fcmp ogt half [[TMP12]], [[TMP11]] +// CHECK-NEXT: [[NEWVAL8:%.*]] = select i1 [[TST7]], half [[TMP12]], half [[TMP11]] +// CHECK-NEXT: store half [[NEWVAL8]], ptr [[ATOMIC_TEMP6]], align 2 +// CHECK-NEXT: [[TMP13:%.*]] = load half, ptr [[ATOMIC_TEMP6]], align 2 +// CHECK-NEXT: [[TMP14:%.*]] = load ptr, ptr [[F16_ADDR]], align 8 +// CHECK-NEXT: store half [[TMP13]], ptr [[TMP14]], align 2 +// CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[BF16_ADDR]], align 8 +// CHECK-NEXT: store bfloat 0xR4228, ptr [[DOTATOMICTMP9]], align 2 +// CHECK-NEXT: [[TMP16:%.*]] = load bfloat, ptr [[DOTATOMICTMP9]], align 2 +// CHECK-NEXT: [[TMP17:%.*]] = atomicrmw fmax ptr [[TMP15]], bfloat [[TMP16]] release, align 2 +// CHECK-NEXT: [[TST11:%.*]] = fcmp ogt bfloat [[TMP17]], [[TMP16]] +// CHECK-NEXT: [[NEWVAL12:%.*]] = select i1 [[TST11]], bfloat [[TMP17]], bfloat [[TMP16]] +// CHECK-NEXT: store bfloat [[NEWVAL12]], ptr [[ATOMIC_TEMP10]], align 2 +// CHECK-NEXT: [[TMP18:%.*]] = load bfloat, ptr [[ATOMIC_TEMP10]], align 2 +// CHECK-NEXT: [[TMP19:%.*]] = load ptr, ptr [[BF16_ADDR]], align 8 +// CHECK-NEXT: store bfloat [[TMP18]], ptr [[TMP19]], align 2 +// CHECK-NEXT: [[TMP20:%.*]] = load ptr, ptr [[F64_ADDR]], align 8 +// CHECK-NEXT: store double 4.210000e+01, ptr [[DOTATOMICTMP13]], align 8 +// CHECK-NEXT: [[TMP21:%.*]] = load double, ptr [[DOTATOMICTMP13]], align 8 +// CHECK-NEXT: [[TMP22:%.*]] = atomicrmw fmin ptr [[TMP20]], double [[TMP21]] release, align 8 +// CHECK-NEXT: [[TST15:%.*]] = fcmp olt double [[TMP22]], [[TMP21]] +// CHECK-NEXT: [[NEWVAL16:%.*]] = select i1 [[TST15]], double [[TMP22]], double [[TMP21]] +// CHECK-NEXT: store double [[NEWVAL16]], ptr [[ATOMIC_TEMP14]], align 8 +// CHECK-NEXT: [[TMP23:%.*]] = load double, ptr [[ATOMIC_TEMP14]], align 8 +// CHECK-NEXT: [[TMP24:%.*]] = load ptr, ptr [[F64_ADDR]], align 8 +// CHECK-NEXT: store double [[TMP23]], ptr [[TMP24]], align 8 +// CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[F32_ADDR]], align 8 +// CHECK-NEXT: store float 0x40450CCCC0000000, ptr [[DOTATOMICTMP17]], align 4 +// CHECK-NEXT: [[TMP26:%.*]] = load float, ptr [[DOTATOMICTMP17]], align 4 +// CHECK-NEXT: [[TMP27:%.*]] = atomicrmw fmin ptr [[TMP25]], float [[TMP26]] release, align 4 +// CHECK-NEXT: [[TST19:%.*]] = fcmp olt float [[TMP27]], [[TMP26]] +// CHECK-NEXT: [[NEWVAL20:%.*]] = select i1 [[TST19]], float [[TMP27]], float [[TMP26]] +// CHECK-NEXT: store float [[NEWVAL20]], ptr [[ATOMIC_TEMP18]], align 4 +// CHECK-NEXT: [[TMP28:%.*]] = load float, ptr [[ATOMIC_TEMP18]], align 4 +// CHECK-NEXT: [[TMP29:%.*]] = load ptr, ptr [[F32_ADDR]], align 8 +// CHECK-NEXT: store float [[TMP28]], ptr [[TMP29]], align 4 +// CHECK-NEXT: [[TMP30:%.*]] = load ptr, ptr [[F16_ADDR]], align 8 +// CHECK-NEXT: store half 0xH5143, ptr [[DOTATOMICTMP21]], align 2 +// CHECK-NEXT: [[TMP31:%.*]] = load half, ptr [[DOTATOMICTMP21]], align 2 +// CHECK-NEXT: [[TMP32:%.*]] = atomicrmw fmin ptr [[TMP30]], half [[TMP31]] release, align 2 +// CHECK-NEXT: [[TST23:%.*]] = fcmp olt half [[TMP32]], [[TMP31]] +// CHECK-NEXT: [[NEWVAL24:%.*]] = select i1 [[TST23]], half [[TMP32]], half [[TMP31]] +// CHECK-NEXT: store half [[NEWVAL24]], ptr [[ATOMIC_TEMP22]], align 2 +// CHECK-NEXT: [[TMP33:%.*]] = load half, ptr [[ATOMIC_TEMP22]], align 2 +// CHECK-NEXT: [[TMP34:%.*]] = load ptr, ptr [[F16_ADDR]], align 8 +// CHECK-NEXT: store half [[TMP33]], ptr [[TMP34]], align 2 +// CHECK-NEXT: [[TMP35:%.*]] = load ptr, ptr [[BF16_ADDR]], align 8 +// CHECK-NEXT: store bfloat 0xR4228, ptr [[DOTATOMICTMP25]], align 2 +// CHECK-NEXT: [[TMP36:%.*]] = load bfloat, ptr [[DOTATOMICTMP25]], align 2 +// CHECK-NEXT: [[TMP37:%.*]] = atomicrmw fmin ptr [[TMP35]], bfloat [[TMP36]] release, align 2 +// CHECK-NEXT: [[TST27:%.*]] = fcmp olt bfloat [[TMP37]], [[TMP36]] +// CHECK-NEXT: [[NEWVAL28:%.*]] = select i1 [[TST27]], bfloat [[TMP37]], bfloat [[TMP36]] +// CHECK-NEXT: store bfloat [[NEWVAL28]], ptr [[ATOMIC_TEMP26]], align 2 +// CHECK-NEXT: [[TMP38:%.*]] = load bfloat, ptr [[ATOMIC_TEMP26]], align 2 +// CHECK-NEXT: [[TMP39:%.*]] = load ptr, ptr [[BF16_ADDR]], align 8 +// CHECK-NEXT: store bfloat [[TMP38]], ptr [[TMP39]], align 2 +// CHECK-NEXT: ret void +// +void test_minmax_postop(float *f32, _Float16 *f16, __bf16 *bf16, double *f64) { + *f64 = __atomic_max_fetch(f64, 42.1, memory_order_release); + *f32 = __atomic_max_fetch(f32, 42.1, memory_order_release); + *f16 = __atomic_max_fetch(f16, 42.1, memory_order_release); + *bf16 = __atomic_max_fetch(bf16, 42.1, memory_order_release); + *f64 = __atomic_min_fetch(f64, 42.1, memory_order_release); + *f32 = __atomic_min_fetch(f32, 42.1, memory_order_release); + *f16 = __atomic_min_fetch(f16, 42.1, memory_order_release); + *bf16 = __atomic_min_fetch(bf16, 42.1, memory_order_release); +} >From 8703e41751db9c33759dd0926b57d8a437f27401 Mon Sep 17 00:00:00 2001 From: Amichaxx <[email protected]> Date: Tue, 23 Sep 2025 15:52:46 +0000 Subject: [PATCH 2/2] Clang formatting --- clang/lib/CodeGen/CGAtomic.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index 99a06e527033b..4e195ca0ec258 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -518,20 +518,23 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder, case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__scoped_atomic_max_fetch: - Pred = IsFP ? llvm::CmpInst::FCMP_OGT - : (IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT); + Pred = IsFP + ? llvm::CmpInst::FCMP_OGT + : (IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT); break; case AtomicExpr::AO__atomic_min_fetch: case AtomicExpr::AO__scoped_atomic_min_fetch: - Pred = IsFP ? llvm::CmpInst::FCMP_OLT - : (IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT); + Pred = IsFP + ? llvm::CmpInst::FCMP_OLT + : (IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT); break; } - llvm::Value *Cmp = IsFP - ? static_cast<llvm::Value*>(Builder.CreateFCmp(Pred, OldVal, RHS, "tst")) - : static_cast<llvm::Value*>(Builder.CreateICmp(Pred, OldVal, RHS, "tst")); + llvm::Value *Cmp = IsFP ? static_cast<llvm::Value *>( + Builder.CreateFCmp(Pred, OldVal, RHS, "tst")) + : static_cast<llvm::Value *>( + Builder.CreateICmp(Pred, OldVal, RHS, "tst")); return Builder.CreateSelect(Cmp, OldVal, RHS, "newval"); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
