diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8188,6 +8188,9 @@ def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; +def err_atomic_op_needs_atomic_int_ptr_or_fp : Error< + "address argument to atomic operation must be a pointer to %select{|atomic }0" + "integer, pointer or supported floating point type (%1 invalid)">; def err_atomic_op_needs_atomic_int_or_ptr : Error< "address argument to atomic operation must be a pointer to %select{|atomic }0" "integer or pointer (%1 invalid)">; diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -602,21 +602,25 @@ break; case AtomicExpr::AO__atomic_add_fetch: - PostOp = llvm::Instruction::Add; + PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FAdd + : llvm::Instruction::Add; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: - Op = llvm::AtomicRMWInst::Add; + Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FAdd + : llvm::AtomicRMWInst::Add; break; case AtomicExpr::AO__atomic_sub_fetch: - PostOp = llvm::Instruction::Sub; + PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FSub + : llvm::Instruction::Sub; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_sub: - Op = llvm::AtomicRMWInst::Sub; + Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FSub + : llvm::AtomicRMWInst::Sub; break; case AtomicExpr::AO__atomic_min_fetch: @@ -813,6 +817,8 @@ bool Oversized = getContext().toBits(TInfo.Width) > MaxInlineWidthInBits; bool Misaligned = (Ptr.getAlignment() % TInfo.Width) != 0; bool UseLibcall = Misaligned | Oversized; + bool ShouldCastToIntPtrTy = true; + CharUnits MaxInlineWidth = getContext().toCharUnitsFromBits(MaxInlineWidthInBits); @@ -892,11 +898,14 @@ EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Temp, Val1Ty)); break; } - LLVM_FALLTHROUGH; + LLVM_FALLTHROUGH; case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_sub_fetch: + ShouldCastToIntPtrTy = !MemTy->isFloatingType(); + LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_store: @@ -937,15 +946,23 @@ LValue AtomicVal = MakeAddrLValue(Ptr, AtomicTy); AtomicInfo Atomics(*this, AtomicVal); - Ptr = Atomics.emitCastToAtomicIntPointer(Ptr); - if (Val1.isValid()) Val1 = Atomics.convertToAtomicIntPointer(Val1); - if (Val2.isValid()) Val2 = Atomics.convertToAtomicIntPointer(Val2); - if (Dest.isValid()) - Dest = Atomics.emitCastToAtomicIntPointer(Dest); - else if (E->isCmpXChg()) + if (ShouldCastToIntPtrTy) { + Ptr = Atomics.emitCastToAtomicIntPointer(Ptr); + if (Val1.isValid()) + Val1 = Atomics.convertToAtomicIntPointer(Val1); + if (Val2.isValid()) + Val2 = Atomics.convertToAtomicIntPointer(Val2); + } + if (Dest.isValid()) { + if (ShouldCastToIntPtrTy) + Dest = Atomics.emitCastToAtomicIntPointer(Dest); + } else if (E->isCmpXChg()) Dest = CreateMemTemp(RValTy, "cmpxchg.bool"); - else if (!RValTy->isVoidType()) - Dest = Atomics.emitCastToAtomicIntPointer(Atomics.CreateTempAlloca()); + else if (!RValTy->isVoidType()) { + Dest = Atomics.CreateTempAlloca(); + if (ShouldCastToIntPtrTy) + Dest = Atomics.emitCastToAtomicIntPointer(Dest); + } // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary . if (UseLibcall) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4931,7 +4931,8 @@ case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_sub_fetch: IsAddSub = true; - LLVM_FALLTHROUGH; + Form = Arithmetic; + break; case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: @@ -4946,6 +4947,8 @@ case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: + Form = Arithmetic; + break; case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_min: @@ -5038,10 +5041,24 @@ // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { - // gcc does not enforce these rules for GNU atomics, but we do so for sanity. - if (IsAddSub && !ValType->isIntegerType() - && !ValType->isPointerType()) { - Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) + // gcc does not enforce these rules for GNU atomics, but we do so for + // sanity. + auto IsAllowedValueType = [&](QualType ValType) { + if (ValType->isIntegerType()) + return true; + if (ValType->isPointerType()) + return true; + if (!ValType->isFloatingType()) + return false; + // LLVM Parser does not allow atomicrmw with x86_fp80 type. + if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return false; + return true; + }; + if (IsAddSub && !IsAllowedValueType(ValType)) { + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_ptr_or_fp) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -5168,7 +5185,9 @@ // passed by address. For the rest, GNU uses by-address and C11 uses // by-value. assert(Form != Load); - if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) + if (Form == Arithmetic && ValType->isPointerType()) + Ty = Context.getPointerDiffType(); + else if (Form == Init || Form == Arithmetic) Ty = ValType; else if (Form == Copy || Form == Xchg) { if (IsPassedByAddress) { @@ -5177,9 +5196,7 @@ ExprRange.getBegin()); } Ty = ByValType; - } else if (Form == Arithmetic) - Ty = Context.getPointerDiffType(); - else { + } else { Expr *ValArg = APIOrderedArgs[i]; // The value pointer is always dereferenced, a nullptr is undefined. CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); diff --git a/clang/test/CodeGen/fp-atomic-ops.c b/clang/test/CodeGen/fp-atomic-ops.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/fp-atomic-ops.c @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 %s -emit-llvm -DDOUBLE -O0 -o - -triple=amdgcn-amd-amdhsa \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT,DOUBLE %s + +// RUN: %clang_cc1 %s -emit-llvm -DDOUBLE -O0 -o - -triple=aarch64-linux-gnu \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT,DOUBLE %s + +// RUN: %clang_cc1 %s -emit-llvm -O0 -o - -triple=armv8-apple-ios7.0 \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT %s + +// RUN: %clang_cc1 %s -emit-llvm -DDOUBLE -O0 -o - -triple=hexagon \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT,DOUBLE %s + +// RUN: %clang_cc1 %s -emit-llvm -DDOUBLE -O0 -o - -triple=mips64-mti-linux-gnu \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT,DOUBLE %s + +// RUN: %clang_cc1 %s -emit-llvm -O0 -o - -triple=i686-linux-gnu \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT %s + +// RUN: %clang_cc1 %s -emit-llvm -DDOUBLE -O0 -o - -triple=x86_64-linux-gnu \ +// RUN: | opt -instnamer -S | FileCheck -check-prefixes=FLOAT,DOUBLE %s + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +void test(float *f, float ff, double *d, double dd) { + // FLOAT: atomicrmw fadd float* {{.*}} monotonic + __atomic_fetch_add(f, ff, memory_order_relaxed); + + // FLOAT: atomicrmw fsub float* {{.*}} monotonic + __atomic_fetch_sub(f, ff, memory_order_relaxed); + +#ifdef DOUBLE + // DOUBLE: atomicrmw fadd double* {{.*}} monotonic + __atomic_fetch_add(d, dd, memory_order_relaxed); + + // DOUBLE: atomicrmw fsub double* {{.*}} monotonic + __atomic_fetch_sub(d, dd, memory_order_relaxed); +#endif +} diff --git a/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=amdgcn-amd-amdhsa \ +// RUN: -fcuda-is-device -target-cpu gfx906 -fnative-half-type \ +// RUN: -fnative-half-arguments-and-returns | FileCheck %s + +// REQUIRES: amdgpu-registered-target + +#include "Inputs/cuda.h" +#include + +__device__ float ffp1(float *p) { + // CHECK-LABEL: @_Z4ffp1Pf + // CHECK: atomicrmw fadd float* {{.*}} monotonic + return __atomic_fetch_add(p, 1.0f, memory_order_relaxed); +} + +__device__ double ffp2(double *p) { + // CHECK-LABEL: @_Z4ffp2Pd + // CHECK: atomicrmw fsub double* {{.*}} monotonic + return __atomic_fetch_sub(p, 1.0, memory_order_relaxed); +} + +// long double is the same as double for amdgcn. +__device__ long double ffp3(long double *p) { + // CHECK-LABEL: @_Z4ffp3Pe + // CHECK: atomicrmw fsub double* {{.*}} monotonic + return __atomic_fetch_sub(p, 1.0L, memory_order_relaxed); +} + +__device__ double ffp4(double *p, float f) { + // CHECK-LABEL: @_Z4ffp4Pdf + // CHECK: fpext float {{.*}} to double + // CHECK: atomicrmw fsub double* {{.*}} monotonic + return __atomic_fetch_sub(p, f, memory_order_relaxed); +} + +__device__ double ffp5(double *p, int i) { + // CHECK-LABEL: @_Z4ffp5Pdi + // CHECK: sitofp i32 {{.*}} to double + // CHECK: atomicrmw fsub double* {{.*}} monotonic + return __atomic_fetch_sub(p, i, memory_order_relaxed); +} diff --git a/clang/test/CodeGenOpenCL/atomic-ops.cl b/clang/test/CodeGenOpenCL/atomic-ops.cl --- a/clang/test/CodeGenOpenCL/atomic-ops.cl +++ b/clang/test/CodeGenOpenCL/atomic-ops.cl @@ -1,12 +1,17 @@ -// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa-amdgizcl | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa \ +// RUN: | opt -instnamer -S | FileCheck %s // Also test serialization of atomic operations here, to avoid duplicating the test. -// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa-amdgizcl -// RUN: %clang_cc1 %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa-amdgizcl -emit-llvm -o - | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa +// RUN: %clang_cc1 %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa \ +// RUN: -emit-llvm -o - | opt -instnamer -S | FileCheck %s #ifndef ALREADY_INCLUDED #define ALREADY_INCLUDED +#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable + typedef __INTPTR_TYPE__ intptr_t; typedef int int8 __attribute__((ext_vector_type(8))); @@ -185,6 +190,18 @@ return __opencl_atomic_exchange(d, 2, memory_order_seq_cst, memory_scope_work_group); } +float ff4(global atomic_float *d, float a) { + // CHECK-LABEL: @ff4 + // CHECK: atomicrmw fadd float addrspace(1)* {{.*}} syncscope("workgroup-one-as") monotonic + return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group); +} + +float ff5(global atomic_double *d, double a) { + // CHECK-LABEL: @ff5 + // CHECK: atomicrmw fadd double addrspace(1)* {{.*}} syncscope("workgroup-one-as") monotonic + return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group); +} + // CHECK-LABEL: @atomic_init_foo void atomic_init_foo() { diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c --- a/clang/test/Sema/atomic-ops.c +++ b/clang/test/Sema/atomic-ops.c @@ -1,4 +1,9 @@ -// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11 +// RUN: %clang_cc1 %s -verify=expected,fp80,noi128 -fgnuc-version=4.2.1 -ffreestanding \ +// RUN: -fsyntax-only -triple=i686-linux-gnu -std=c11 +// RUN: %clang_cc1 %s -verify=expected,noi128 -fgnuc-version=4.2.1 -ffreestanding \ +// RUN: -fsyntax-only -triple=i686-linux-android -std=c11 +// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \ +// RUN: -fsyntax-only -triple=powerpc64-linux-gnu -std=c11 // Basic parsing/Sema tests for __c11_atomic_* @@ -51,7 +56,7 @@ _Static_assert(atomic_is_lock_free((atomic_short*)0), ""); _Static_assert(atomic_is_lock_free((atomic_int*)0), ""); _Static_assert(atomic_is_lock_free((atomic_long*)0), ""); -// expected-error@+1 {{__int128 is not supported on this target}} +// noi128-error@+1 {{__int128 is not supported on this target}} _Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-error {{not an integral constant expression}} _Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), ""); @@ -99,7 +104,8 @@ #define _AS2 __attribute__((address_space(2))) void f(_Atomic(int) *i, const _Atomic(int) *ci, - _Atomic(int*) *p, _Atomic(float) *d, + _Atomic(int*) *p, _Atomic(float) *f, _Atomic(double) *d, + _Atomic(long double) *ld, int *I, const int *CI, int **P, float *D, struct S *s1, struct S *s2) { __c11_atomic_init(I, 5); // expected-error {{pointer to _Atomic}} @@ -114,7 +120,7 @@ __c11_atomic_load(i, memory_order_seq_cst); __c11_atomic_load(p, memory_order_seq_cst); - __c11_atomic_load(d, memory_order_seq_cst); + __c11_atomic_load(f, memory_order_seq_cst); __c11_atomic_load(ci, memory_order_seq_cst); int load_n_1 = __atomic_load_n(I, memory_order_relaxed); @@ -137,7 +143,7 @@ __c11_atomic_store(i, 1, memory_order_seq_cst); __c11_atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}} - (int)__c11_atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}} + (int)__c11_atomic_store(f, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}} __atomic_store_n(I, 4, memory_order_release); __atomic_store_n(I, 4.0, memory_order_release); @@ -166,20 +172,22 @@ __c11_atomic_fetch_add(i, 1, memory_order_seq_cst); __c11_atomic_fetch_add(p, 1, memory_order_seq_cst); - __c11_atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}} + __c11_atomic_fetch_add(f, 1.0f, memory_order_seq_cst); + __c11_atomic_fetch_add(d, 1.0, memory_order_seq_cst); + __c11_atomic_fetch_add(ld, 1.0, memory_order_seq_cst); // fp80-error {{must be a pointer to atomic integer, pointer or supported floating point type}} - __atomic_fetch_add(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer or pointer}} + __atomic_fetch_add(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer, pointer or supported floating point type}} __atomic_fetch_sub(I, 3, memory_order_seq_cst); __atomic_fetch_sub(P, 3, memory_order_seq_cst); - __atomic_fetch_sub(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} - __atomic_fetch_sub(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} + __atomic_fetch_sub(D, 3, memory_order_seq_cst); + __atomic_fetch_sub(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer, pointer or supported floating point type}} __atomic_fetch_min(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer}} __atomic_fetch_max(P, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer}} __atomic_fetch_max(p, 3); // expected-error {{too few arguments to function call, expected 3, have 2}} __c11_atomic_fetch_and(i, 1, memory_order_seq_cst); __c11_atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} - __c11_atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} + __c11_atomic_fetch_and(f, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} __atomic_fetch_and(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer}} __atomic_fetch_or(I, 3, memory_order_seq_cst); @@ -189,12 +197,12 @@ _Bool cmpexch_1 = __c11_atomic_compare_exchange_strong(i, I, 1, memory_order_seq_cst, memory_order_seq_cst); _Bool cmpexch_2 = __c11_atomic_compare_exchange_strong(p, P, (int*)1, memory_order_seq_cst, memory_order_seq_cst); - _Bool cmpexch_3 = __c11_atomic_compare_exchange_strong(d, I, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} + _Bool cmpexch_3 = __c11_atomic_compare_exchange_strong(f, I, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} (void)__c11_atomic_compare_exchange_strong(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}} _Bool cmpexchw_1 = __c11_atomic_compare_exchange_weak(i, I, 1, memory_order_seq_cst, memory_order_seq_cst); _Bool cmpexchw_2 = __c11_atomic_compare_exchange_weak(p, P, (int*)1, memory_order_seq_cst, memory_order_seq_cst); - _Bool cmpexchw_3 = __c11_atomic_compare_exchange_weak(d, I, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} + _Bool cmpexchw_3 = __c11_atomic_compare_exchange_weak(f, I, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}} (void)__c11_atomic_compare_exchange_weak(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{passing 'const int *' to parameter of type 'int *' discards qualifiers}} _Bool cmpexch_4 = __atomic_compare_exchange_n(I, I, 5, 1, memory_order_seq_cst, memory_order_seq_cst); diff --git a/clang/test/SemaOpenCL/atomic-ops.cl b/clang/test/SemaOpenCL/atomic-ops.cl --- a/clang/test/SemaOpenCL/atomic-ops.cl +++ b/clang/test/SemaOpenCL/atomic-ops.cl @@ -1,10 +1,13 @@ -// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only -triple=spir64 -// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only -triple=amdgcn-amdhsa-amd-opencl +// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify=expected,spir \ +// RUN: -fsyntax-only -triple=spir64 +// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only \ +// RUN: -triple=amdgcn-amd-amdhsa // Basic parsing/Sema tests for __opencl_atomic_* #pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable #pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable +#pragma OPENCL EXTENSION cl_khr_fp16 : enable typedef __INTPTR_TYPE__ intptr_t; typedef int int8 __attribute__((ext_vector_type(8))); @@ -36,7 +39,7 @@ atomic_int gn; void f(atomic_int *i, const atomic_int *ci, - atomic_intptr_t *p, atomic_float *d, + atomic_intptr_t *p, atomic_float *f, atomic_double *d, atomic_half *h, // expected-error {{unknown type name 'atomic_half'}} int *I, const int *CI, intptr_t *P, float *D, struct S *s1, struct S *s2, global atomic_int *i_g, local atomic_int *i_l, private atomic_int *i_p, @@ -57,37 +60,38 @@ __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_load(p, memory_order_seq_cst, memory_scope_work_group); - __opencl_atomic_load(d, memory_order_seq_cst, memory_scope_work_group); + __opencl_atomic_load(f, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_load(ci, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_load(i_c, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-constant _Atomic type ('__constant atomic_int *' (aka '__constant _Atomic(int) *') invalid)}} __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_store(p, 1, memory_order_seq_cst, memory_scope_work_group); - (int)__opencl_atomic_store(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{operand of type 'void' where arithmetic or pointer type is required}} + (int)__opencl_atomic_store(f, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{operand of type 'void' where arithmetic or pointer type is required}} int exchange_1 = __opencl_atomic_exchange(i, 1, memory_order_seq_cst, memory_scope_work_group); int exchange_2 = __opencl_atomic_exchange(I, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to _Atomic}} __opencl_atomic_fetch_add(i, 1, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_fetch_add(p, 1, memory_order_seq_cst, memory_scope_work_group); - __opencl_atomic_fetch_add(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer or pointer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} + __opencl_atomic_fetch_add(f, 1.0f, memory_order_seq_cst, memory_scope_work_group); + __opencl_atomic_fetch_add(d, 1.0, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_fetch_and(i, 1, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_fetch_and(p, 1, memory_order_seq_cst, memory_scope_work_group); - __opencl_atomic_fetch_and(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} + __opencl_atomic_fetch_and(f, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} __opencl_atomic_fetch_min(i, 1, memory_order_seq_cst, memory_scope_work_group); __opencl_atomic_fetch_max(i, 1, memory_order_seq_cst, memory_scope_work_group); - __opencl_atomic_fetch_min(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} - __opencl_atomic_fetch_max(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} + __opencl_atomic_fetch_min(f, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} + __opencl_atomic_fetch_max(f, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}} bool cmpexch_1 = __opencl_atomic_compare_exchange_strong(i, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); bool cmpexch_2 = __opencl_atomic_compare_exchange_strong(p, P, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - bool cmpexch_3 = __opencl_atomic_compare_exchange_strong(d, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *__private' to parameter of type '__generic float *'}} + bool cmpexch_3 = __opencl_atomic_compare_exchange_strong(f, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *__private' to parameter of type '__generic float *'}} (void)__opencl_atomic_compare_exchange_strong(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{passing 'const __generic int *__private' to parameter of type '__generic int *' discards qualifiers}} bool cmpexchw_1 = __opencl_atomic_compare_exchange_weak(i, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); bool cmpexchw_2 = __opencl_atomic_compare_exchange_weak(p, P, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - bool cmpexchw_3 = __opencl_atomic_compare_exchange_weak(d, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *__private' to parameter of type '__generic float *'}} + bool cmpexchw_3 = __opencl_atomic_compare_exchange_weak(f, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *__private' to parameter of type '__generic float *'}} (void)__opencl_atomic_compare_exchange_weak(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{passing 'const __generic int *__private' to parameter of type '__generic int *' discards qualifiers}} // Pointers to different address spaces are allowed.