Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CGAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,18 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
bool IsSigned,
llvm::Value *OldVal,
llvm::Value *RHS) {
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;

return Builder.CreateBinaryIntrinsic(IID, OldVal, RHS, llvm::FMFSource(),
"newval");
}

llvm::CmpInst::Predicate Pred;
switch (Op) {
default:
Expand Down
117 changes: 117 additions & 0 deletions clang/test/CodeGen/AArch64/atomic-ops-float-check-minmax.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 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 | 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: [[DOTATOMICTMP4:%.*]] = alloca half, align 2
// CHECK-NEXT: [[ATOMIC_TEMP5:%.*]] = alloca half, align 2
// CHECK-NEXT: [[DOTATOMICTMP7:%.*]] = alloca bfloat, align 2
// CHECK-NEXT: [[ATOMIC_TEMP8:%.*]] = alloca bfloat, align 2
// CHECK-NEXT: [[DOTATOMICTMP10:%.*]] = alloca double, align 8
// CHECK-NEXT: [[ATOMIC_TEMP11:%.*]] = alloca double, align 8
// CHECK-NEXT: [[DOTATOMICTMP13:%.*]] = alloca float, align 4
// CHECK-NEXT: [[ATOMIC_TEMP14:%.*]] = alloca float, align 4
// CHECK-NEXT: [[DOTATOMICTMP16:%.*]] = alloca half, align 2
// CHECK-NEXT: [[ATOMIC_TEMP17:%.*]] = alloca half, align 2
// CHECK-NEXT: [[DOTATOMICTMP19:%.*]] = alloca bfloat, align 2
// CHECK-NEXT: [[ATOMIC_TEMP20:%.*]] = 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: [[NEWVAL:%.*]] = call double @llvm.maxnum.f64(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: [[NEWVAL3:%.*]] = call float @llvm.maxnum.f32(float [[TMP7]], float [[TMP6]])
// CHECK-NEXT: store float [[NEWVAL3]], 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 [[DOTATOMICTMP4]], align 2
// CHECK-NEXT: [[TMP11:%.*]] = load half, ptr [[DOTATOMICTMP4]], align 2
// CHECK-NEXT: [[TMP12:%.*]] = atomicrmw fmax ptr [[TMP10]], half [[TMP11]] release, align 2
// CHECK-NEXT: [[NEWVAL6:%.*]] = call half @llvm.maxnum.f16(half [[TMP12]], half [[TMP11]])
// CHECK-NEXT: store half [[NEWVAL6]], ptr [[ATOMIC_TEMP5]], align 2
// CHECK-NEXT: [[TMP13:%.*]] = load half, ptr [[ATOMIC_TEMP5]], 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 [[DOTATOMICTMP7]], align 2
// CHECK-NEXT: [[TMP16:%.*]] = load bfloat, ptr [[DOTATOMICTMP7]], align 2
// CHECK-NEXT: [[TMP17:%.*]] = atomicrmw fmax ptr [[TMP15]], bfloat [[TMP16]] release, align 2
// CHECK-NEXT: [[NEWVAL9:%.*]] = call bfloat @llvm.maxnum.bf16(bfloat [[TMP17]], bfloat [[TMP16]])
// CHECK-NEXT: store bfloat [[NEWVAL9]], ptr [[ATOMIC_TEMP8]], align 2
// CHECK-NEXT: [[TMP18:%.*]] = load bfloat, ptr [[ATOMIC_TEMP8]], 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 [[DOTATOMICTMP10]], align 8
// CHECK-NEXT: [[TMP21:%.*]] = load double, ptr [[DOTATOMICTMP10]], align 8
// CHECK-NEXT: [[TMP22:%.*]] = atomicrmw fmin ptr [[TMP20]], double [[TMP21]] release, align 8
// CHECK-NEXT: [[NEWVAL12:%.*]] = call double @llvm.minnum.f64(double [[TMP22]], double [[TMP21]])
// CHECK-NEXT: store double [[NEWVAL12]], ptr [[ATOMIC_TEMP11]], align 8
// CHECK-NEXT: [[TMP23:%.*]] = load double, ptr [[ATOMIC_TEMP11]], 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 [[DOTATOMICTMP13]], align 4
// CHECK-NEXT: [[TMP26:%.*]] = load float, ptr [[DOTATOMICTMP13]], align 4
// CHECK-NEXT: [[TMP27:%.*]] = atomicrmw fmin ptr [[TMP25]], float [[TMP26]] release, align 4
// CHECK-NEXT: [[NEWVAL15:%.*]] = call float @llvm.minnum.f32(float [[TMP27]], float [[TMP26]])
// CHECK-NEXT: store float [[NEWVAL15]], ptr [[ATOMIC_TEMP14]], align 4
// CHECK-NEXT: [[TMP28:%.*]] = load float, ptr [[ATOMIC_TEMP14]], 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 [[DOTATOMICTMP16]], align 2
// CHECK-NEXT: [[TMP31:%.*]] = load half, ptr [[DOTATOMICTMP16]], align 2
// CHECK-NEXT: [[TMP32:%.*]] = atomicrmw fmin ptr [[TMP30]], half [[TMP31]] release, align 2
// CHECK-NEXT: [[NEWVAL18:%.*]] = call half @llvm.minnum.f16(half [[TMP32]], half [[TMP31]])
// CHECK-NEXT: store half [[NEWVAL18]], ptr [[ATOMIC_TEMP17]], align 2
// CHECK-NEXT: [[TMP33:%.*]] = load half, ptr [[ATOMIC_TEMP17]], 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 [[DOTATOMICTMP19]], align 2
// CHECK-NEXT: [[TMP36:%.*]] = load bfloat, ptr [[DOTATOMICTMP19]], align 2
// CHECK-NEXT: [[TMP37:%.*]] = atomicrmw fmin ptr [[TMP35]], bfloat [[TMP36]] release, align 2
// CHECK-NEXT: [[NEWVAL21:%.*]] = call bfloat @llvm.minnum.bf16(bfloat [[TMP37]], bfloat [[TMP36]])
// CHECK-NEXT: store bfloat [[NEWVAL21]], ptr [[ATOMIC_TEMP20]], align 2
// CHECK-NEXT: [[TMP38:%.*]] = load bfloat, ptr [[ATOMIC_TEMP20]], 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);
}
16 changes: 16 additions & 0 deletions clang/test/Sema/atomic-ops-fp-minmax.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -verify -ffreestanding -triple=aarch64-linux-gnu %s
// REQUIRES: aarch64-registered-target

#include <stdatomic.h>

void memory_checks(_Float16 *p16, __bf16 *pbf, float *pf, double *pd) {
(void)__atomic_fetch_min(p16, (_Float16)1.0f, memory_order_relaxed);
(void)__atomic_fetch_max(pbf, (__bf16)2.0f, memory_order_acquire);
(void)__atomic_fetch_min(pf, 3.0f, memory_order_release);
(void)__atomic_fetch_max(pd, 4.0, memory_order_seq_cst);
}

void nullPointerWarning(void) {
(void)__atomic_fetch_min((volatile float*)0, 42.0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
(void)__atomic_fetch_max((float*)0, 42.0, memory_order_relaxed); // expected-warning {{null passed to a callee that requires a non-null argument}}
}