| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --functions ".*" --include-generated-funcs --version 6 | |
| // RUN: %clang_cc1 -triple amdgpu-amd-amdhsa -emit-llvm -O1 -x c++ -std=c++2b %s -o - | FileCheck --check-prefix=AMDGCN %s | |
| // RUN: %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm -O1 -x c++ -std=c++2b %s -o - | FileCheck --check-prefix=SPIRV %s | |
| // REQUIRES: amdgpu-registered-target | |
| // Verify that lifetime markers for an sret temporary use the alloca address | |
| // space (5), even when the sret pointer itself is in the default address | |
| // space (0). Regression test for an assertion failure in EmitLifetimeEnd | |
| // when the return value of a function returning a non-trivially-copyable | |
| // type is discarded. | |
| template <int N> | |
| struct SuperScalar { | |
| double val[N]; | |
| SuperScalar() { | |
| for (int i = 0; i < N; i++) val[i] = 0.0; | |
| } | |
| SuperScalar(const SuperScalar& rhs) { | |
| for (int i = 0; i < N; i++) val[i] = rhs.val[i]; | |
| } | |
| SuperScalar& operator=(const SuperScalar& rhs) { | |
| for (int i = 0; i < N; i++) val[i] = rhs.val[i]; | |
| return *this; | |
| } | |
| }; | |
| template <int N> | |
| SuperScalar<N> atomic_fetch_add(SuperScalar<N>* dest, const SuperScalar<N>& val); | |
| template <int N> | |
| void add_functor(SuperScalar<N>* data, int i, SuperScalar<N>& update) { | |
| atomic_fetch_add(&data[i], update); | |
| } | |
| template void add_functor<4>(SuperScalar<4>*, int, SuperScalar<4>&); | |
| // AMDGCN-LABEL: define weak_odr void @_Z11add_functorILi4EEvP11SuperScalarIXT_EEiRS1_( | |
| // AMDGCN-SAME: ptr noundef [[DATA:%.*]], i32 noundef [[I:%.*]], ptr noundef nonnull align 8 dereferenceable(32) [[UPDATE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] comdat { | |
| // AMDGCN-NEXT: [[ENTRY:.*:]] | |
| // AMDGCN-NEXT: [[TMP:%.*]] = alloca [[STRUCT_SUPERSCALAR:%.*]], align 8, addrspace(5) | |
| // AMDGCN-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 | |
| // AMDGCN-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr [[DATA]], i64 [[IDXPROM]] | |
| // AMDGCN-NEXT: call void @llvm.lifetime.start.p5(ptr addrspace(5) [[TMP]]) #[[ATTR3:[0-9]+]] | |
| // AMDGCN-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr | |
| // AMDGCN-NEXT: call void @_Z16atomic_fetch_addILi4EE11SuperScalarIXT_EEPS1_RKS1_(ptr dead_on_unwind writable sret([[STRUCT_SUPERSCALAR]]) align 8 [[TMP_ASCAST]], ptr noundef [[ARRAYIDX]], ptr noundef nonnull align 8 dereferenceable(32) [[UPDATE]]) #[[ATTR4:[0-9]+]] | |
| // AMDGCN-NEXT: call void @llvm.lifetime.end.p5(ptr addrspace(5) [[TMP]]) #[[ATTR3]] | |
| // AMDGCN-NEXT: ret void | |
| // | |
| // | |
| // SPIRV-LABEL: define weak_odr spir_func void @_Z11add_functorILi4EEvP11SuperScalarIXT_EEiRS1_( | |
| // SPIRV-SAME: ptr addrspace(4) noundef [[DATA:%.*]], i32 noundef [[I:%.*]], ptr addrspace(4) noundef align 8 dereferenceable(32) [[UPDATE:%.*]]) local_unnamed_addr addrspace(4) #[[ATTR0:[0-9]+]] comdat { | |
| // SPIRV-NEXT: [[ENTRY:.*:]] | |
| // SPIRV-NEXT: [[TMP:%.*]] = alloca [[STRUCT_SUPERSCALAR:%.*]], align 8 | |
| // SPIRV-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 | |
| // SPIRV-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr addrspace(4) [[DATA]], i64 [[IDXPROM]] | |
| // SPIRV-NEXT: call addrspace(4) void @llvm.lifetime.start.p0(ptr nonnull [[TMP]]) #[[ATTR3:[0-9]+]] | |
| // SPIRV-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr [[TMP]] to ptr addrspace(4) | |
| // SPIRV-NEXT: call spir_func addrspace(4) void @_Z16atomic_fetch_addILi4EE11SuperScalarIXT_EEPS1_RKS1_(ptr addrspace(4) dead_on_unwind writable sret([[STRUCT_SUPERSCALAR]]) align 8 [[TMP_ASCAST]], ptr addrspace(4) noundef [[ARRAYIDX]], ptr addrspace(4) noundef align 8 dereferenceable(32) [[UPDATE]]) #[[ATTR3]] | |
| // SPIRV-NEXT: call addrspace(4) void @llvm.lifetime.end.p0(ptr nonnull [[TMP]]) #[[ATTR3]] | |
| // SPIRV-NEXT: ret void | |
| // |