1// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -ffake-address-space-map -triple i686-pc-darwin | FileCheck -enable-var-scope -check-prefixes=COM,X86 %s 2// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN %s 3// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL2.0 -O0 -finclude-default-header -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN,AMDGCN20 %s 4 5typedef struct { 6 int cells[9]; 7} Mat3X3; 8 9typedef struct { 10 int cells[16]; 11} Mat4X4; 12 13typedef struct { 14 int cells[1024]; 15} Mat32X32; 16 17typedef struct { 18 int cells[4096]; 19} Mat64X64; 20 21struct StructOneMember { 22 int2 x; 23}; 24 25struct StructTwoMember { 26 int2 x; 27 int2 y; 28}; 29 30struct LargeStructOneMember { 31 int2 x[100]; 32}; 33 34struct LargeStructTwoMember { 35 int2 x[40]; 36 int2 y[20]; 37}; 38 39#if __OPENCL_C_VERSION__ >= 200 40struct LargeStructOneMember g_s; 41#endif 42 43// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret %agg.result, %struct.Mat3X3* byval align 4 %in) 44// AMDGCN-LABEL: define %struct.Mat4X4 @foo([9 x i32] %in.coerce) 45Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) { 46 Mat4X4 out; 47 return out; 48} 49 50// COM-LABEL: define {{.*}} void @ker 51// Expect two mem copies: one for the argument "in", and one for 52// the return value. 53// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8* 54// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* 55 56// AMDGCN: load [9 x i32], [9 x i32] addrspace(1)* 57// AMDGCN: call %struct.Mat4X4 @foo([9 x i32] 58// AMDGCN: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)* 59kernel void ker(global Mat3X3 *in, global Mat4X4 *out) { 60 out[0] = foo(in[1]); 61} 62 63// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret %agg.result, %struct.Mat32X32* byval align 4 %in) 64// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret %agg.result, %struct.Mat32X32 addrspace(5)* byval align 4 %in) 65Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) { 66 Mat64X64 out; 67 return out; 68} 69 70// COM-LABEL: define {{.*}} void @ker_large 71// Expect two mem copies: one for the argument "in", and one for 72// the return value. 73// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8* 74// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* 75// AMDGCN: call void @llvm.memcpy.p5i8.p1i8.i64(i8 addrspace(5)* 76// AMDGCN: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)* 77kernel void ker_large(global Mat32X32 *in, global Mat64X64 *out) { 78 out[0] = foo_large(in[1]); 79} 80 81// AMDGCN-LABEL: define void @FuncOneMember(<2 x i32> %u.coerce) 82void FuncOneMember(struct StructOneMember u) { 83 u.x = (int2)(0, 0); 84} 85 86// AMDGCN-LABEL: define void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %u) 87// AMDGCN-NOT: addrspacecast 88// AMDGCN: store <2 x i32> %{{.*}}, <2 x i32> addrspace(5)* 89void FuncOneLargeMember(struct LargeStructOneMember u) { 90 u.x[0] = (int2)(0, 0); 91} 92 93// AMDGCN20-LABEL: define void @test_indirect_arg_globl() 94// AMDGCN20: %[[byval_temp:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5) 95// AMDGCN20: %[[r0:.*]] = bitcast %struct.LargeStructOneMember addrspace(5)* %[[byval_temp]] to i8 addrspace(5)* 96// AMDGCN20: call void @llvm.memcpy.p5i8.p1i8.i64(i8 addrspace(5)* align 8 %[[r0]], i8 addrspace(1)* align 8 bitcast (%struct.LargeStructOneMember addrspace(1)* @g_s to i8 addrspace(1)*), i64 800, i1 false) 97// AMDGCN20: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[byval_temp]]) 98#if __OPENCL_C_VERSION__ >= 200 99void test_indirect_arg_globl(void) { 100 FuncOneLargeMember(g_s); 101} 102#endif 103 104// AMDGCN-LABEL: define amdgpu_kernel void @test_indirect_arg_local() 105// AMDGCN: %[[byval_temp:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5) 106// AMDGCN: %[[r0:.*]] = bitcast %struct.LargeStructOneMember addrspace(5)* %[[byval_temp]] to i8 addrspace(5)* 107// AMDGCN: call void @llvm.memcpy.p5i8.p3i8.i64(i8 addrspace(5)* align 8 %[[r0]], i8 addrspace(3)* align 8 bitcast (%struct.LargeStructOneMember addrspace(3)* @test_indirect_arg_local.l_s to i8 addrspace(3)*), i64 800, i1 false) 108// AMDGCN: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[byval_temp]]) 109kernel void test_indirect_arg_local(void) { 110 local struct LargeStructOneMember l_s; 111 FuncOneLargeMember(l_s); 112} 113 114// AMDGCN-LABEL: define void @test_indirect_arg_private() 115// AMDGCN: %[[p_s:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5) 116// AMDGCN-NOT: @llvm.memcpy 117// AMDGCN-NEXT: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[p_s]]) 118void test_indirect_arg_private(void) { 119 struct LargeStructOneMember p_s; 120 FuncOneLargeMember(p_s); 121} 122 123// AMDGCN-LABEL: define amdgpu_kernel void @KernelOneMember 124// AMDGCN-SAME: (<2 x i32> %[[u_coerce:.*]]) 125// AMDGCN: %[[u:.*]] = alloca %struct.StructOneMember, align 8, addrspace(5) 126// AMDGCN: %[[coerce_dive:.*]] = getelementptr inbounds %struct.StructOneMember, %struct.StructOneMember addrspace(5)* %[[u]], i32 0, i32 0 127// AMDGCN: store <2 x i32> %[[u_coerce]], <2 x i32> addrspace(5)* %[[coerce_dive]] 128// AMDGCN: call void @FuncOneMember(<2 x i32> 129kernel void KernelOneMember(struct StructOneMember u) { 130 FuncOneMember(u); 131} 132 133// AMDGCN-LABEL: define amdgpu_kernel void @KernelLargeOneMember( 134// AMDGCN: %[[U:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5) 135// AMDGCN: store %struct.LargeStructOneMember %u.coerce, %struct.LargeStructOneMember addrspace(5)* %[[U]], align 8 136// AMDGCN: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[U]]) 137kernel void KernelLargeOneMember(struct LargeStructOneMember u) { 138 FuncOneLargeMember(u); 139} 140 141// AMDGCN-LABEL: define void @FuncTwoMember(<2 x i32> %u.coerce0, <2 x i32> %u.coerce1) 142void FuncTwoMember(struct StructTwoMember u) { 143 u.y = (int2)(0, 0); 144} 145 146// AMDGCN-LABEL: define void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %u) 147void FuncLargeTwoMember(struct LargeStructTwoMember u) { 148 u.y[0] = (int2)(0, 0); 149} 150 151// AMDGCN-LABEL: define amdgpu_kernel void @KernelTwoMember 152// AMDGCN-SAME: (%struct.StructTwoMember %[[u_coerce:.*]]) 153// AMDGCN: %[[u:.*]] = alloca %struct.StructTwoMember, align 8, addrspace(5) 154// AMDGCN: %[[LD0:.*]] = load <2 x i32>, <2 x i32> addrspace(5)* 155// AMDGCN: %[[LD1:.*]] = load <2 x i32>, <2 x i32> addrspace(5)* 156// AMDGCN: call void @FuncTwoMember(<2 x i32> %[[LD0]], <2 x i32> %[[LD1]]) 157kernel void KernelTwoMember(struct StructTwoMember u) { 158 FuncTwoMember(u); 159} 160 161// AMDGCN-LABEL: define amdgpu_kernel void @KernelLargeTwoMember 162// AMDGCN-SAME: (%struct.LargeStructTwoMember %[[u_coerce:.*]]) 163// AMDGCN: %[[u:.*]] = alloca %struct.LargeStructTwoMember, align 8, addrspace(5) 164// AMDGCN: store %struct.LargeStructTwoMember %[[u_coerce]], %struct.LargeStructTwoMember addrspace(5)* %[[u]] 165// AMDGCN: call void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %[[u]]) 166kernel void KernelLargeTwoMember(struct LargeStructTwoMember u) { 167 FuncLargeTwoMember(u); 168} 169