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