xref: /llvm-project/clang/test/CodeGenOpenCL/atomic-ops.cl (revision 6e0b0038cd65ce726ce404305a06e1cf33e36cca)
1// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa \
2// RUN:   | FileCheck %s
3
4// Also test serialization of atomic operations here, to avoid duplicating the test.
5// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa
6// RUN: %clang_cc1 %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa \
7// RUN:   -emit-llvm -o - | FileCheck %s
8
9#ifndef ALREADY_INCLUDED
10#define ALREADY_INCLUDED
11
12#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
13#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable
14
15typedef __INTPTR_TYPE__ intptr_t;
16typedef int int8 __attribute__((ext_vector_type(8)));
17
18typedef enum memory_order {
19  memory_order_relaxed = __ATOMIC_RELAXED,
20  memory_order_acquire = __ATOMIC_ACQUIRE,
21  memory_order_release = __ATOMIC_RELEASE,
22  memory_order_acq_rel = __ATOMIC_ACQ_REL,
23  memory_order_seq_cst = __ATOMIC_SEQ_CST
24} memory_order;
25
26typedef enum memory_scope {
27  memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
28  memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP,
29  memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE,
30  memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES,
31#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups)
32  memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP
33#endif
34} memory_scope;
35
36atomic_int j;
37
38void fi1(atomic_int *i) {
39  // CHECK-LABEL: @fi1
40  // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4{{$}}
41  int x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
42
43  // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("agent") seq_cst, align 4{{$}}
44  x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_device);
45
46  // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} seq_cst, align 4{{$}}
47  x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_all_svm_devices);
48
49  // CHECK: load atomic i32, ptr %{{[.0-9A-Z_a-z]+}} syncscope("wavefront") seq_cst, align 4{{$}}
50  x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_sub_group);
51}
52
53void fi2(atomic_int *i) {
54  // CHECK-LABEL: @fi2
55  // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4{{$}}
56  __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group);
57}
58
59void test_addr(global atomic_int *ig, private atomic_int *ip, local atomic_int *il) {
60  // CHECK-LABEL: @test_addr
61  // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(1) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4{{$}}
62  __opencl_atomic_store(ig, 1, memory_order_seq_cst, memory_scope_work_group);
63
64  // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(5) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4{{$}}
65  __opencl_atomic_store(ip, 1, memory_order_seq_cst, memory_scope_work_group);
66
67  // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, ptr addrspace(3) %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4{{$}}
68  __opencl_atomic_store(il, 1, memory_order_seq_cst, memory_scope_work_group);
69}
70
71void fi3(atomic_int *i, atomic_uint *ui) {
72  // CHECK-LABEL: @fi3
73  // CHECK: atomicrmw and ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE:![0-9]+]]{{$}}
74  int x = __opencl_atomic_fetch_and(i, 1, memory_order_seq_cst, memory_scope_work_group);
75
76  // CHECK: atomicrmw min ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
77  x = __opencl_atomic_fetch_min(i, 1, memory_order_seq_cst, memory_scope_work_group);
78
79  // CHECK: atomicrmw max ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
80  x = __opencl_atomic_fetch_max(i, 1, memory_order_seq_cst, memory_scope_work_group);
81
82  // CHECK: atomicrmw umin ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
83  x = __opencl_atomic_fetch_min(ui, 1, memory_order_seq_cst, memory_scope_work_group);
84
85  // CHECK: atomicrmw umax ptr %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
86  x = __opencl_atomic_fetch_max(ui, 1, memory_order_seq_cst, memory_scope_work_group);
87}
88
89bool fi4(atomic_int *i) {
90  // CHECK-LABEL: @fi4(
91  // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg ptr [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] syncscope("workgroup-one-as") acquire acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
92  // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
93  // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
94  // CHECK: br i1 [[CMP]], label %[[STORE_EXPECTED:[.0-9A-Z_a-z]+]], label %[[CONTINUE:[.0-9A-Z_a-z]+]]
95  // CHECK: store i32 [[OLD]]
96  int cmp = 0;
97  return __opencl_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire, memory_scope_work_group);
98}
99
100void fi5(atomic_int *i, int scope) {
101  // CHECK-LABEL: @fi5
102  // CHECK: switch i32 %{{.*}}, label %[[opencl_allsvmdevices:.*]] [
103  // CHECK-NEXT: i32 1, label %[[opencl_workgroup:.*]]
104  // CHECK-NEXT: i32 2, label %[[opencl_device:.*]]
105  // CHECK-NEXT: i32 4, label %[[opencl_subgroup:.*]]
106  // CHECK-NEXT: ]
107  // CHECK: [[opencl_workgroup]]:
108  // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup") seq_cst, align 4{{$}}
109  // CHECK: br label %[[continue:.*]]
110  // CHECK: [[opencl_device]]:
111  // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent") seq_cst, align 4{{$}}
112  // CHECK: br label %[[continue]]
113  // CHECK: [[opencl_allsvmdevices]]:
114  // CHECK: load atomic i32, ptr %{{.*}} seq_cst, align 4
115  // CHECK: br label %[[continue]]
116  // CHECK: [[opencl_subgroup]]:
117  // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront") seq_cst, align 4{{$}}
118  // CHECK: br label %[[continue]]
119  // CHECK: [[continue]]:
120  int x = __opencl_atomic_load(i, memory_order_seq_cst, scope);
121}
122
123void fi6(atomic_int *i, int order, int scope) {
124  // CHECK-LABEL: @fi6
125  // CHECK: switch i32 %{{.*}}, label %[[monotonic:.*]] [
126  // CHECK-NEXT: i32 1, label %[[acquire:.*]]
127  // CHECK-NEXT: i32 2, label %[[acquire:.*]]
128  // CHECK-NEXT: i32 5, label %[[seqcst:.*]]
129  // CHECK-NEXT: ]
130  // CHECK: [[monotonic]]:
131  // CHECK: switch i32 %{{.*}}, label %[[MON_ALL:.*]] [
132  // CHECK-NEXT: i32 1, label %[[MON_WG:.*]]
133  // CHECK-NEXT: i32 2, label %[[MON_DEV:.*]]
134  // CHECK-NEXT: i32 4, label %[[MON_SUB:.*]]
135  // CHECK-NEXT: ]
136  // CHECK: [[acquire]]:
137  // CHECK: switch i32 %{{.*}}, label %[[ACQ_ALL:.*]] [
138  // CHECK-NEXT: i32 1, label %[[ACQ_WG:.*]]
139  // CHECK-NEXT: i32 2, label %[[ACQ_DEV:.*]]
140  // CHECK-NEXT: i32 4, label %[[ACQ_SUB:.*]]
141  // CHECK-NEXT: ]
142  // CHECK: [[seqcst]]:
143  // CHECK: switch i32 %{{.*}}, label %[[SEQ_ALL:.*]] [
144  // CHECK-NEXT: i32 1, label %[[SEQ_WG:.*]]
145  // CHECK-NEXT: i32 2, label %[[SEQ_DEV:.*]]
146  // CHECK-NEXT: i32 4, label %[[SEQ_SUB:.*]]
147  // CHECK-NEXT: ]
148  // CHECK: [[MON_WG]]:
149  // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup-one-as") monotonic, align 4{{$}}
150  // CHECK: [[MON_DEV]]:
151  // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent-one-as") monotonic, align 4{{$}}
152  // CHECK: [[MON_ALL]]:
153  // CHECK: load atomic i32, ptr %{{.*}} monotonic, align 4{{$}}
154  // CHECK: [[MON_SUB]]:
155  // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront-one-as") monotonic, align 4{{$}}
156  // CHECK: [[ACQ_WG]]:
157  // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup-one-as") acquire, align 4{{$}}
158  // CHECK: [[ACQ_DEV]]:
159  // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent-one-as") acquire, align 4{{$}}
160  // CHECK: [[ACQ_ALL]]:
161  // CHECK: load atomic i32, ptr %{{.*}} acquire, align 4{{$}}
162  // CHECK: [[ACQ_SUB]]:
163  // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront-one-as") acquire, align 4{{$}}
164  // CHECK: [[SEQ_WG]]:
165  // CHECK: load atomic i32, ptr %{{.*}} syncscope("workgroup") seq_cst, align 4{{$}}
166  // CHECK: [[SEQ_DEV]]:
167  // CHECK: load atomic i32, ptr %{{.*}} syncscope("agent") seq_cst, align 4{{$}}
168  // CHECK: [[SEQ_ALL]]:
169  // CHECK: load atomic i32, ptr %{{.*}} seq_cst, align 4{{$}}
170  // CHECK: [[SEQ_SUB]]:
171  // CHECK: load atomic i32, ptr %{{.*}} syncscope("wavefront") seq_cst, align 4{{$}}
172  int x = __opencl_atomic_load(i, order, scope);
173}
174
175float ff1(global atomic_float *d) {
176  // CHECK-LABEL: @ff1
177  // CHECK: load atomic i32, ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic, align 4{{$}}
178  return __opencl_atomic_load(d, memory_order_relaxed, memory_scope_work_group);
179}
180
181void ff2(atomic_float *d) {
182  // CHECK-LABEL: @ff2
183  // CHECK: store atomic i32 {{.*}} syncscope("workgroup-one-as") release, align 4
184  __opencl_atomic_store(d, 1, memory_order_release, memory_scope_work_group);
185}
186
187float ff3(atomic_float *d) {
188  // CHECK-LABEL: @ff3
189  // CHECK: atomicrmw xchg ptr {{.*}} syncscope("workgroup") seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
190  return __opencl_atomic_exchange(d, 2, memory_order_seq_cst, memory_scope_work_group);
191}
192
193float ff4(global atomic_float *d, float a) {
194  // CHECK-LABEL: @ff4
195  // CHECK: atomicrmw fadd ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic, align 4{{$}}
196  return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group);
197}
198
199float ff5(global atomic_double *d, double a) {
200  // CHECK-LABEL: @ff5
201  // CHECK: atomicrmw fadd ptr addrspace(1) {{.*}} syncscope("workgroup-one-as") monotonic, align 8{{$}}
202  return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group);
203}
204
205float ff4_generic(atomic_float *d, float a) {
206  // CHECK-LABEL: @ff4_generic
207  // CHECK: atomicrmw fadd ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
208  return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group);
209}
210
211float ff5_generic(atomic_double *d, double a) {
212  // CHECK-LABEL: @ff5_generic
213  // CHECK: atomicrmw fadd ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 8, !noalias.addrspace [[$NOPRIVATE]]{{$}}
214  return __opencl_atomic_fetch_add(d, a, memory_order_relaxed, memory_scope_work_group);
215}
216
217// CHECK-LABEL: @atomic_init_foo
218void atomic_init_foo()
219{
220  // CHECK-NOT: atomic
221  // CHECK: store
222  __opencl_atomic_init(&j, 42);
223
224  // CHECK-NOT: atomic
225  // CHECK: }
226}
227
228// CHECK-LABEL: @failureOrder
229void failureOrder(atomic_int *ptr, int *ptr2) {
230  // CHECK: cmpxchg ptr {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup-one-as") acquire monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
231  __opencl_atomic_compare_exchange_strong(ptr, ptr2, 43, memory_order_acquire, memory_order_relaxed, memory_scope_work_group);
232
233  // CHECK: cmpxchg weak ptr {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup") seq_cst acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
234  __opencl_atomic_compare_exchange_weak(ptr, ptr2, 43, memory_order_seq_cst, memory_order_acquire, memory_scope_work_group);
235}
236
237// CHECK-LABEL: @generalFailureOrder
238void generalFailureOrder(atomic_int *ptr, int *ptr2, int success, int fail) {
239  __opencl_atomic_compare_exchange_strong(ptr, ptr2, 42, success, fail, memory_scope_work_group);
240// CHECK: switch i32 {{.*}}, label %[[MONOTONIC:[0-9a-zA-Z._]+]] [
241  // CHECK-NEXT: i32 1, label %[[ACQUIRE:[0-9a-zA-Z._]+]]
242  // CHECK-NEXT: i32 2, label %[[ACQUIRE]]
243  // CHECK-NEXT: i32 3, label %[[RELEASE:[0-9a-zA-Z._]+]]
244  // CHECK-NEXT: i32 4, label %[[ACQREL:[0-9a-zA-Z._]+]]
245  // CHECK-NEXT: i32 5, label %[[SEQCST:[0-9a-zA-Z._]+]]
246
247  // CHECK: [[MONOTONIC]]
248  // CHECK: switch {{.*}}, label %[[MONOTONIC_MONOTONIC:[0-9a-zA-Z._]+]] [
249  // CHECK-NEXT: i32 1, label %[[MONOTONIC_ACQUIRE:[0-9a-zA-Z._]+]]
250  // CHECK-NEXT: i32 2, label %[[MONOTONIC_ACQUIRE:[0-9a-zA-Z._]+]]
251  // CHECK-NEXT: i32 5, label %[[MONOTONIC_SEQCST:[0-9a-zA-Z._]+]]
252  // CHECK-NEXT: ]
253
254  // CHECK: [[ACQUIRE]]
255  // CHECK: switch {{.*}}, label %[[ACQUIRE_MONOTONIC:[0-9a-zA-Z._]+]] [
256  // CHECK-NEXT: i32 1, label %[[ACQUIRE_ACQUIRE:[0-9a-zA-Z._]+]]
257  // CHECK-NEXT: i32 2, label %[[ACQUIRE_ACQUIRE:[0-9a-zA-Z._]+]]
258  // CHECK-NEXT: i32 5, label %[[ACQUIRE_SEQCST:[0-9a-zA-Z._]+]]
259  // CHECK-NEXT: ]
260
261  // CHECK: [[RELEASE]]
262  // CHECK: switch {{.*}}, label %[[RELEASE_MONOTONIC:[0-9a-zA-Z._]+]] [
263  // CHECK-NEXT: i32 1, label %[[RELEASE_ACQUIRE:[0-9a-zA-Z._]+]]
264  // CHECK-NEXT: i32 2, label %[[RELEASE_ACQUIRE:[0-9a-zA-Z._]+]]
265  // CHECK-NEXT: i32 5, label %[[RELEASE_SEQCST:[0-9a-zA-Z._]+]]
266  // CHECK-NEXT: ]
267
268  // CHECK: [[ACQREL]]
269  // CHECK: switch {{.*}}, label %[[ACQREL_MONOTONIC:[0-9a-zA-Z._]+]] [
270  // CHECK-NEXT: i32 1, label %[[ACQREL_ACQUIRE:[0-9a-zA-Z._]+]]
271  // CHECK-NEXT: i32 2, label %[[ACQREL_ACQUIRE:[0-9a-zA-Z._]+]]
272  // CHECK-NEXT: i32 5, label %[[ACQREL_SEQCST:[0-9a-zA-Z._]+]]
273  // CHECK-NEXT: ]
274
275  // CHECK: [[SEQCST]]
276  // CHECK: switch {{.*}}, label %[[SEQCST_MONOTONIC:[0-9a-zA-Z._]+]] [
277  // CHECK-NEXT: i32 1, label %[[SEQCST_ACQUIRE:[0-9a-zA-Z._]+]]
278  // CHECK-NEXT: i32 2, label %[[SEQCST_ACQUIRE]]
279  // CHECK-NEXT: i32 5, label %[[SEQCST_SEQCST:[0-9a-zA-Z._]+]]
280  // CHECK-NEXT: ]
281
282  // CHECK: [[MONOTONIC_MONOTONIC]]
283  // CHECK: cmpxchg {{.*}} monotonic monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
284  // CHECK: br
285
286  // CHECK: [[MONOTONIC_ACQUIRE]]
287  // CHECK: cmpxchg {{.*}} monotonic acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
288  // CHECK: br
289
290  // CHECK: [[MONOTONIC_SEQCST]]
291  // CHECK: cmpxchg {{.*}} monotonic seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
292  // CHECK: br
293
294  // CHECK: [[ACQUIRE_MONOTONIC]]
295  // CHECK: cmpxchg {{.*}} acquire monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
296  // CHECK: br
297
298  // CHECK: [[ACQUIRE_ACQUIRE]]
299  // CHECK: cmpxchg {{.*}} acquire acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
300  // CHECK: br
301
302  // CHECK: [[ACQUIRE_SEQCST]]
303  // CHECK: cmpxchg {{.*}} acquire seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
304  // CHECK: br
305
306  // CHECK: [[RELEASE_MONOTONIC]]
307  // CHECK: cmpxchg {{.*}} release monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
308  // CHECK: br
309
310  // CHECK: [[RELEASE_ACQUIRE]]
311  // CHECK: cmpxchg {{.*}} release acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
312  // CHECK: br
313
314  // CHECK: [[RELEASE_SEQCST]]
315  // CHECK: cmpxchg {{.*}} release seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
316  // CHECK: br
317
318  // CHECK: [[ACQREL_MONOTONIC]]
319  // CHECK: cmpxchg {{.*}} acq_rel monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
320  // CHECK: br
321
322  // CHECK: [[ACQREL_ACQUIRE]]
323  // CHECK: cmpxchg {{.*}} acq_rel acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
324  // CHECK: br
325
326  // CHECK: [[ACQREL_SEQCST]]
327  // CHECK: cmpxchg {{.*}} acq_rel seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
328  // CHECK: br
329
330  // CHECK: [[SEQCST_MONOTONIC]]
331  // CHECK: cmpxchg {{.*}} seq_cst monotonic, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
332  // CHECK: br
333
334  // CHECK: [[SEQCST_ACQUIRE]]
335  // CHECK: cmpxchg {{.*}} seq_cst acquire, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
336  // CHECK: br
337
338  // CHECK: [[SEQCST_SEQCST]]
339  // CHECK: cmpxchg {{.*}} seq_cst seq_cst, align 4, !noalias.addrspace [[$NOPRIVATE]]{{$}}
340  // CHECK: br
341}
342
343int test_volatile(volatile atomic_int *i) {
344  // CHECK-LABEL: @test_volatile
345  // CHECK:      %[[i_addr:.*]] = alloca ptr
346  // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32
347  // CHECK-NEXT: %[[retval_ascast:.*]] = addrspacecast ptr addrspace(5) {{.*}} to ptr
348  // CHECK-NEXT: %[[i_addr_ascast:.*]] = addrspacecast ptr addrspace(5) %[[i_addr]] to ptr
349  // CHECK-NEXT: %[[atomicdst_ascast:.*]] = addrspacecast ptr addrspace(5) %[[atomicdst]] to ptr
350  // CHECK-NEXT: store ptr %i, ptr %[[i_addr_ascast]]
351  // CHECK-NEXT: %[[addr:.*]] = load ptr, ptr %[[i_addr_ascast]]
352  // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32, ptr %[[addr]] syncscope("workgroup") seq_cst, align 4{{$}}
353  // CHECK-NEXT: store i32 %[[res]], ptr %[[atomicdst_ascast]]
354  // CHECK-NEXT: %[[retval:.*]] = load i32, ptr %[[atomicdst_ascast]]
355  // CHECK-NEXT: ret i32 %[[retval]]
356  return __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
357}
358
359#endif
360
361// CHECK: [[$NOPRIVATE]] = !{i32 5, i32 6}
362