Add AArch64 as an experimental target.
[oota-llvm.git] / test / CodeGen / AArch64 / atomic-ops.ll
1 ; RUN: llc -march=aarch64 -verify-machineinstrs < %s | FileCheck %s
2
3 @var8 = global i8 0
4 @var16 = global i16 0
5 @var32 = global i32 0
6 @var64 = global i64 0
7
8 define i8 @test_atomic_load_add_i8(i8 %offset) nounwind {
9 ; CHECK: test_atomic_load_add_i8:
10    %old = atomicrmw add i8* @var8, i8 %offset seq_cst
11 ; CHECK: dmb ish
12 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
13 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
14
15 ; CHECK: .LBB{{[0-9]+}}_1:
16 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
17   ; w0 below is a reasonable guess but could change: it certainly comes into the
18   ;  function there.
19 ; CHECK-NEXT: add [[NEW:w[0-9]+]], w[[OLD]], w0
20 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
21 ; CHECK-NEXT: cmp [[STATUS]], #0
22 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
23 ; CHECK: dmb ish
24
25 ; CHECK: mov x0, x[[OLD]]
26    ret i8 %old
27 }
28
29 define i16 @test_atomic_load_add_i16(i16 %offset) nounwind {
30 ; CHECK: test_atomic_load_add_i16:
31    %old = atomicrmw add i16* @var16, i16 %offset seq_cst
32 ; CHECK: dmb ish
33 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
34 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
35
36 ; CHECK: .LBB{{[0-9]+}}_1:
37 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
38   ; w0 below is a reasonable guess but could change: it certainly comes into the
39   ;  function there.
40 ; CHECK-NEXT: add [[NEW:w[0-9]+]], w[[OLD]], w0
41 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
42 ; CHECK-NEXT: cmp [[STATUS]], #0
43 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
44 ; CHECK: dmb ish
45
46 ; CHECK: mov x0, x[[OLD]]
47    ret i16 %old
48 }
49
50 define i32 @test_atomic_load_add_i32(i32 %offset) nounwind {
51 ; CHECK: test_atomic_load_add_i32:
52    %old = atomicrmw add i32* @var32, i32 %offset seq_cst
53 ; CHECK: dmb ish
54 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
55 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
56
57 ; CHECK: .LBB{{[0-9]+}}_1:
58 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
59   ; w0 below is a reasonable guess but could change: it certainly comes into the
60   ;  function there.
61 ; CHECK-NEXT: add [[NEW:w[0-9]+]], w[[OLD]], w0
62 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
63 ; CHECK-NEXT: cmp [[STATUS]], #0
64 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
65 ; CHECK: dmb ish
66
67 ; CHECK: mov x0, x[[OLD]]
68    ret i32 %old
69 }
70
71 define i64 @test_atomic_load_add_i64(i64 %offset) nounwind {
72 ; CHECK: test_atomic_load_add_i64:
73    %old = atomicrmw add i64* @var64, i64 %offset seq_cst
74 ; CHECK: dmb ish
75 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
76 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
77
78 ; CHECK: .LBB{{[0-9]+}}_1:
79 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
80   ; x0 below is a reasonable guess but could change: it certainly comes into the
81   ; function there.
82 ; CHECK-NEXT: add [[NEW:x[0-9]+]], x[[OLD]], x0
83 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
84 ; CHECK-NEXT: cmp [[STATUS]], #0
85 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
86 ; CHECK: dmb ish
87
88 ; CHECK: mov x0, x[[OLD]]
89    ret i64 %old
90 }
91
92 define i8 @test_atomic_load_sub_i8(i8 %offset) nounwind {
93 ; CHECK: test_atomic_load_sub_i8:
94    %old = atomicrmw sub i8* @var8, i8 %offset seq_cst
95 ; CHECK: dmb ish
96 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
97 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
98
99 ; CHECK: .LBB{{[0-9]+}}_1:
100 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
101   ; w0 below is a reasonable guess but could change: it certainly comes into the
102   ;  function there.
103 ; CHECK-NEXT: sub [[NEW:w[0-9]+]], w[[OLD]], w0
104 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
105 ; CHECK-NEXT: cmp [[STATUS]], #0
106 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
107 ; CHECK: dmb ish
108
109 ; CHECK: mov x0, x[[OLD]]
110    ret i8 %old
111 }
112
113 define i16 @test_atomic_load_sub_i16(i16 %offset) nounwind {
114 ; CHECK: test_atomic_load_sub_i16:
115    %old = atomicrmw sub i16* @var16, i16 %offset seq_cst
116 ; CHECK: dmb ish
117 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
118 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
119
120 ; CHECK: .LBB{{[0-9]+}}_1:
121 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
122   ; w0 below is a reasonable guess but could change: it certainly comes into the
123   ;  function there.
124 ; CHECK-NEXT: sub [[NEW:w[0-9]+]], w[[OLD]], w0
125 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
126 ; CHECK-NEXT: cmp [[STATUS]], #0
127 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
128 ; CHECK: dmb ish
129
130 ; CHECK: mov x0, x[[OLD]]
131    ret i16 %old
132 }
133
134 define i32 @test_atomic_load_sub_i32(i32 %offset) nounwind {
135 ; CHECK: test_atomic_load_sub_i32:
136    %old = atomicrmw sub i32* @var32, i32 %offset seq_cst
137 ; CHECK: dmb ish
138 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
139 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
140
141 ; CHECK: .LBB{{[0-9]+}}_1:
142 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
143   ; w0 below is a reasonable guess but could change: it certainly comes into the
144   ;  function there.
145 ; CHECK-NEXT: sub [[NEW:w[0-9]+]], w[[OLD]], w0
146 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
147 ; CHECK-NEXT: cmp [[STATUS]], #0
148 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
149 ; CHECK: dmb ish
150
151 ; CHECK: mov x0, x[[OLD]]
152    ret i32 %old
153 }
154
155 define i64 @test_atomic_load_sub_i64(i64 %offset) nounwind {
156 ; CHECK: test_atomic_load_sub_i64:
157    %old = atomicrmw sub i64* @var64, i64 %offset seq_cst
158 ; CHECK: dmb ish
159 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
160 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
161
162 ; CHECK: .LBB{{[0-9]+}}_1:
163 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
164   ; x0 below is a reasonable guess but could change: it certainly comes into the
165   ; function there.
166 ; CHECK-NEXT: sub [[NEW:x[0-9]+]], x[[OLD]], x0
167 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
168 ; CHECK-NEXT: cmp [[STATUS]], #0
169 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
170 ; CHECK: dmb ish
171
172 ; CHECK: mov x0, x[[OLD]]
173    ret i64 %old
174 }
175
176 define i8 @test_atomic_load_and_i8(i8 %offset) nounwind {
177 ; CHECK: test_atomic_load_and_i8:
178    %old = atomicrmw and i8* @var8, i8 %offset seq_cst
179 ; CHECK: dmb ish
180 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
181 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
182
183 ; CHECK: .LBB{{[0-9]+}}_1:
184 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
185   ; w0 below is a reasonable guess but could change: it certainly comes into the
186   ;  function there.
187 ; CHECK-NEXT: and [[NEW:w[0-9]+]], w[[OLD]], w0
188 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
189 ; CHECK-NEXT: cmp [[STATUS]], #0
190 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
191 ; CHECK: dmb ish
192
193 ; CHECK: mov x0, x[[OLD]]
194    ret i8 %old
195 }
196
197 define i16 @test_atomic_load_and_i16(i16 %offset) nounwind {
198 ; CHECK: test_atomic_load_and_i16:
199    %old = atomicrmw and i16* @var16, i16 %offset seq_cst
200 ; CHECK: dmb ish
201 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
202 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
203
204 ; CHECK: .LBB{{[0-9]+}}_1:
205 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
206   ; w0 below is a reasonable guess but could change: it certainly comes into the
207   ;  function there.
208 ; CHECK-NEXT: and [[NEW:w[0-9]+]], w[[OLD]], w0
209 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
210 ; CHECK-NEXT: cmp [[STATUS]], #0
211 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
212 ; CHECK: dmb ish
213
214 ; CHECK: mov x0, x[[OLD]]
215    ret i16 %old
216 }
217
218 define i32 @test_atomic_load_and_i32(i32 %offset) nounwind {
219 ; CHECK: test_atomic_load_and_i32:
220    %old = atomicrmw and i32* @var32, i32 %offset seq_cst
221 ; CHECK: dmb ish
222 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
223 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
224
225 ; CHECK: .LBB{{[0-9]+}}_1:
226 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
227   ; w0 below is a reasonable guess but could change: it certainly comes into the
228   ;  function there.
229 ; CHECK-NEXT: and [[NEW:w[0-9]+]], w[[OLD]], w0
230 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
231 ; CHECK-NEXT: cmp [[STATUS]], #0
232 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
233 ; CHECK: dmb ish
234
235 ; CHECK: mov x0, x[[OLD]]
236    ret i32 %old
237 }
238
239 define i64 @test_atomic_load_and_i64(i64 %offset) nounwind {
240 ; CHECK: test_atomic_load_and_i64:
241    %old = atomicrmw and i64* @var64, i64 %offset seq_cst
242 ; CHECK: dmb ish
243 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
244 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
245
246 ; CHECK: .LBB{{[0-9]+}}_1:
247 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
248   ; x0 below is a reasonable guess but could change: it certainly comes into the
249   ; function there.
250 ; CHECK-NEXT: and [[NEW:x[0-9]+]], x[[OLD]], x0
251 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
252 ; CHECK-NEXT: cmp [[STATUS]], #0
253 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
254 ; CHECK: dmb ish
255
256 ; CHECK: mov x0, x[[OLD]]
257    ret i64 %old
258 }
259
260 define i8 @test_atomic_load_or_i8(i8 %offset) nounwind {
261 ; CHECK: test_atomic_load_or_i8:
262    %old = atomicrmw or i8* @var8, i8 %offset seq_cst
263 ; CHECK: dmb ish
264 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
265 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
266
267 ; CHECK: .LBB{{[0-9]+}}_1:
268 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
269   ; w0 below is a reasonable guess but could change: it certainly comes into the
270   ;  function there.
271 ; CHECK-NEXT: orr [[NEW:w[0-9]+]], w[[OLD]], w0
272 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
273 ; CHECK-NEXT: cmp [[STATUS]], #0
274 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
275 ; CHECK: dmb ish
276
277 ; CHECK: mov x0, x[[OLD]]
278    ret i8 %old
279 }
280
281 define i16 @test_atomic_load_or_i16(i16 %offset) nounwind {
282 ; CHECK: test_atomic_load_or_i16:
283    %old = atomicrmw or i16* @var16, i16 %offset seq_cst
284 ; CHECK: dmb ish
285 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
286 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
287
288 ; CHECK: .LBB{{[0-9]+}}_1:
289 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
290   ; w0 below is a reasonable guess but could change: it certainly comes into the
291   ;  function there.
292 ; CHECK-NEXT: orr [[NEW:w[0-9]+]], w[[OLD]], w0
293 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
294 ; CHECK-NEXT: cmp [[STATUS]], #0
295 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
296 ; CHECK: dmb ish
297
298 ; CHECK: mov x0, x[[OLD]]
299    ret i16 %old
300 }
301
302 define i32 @test_atomic_load_or_i32(i32 %offset) nounwind {
303 ; CHECK: test_atomic_load_or_i32:
304    %old = atomicrmw or i32* @var32, i32 %offset seq_cst
305 ; CHECK: dmb ish
306 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
307 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
308
309 ; CHECK: .LBB{{[0-9]+}}_1:
310 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
311   ; w0 below is a reasonable guess but could change: it certainly comes into the
312   ;  function there.
313 ; CHECK-NEXT: orr [[NEW:w[0-9]+]], w[[OLD]], w0
314 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
315 ; CHECK-NEXT: cmp [[STATUS]], #0
316 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
317 ; CHECK: dmb ish
318
319 ; CHECK: mov x0, x[[OLD]]
320    ret i32 %old
321 }
322
323 define i64 @test_atomic_load_or_i64(i64 %offset) nounwind {
324 ; CHECK: test_atomic_load_or_i64:
325    %old = atomicrmw or i64* @var64, i64 %offset seq_cst
326 ; CHECK: dmb ish
327 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
328 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
329
330 ; CHECK: .LBB{{[0-9]+}}_1:
331 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
332   ; x0 below is a reasonable guess but could change: it certainly comes into the
333   ; function there.
334 ; CHECK-NEXT: orr [[NEW:x[0-9]+]], x[[OLD]], x0
335 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
336 ; CHECK-NEXT: cmp [[STATUS]], #0
337 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
338 ; CHECK: dmb ish
339
340 ; CHECK: mov x0, x[[OLD]]
341    ret i64 %old
342 }
343
344 define i8 @test_atomic_load_xor_i8(i8 %offset) nounwind {
345 ; CHECK: test_atomic_load_xor_i8:
346    %old = atomicrmw xor i8* @var8, i8 %offset seq_cst
347 ; CHECK: dmb ish
348 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
349 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
350
351 ; CHECK: .LBB{{[0-9]+}}_1:
352 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
353   ; w0 below is a reasonable guess but could change: it certainly comes into the
354   ;  function there.
355 ; CHECK-NEXT: eor [[NEW:w[0-9]+]], w[[OLD]], w0
356 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
357 ; CHECK-NEXT: cmp [[STATUS]], #0
358 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
359 ; CHECK: dmb ish
360
361 ; CHECK: mov x0, x[[OLD]]
362    ret i8 %old
363 }
364
365 define i16 @test_atomic_load_xor_i16(i16 %offset) nounwind {
366 ; CHECK: test_atomic_load_xor_i16:
367    %old = atomicrmw xor i16* @var16, i16 %offset seq_cst
368 ; CHECK: dmb ish
369 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
370 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
371
372 ; CHECK: .LBB{{[0-9]+}}_1:
373 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
374   ; w0 below is a reasonable guess but could change: it certainly comes into the
375   ;  function there.
376 ; CHECK-NEXT: eor [[NEW:w[0-9]+]], w[[OLD]], w0
377 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
378 ; CHECK-NEXT: cmp [[STATUS]], #0
379 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
380 ; CHECK: dmb ish
381
382 ; CHECK: mov x0, x[[OLD]]
383    ret i16 %old
384 }
385
386 define i32 @test_atomic_load_xor_i32(i32 %offset) nounwind {
387 ; CHECK: test_atomic_load_xor_i32:
388    %old = atomicrmw xor i32* @var32, i32 %offset seq_cst
389 ; CHECK: dmb ish
390 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
391 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
392
393 ; CHECK: .LBB{{[0-9]+}}_1:
394 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
395   ; w0 below is a reasonable guess but could change: it certainly comes into the
396   ;  function there.
397 ; CHECK-NEXT: eor [[NEW:w[0-9]+]], w[[OLD]], w0
398 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
399 ; CHECK-NEXT: cmp [[STATUS]], #0
400 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
401 ; CHECK: dmb ish
402
403 ; CHECK: mov x0, x[[OLD]]
404    ret i32 %old
405 }
406
407 define i64 @test_atomic_load_xor_i64(i64 %offset) nounwind {
408 ; CHECK: test_atomic_load_xor_i64:
409    %old = atomicrmw xor i64* @var64, i64 %offset seq_cst
410 ; CHECK: dmb ish
411 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
412 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
413
414 ; CHECK: .LBB{{[0-9]+}}_1:
415 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
416   ; x0 below is a reasonable guess but could change: it certainly comes into the
417   ; function there.
418 ; CHECK-NEXT: eor [[NEW:x[0-9]+]], x[[OLD]], x0
419 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
420 ; CHECK-NEXT: cmp [[STATUS]], #0
421 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
422 ; CHECK: dmb ish
423
424 ; CHECK: mov x0, x[[OLD]]
425    ret i64 %old
426 }
427
428 define i8 @test_atomic_load_xchg_i8(i8 %offset) nounwind {
429 ; CHECK: test_atomic_load_xchg_i8:
430    %old = atomicrmw xchg i8* @var8, i8 %offset seq_cst
431 ; CHECK: dmb ish
432 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
433 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
434
435 ; CHECK: .LBB{{[0-9]+}}_1:
436 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
437   ; w0 below is a reasonable guess but could change: it certainly comes into the
438   ; function there.
439 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], w0, [x[[ADDR]]]
440 ; CHECK-NEXT: cmp [[STATUS]], #0
441 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
442 ; CHECK: dmb ish
443
444 ; CHECK: mov x0, x[[OLD]]
445    ret i8 %old
446 }
447
448 define i16 @test_atomic_load_xchg_i16(i16 %offset) nounwind {
449 ; CHECK: test_atomic_load_xchg_i16:
450    %old = atomicrmw xchg i16* @var16, i16 %offset seq_cst
451 ; CHECK: dmb ish
452 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
453 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
454
455 ; CHECK: .LBB{{[0-9]+}}_1:
456 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
457   ; w0 below is a reasonable guess but could change: it certainly comes into the
458   ; function there.
459 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], w0, [x[[ADDR]]]
460 ; CHECK-NEXT: cmp [[STATUS]], #0
461 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
462 ; CHECK: dmb ish
463
464 ; CHECK: mov x0, x[[OLD]]
465    ret i16 %old
466 }
467
468 define i32 @test_atomic_load_xchg_i32(i32 %offset) nounwind {
469 ; CHECK: test_atomic_load_xchg_i32:
470    %old = atomicrmw xchg i32* @var32, i32 %offset seq_cst
471 ; CHECK: dmb ish
472 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
473 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
474
475 ; CHECK: .LBB{{[0-9]+}}_1:
476 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
477   ; w0 below is a reasonable guess but could change: it certainly comes into the
478   ;  function there.
479 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], w0, [x[[ADDR]]]
480 ; CHECK-NEXT: cmp [[STATUS]], #0
481 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
482 ; CHECK: dmb ish
483
484 ; CHECK: mov x0, x[[OLD]]
485    ret i32 %old
486 }
487
488 define i64 @test_atomic_load_xchg_i64(i64 %offset) nounwind {
489 ; CHECK: test_atomic_load_xchg_i64:
490    %old = atomicrmw xchg i64* @var64, i64 %offset seq_cst
491 ; CHECK: dmb ish
492 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
493 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
494
495 ; CHECK: .LBB{{[0-9]+}}_1:
496 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
497   ; x0 below is a reasonable guess but could change: it certainly comes into the
498   ; function there.
499 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], x0, [x[[ADDR]]]
500 ; CHECK-NEXT: cmp [[STATUS]], #0
501 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
502 ; CHECK: dmb ish
503
504 ; CHECK: mov x0, x[[OLD]]
505    ret i64 %old
506 }
507
508
509 define i8 @test_atomic_load_min_i8(i8 %offset) nounwind {
510 ; CHECK: test_atomic_load_min_i8:
511    %old = atomicrmw min i8* @var8, i8 %offset seq_cst
512 ; CHECK: dmb ish
513 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
514 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
515
516 ; CHECK: .LBB{{[0-9]+}}_1:
517 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
518   ; w0 below is a reasonable guess but could change: it certainly comes into the
519   ;  function there.
520 ; CHECK-NEXT: cmp w0, w[[OLD]], sxtb
521 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, gt
522 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
523 ; CHECK-NEXT: cmp [[STATUS]], #0
524 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
525 ; CHECK: dmb ish
526
527 ; CHECK: mov x0, x[[OLD]]
528    ret i8 %old
529 }
530
531 define i16 @test_atomic_load_min_i16(i16 %offset) nounwind {
532 ; CHECK: test_atomic_load_min_i16:
533    %old = atomicrmw min i16* @var16, i16 %offset seq_cst
534 ; CHECK: dmb ish
535 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
536 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
537
538 ; CHECK: .LBB{{[0-9]+}}_1:
539 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
540   ; w0 below is a reasonable guess but could change: it certainly comes into the
541   ;  function there.
542 ; CHECK-NEXT: cmp w0, w[[OLD]], sxth
543 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, gt
544 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
545 ; CHECK-NEXT: cmp [[STATUS]], #0
546 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
547 ; CHECK: dmb ish
548
549 ; CHECK: mov x0, x[[OLD]]
550    ret i16 %old
551 }
552
553 define i32 @test_atomic_load_min_i32(i32 %offset) nounwind {
554 ; CHECK: test_atomic_load_min_i32:
555    %old = atomicrmw min i32* @var32, i32 %offset seq_cst
556 ; CHECK: dmb ish
557 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
558 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
559
560 ; CHECK: .LBB{{[0-9]+}}_1:
561 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
562   ; w0 below is a reasonable guess but could change: it certainly comes into the
563   ;  function there.
564 ; CHECK-NEXT: cmp w0, w[[OLD]]
565 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, gt
566 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
567 ; CHECK-NEXT: cmp [[STATUS]], #0
568 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
569 ; CHECK: dmb ish
570
571 ; CHECK: mov x0, x[[OLD]]
572    ret i32 %old
573 }
574
575 define i64 @test_atomic_load_min_i64(i64 %offset) nounwind {
576 ; CHECK: test_atomic_load_min_i64:
577    %old = atomicrmw min i64* @var64, i64 %offset seq_cst
578 ; CHECK: dmb ish
579 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
580 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
581
582 ; CHECK: .LBB{{[0-9]+}}_1:
583 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
584   ; x0 below is a reasonable guess but could change: it certainly comes into the
585   ; function there.
586 ; CHECK-NEXT: cmp x0, x[[OLD]]
587 ; CHECK-NEXT: csel [[NEW:x[0-9]+]], x[[OLD]], x0, gt
588 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
589 ; CHECK-NEXT: cmp [[STATUS]], #0
590 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
591 ; CHECK: dmb ish
592
593 ; CHECK: mov x0, x[[OLD]]
594    ret i64 %old
595 }
596
597 define i8 @test_atomic_load_max_i8(i8 %offset) nounwind {
598 ; CHECK: test_atomic_load_max_i8:
599    %old = atomicrmw max i8* @var8, i8 %offset seq_cst
600 ; CHECK: dmb ish
601 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
602 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
603
604 ; CHECK: .LBB{{[0-9]+}}_1:
605 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
606   ; w0 below is a reasonable guess but could change: it certainly comes into the
607   ;  function there.
608 ; CHECK-NEXT: cmp w0, w[[OLD]], sxtb
609 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lt
610 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
611 ; CHECK-NEXT: cmp [[STATUS]], #0
612 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
613 ; CHECK: dmb ish
614
615 ; CHECK: mov x0, x[[OLD]]
616    ret i8 %old
617 }
618
619 define i16 @test_atomic_load_max_i16(i16 %offset) nounwind {
620 ; CHECK: test_atomic_load_max_i16:
621    %old = atomicrmw max i16* @var16, i16 %offset seq_cst
622 ; CHECK: dmb ish
623 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
624 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
625
626 ; CHECK: .LBB{{[0-9]+}}_1:
627 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
628   ; w0 below is a reasonable guess but could change: it certainly comes into the
629   ;  function there.
630 ; CHECK-NEXT: cmp w0, w[[OLD]], sxth
631 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lt
632 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
633 ; CHECK-NEXT: cmp [[STATUS]], #0
634 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
635 ; CHECK: dmb ish
636
637 ; CHECK: mov x0, x[[OLD]]
638    ret i16 %old
639 }
640
641 define i32 @test_atomic_load_max_i32(i32 %offset) nounwind {
642 ; CHECK: test_atomic_load_max_i32:
643    %old = atomicrmw max i32* @var32, i32 %offset seq_cst
644 ; CHECK: dmb ish
645 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
646 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
647
648 ; CHECK: .LBB{{[0-9]+}}_1:
649 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
650   ; w0 below is a reasonable guess but could change: it certainly comes into the
651   ;  function there.
652 ; CHECK-NEXT: cmp w0, w[[OLD]]
653 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lt
654 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
655 ; CHECK-NEXT: cmp [[STATUS]], #0
656 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
657 ; CHECK: dmb ish
658
659 ; CHECK: mov x0, x[[OLD]]
660    ret i32 %old
661 }
662
663 define i64 @test_atomic_load_max_i64(i64 %offset) nounwind {
664 ; CHECK: test_atomic_load_max_i64:
665    %old = atomicrmw max i64* @var64, i64 %offset seq_cst
666 ; CHECK: dmb ish
667 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
668 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
669
670 ; CHECK: .LBB{{[0-9]+}}_1:
671 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
672   ; x0 below is a reasonable guess but could change: it certainly comes into the
673   ; function there.
674 ; CHECK-NEXT: cmp x0, x[[OLD]]
675 ; CHECK-NEXT: csel [[NEW:x[0-9]+]], x[[OLD]], x0, lt
676 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
677 ; CHECK-NEXT: cmp [[STATUS]], #0
678 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
679 ; CHECK: dmb ish
680
681 ; CHECK: mov x0, x[[OLD]]
682    ret i64 %old
683 }
684
685 define i8 @test_atomic_load_umin_i8(i8 %offset) nounwind {
686 ; CHECK: test_atomic_load_umin_i8:
687    %old = atomicrmw umin i8* @var8, i8 %offset seq_cst
688 ; CHECK: dmb ish
689 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
690 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
691
692 ; CHECK: .LBB{{[0-9]+}}_1:
693 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
694   ; w0 below is a reasonable guess but could change: it certainly comes into the
695   ;  function there.
696 ; CHECK-NEXT: cmp w0, w[[OLD]], uxtb
697 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, hi
698 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
699 ; CHECK-NEXT: cmp [[STATUS]], #0
700 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
701 ; CHECK: dmb ish
702
703 ; CHECK: mov x0, x[[OLD]]
704    ret i8 %old
705 }
706
707 define i16 @test_atomic_load_umin_i16(i16 %offset) nounwind {
708 ; CHECK: test_atomic_load_umin_i16:
709    %old = atomicrmw umin i16* @var16, i16 %offset seq_cst
710 ; CHECK: dmb ish
711 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
712 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
713
714 ; CHECK: .LBB{{[0-9]+}}_1:
715 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
716   ; w0 below is a reasonable guess but could change: it certainly comes into the
717   ;  function there.
718 ; CHECK-NEXT: cmp w0, w[[OLD]], uxth
719 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, hi
720 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
721 ; CHECK-NEXT: cmp [[STATUS]], #0
722 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
723 ; CHECK: dmb ish
724
725 ; CHECK: mov x0, x[[OLD]]
726    ret i16 %old
727 }
728
729 define i32 @test_atomic_load_umin_i32(i32 %offset) nounwind {
730 ; CHECK: test_atomic_load_umin_i32:
731    %old = atomicrmw umin i32* @var32, i32 %offset seq_cst
732 ; CHECK: dmb ish
733 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
734 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
735
736 ; CHECK: .LBB{{[0-9]+}}_1:
737 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
738   ; w0 below is a reasonable guess but could change: it certainly comes into the
739   ;  function there.
740 ; CHECK-NEXT: cmp w0, w[[OLD]]
741 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, hi
742 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
743 ; CHECK-NEXT: cmp [[STATUS]], #0
744 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
745 ; CHECK: dmb ish
746
747 ; CHECK: mov x0, x[[OLD]]
748    ret i32 %old
749 }
750
751 define i64 @test_atomic_load_umin_i64(i64 %offset) nounwind {
752 ; CHECK: test_atomic_load_umin_i64:
753    %old = atomicrmw umin i64* @var64, i64 %offset seq_cst
754 ; CHECK: dmb ish
755 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
756 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
757
758 ; CHECK: .LBB{{[0-9]+}}_1:
759 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
760   ; x0 below is a reasonable guess but could change: it certainly comes into the
761   ; function there.
762 ; CHECK-NEXT: cmp x0, x[[OLD]]
763 ; CHECK-NEXT: csel [[NEW:x[0-9]+]], x[[OLD]], x0, hi
764 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
765 ; CHECK-NEXT: cmp [[STATUS]], #0
766 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
767 ; CHECK: dmb ish
768
769 ; CHECK: mov x0, x[[OLD]]
770    ret i64 %old
771 }
772
773 define i8 @test_atomic_load_umax_i8(i8 %offset) nounwind {
774 ; CHECK: test_atomic_load_umax_i8:
775    %old = atomicrmw umax i8* @var8, i8 %offset seq_cst
776 ; CHECK: dmb ish
777 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
778 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
779
780 ; CHECK: .LBB{{[0-9]+}}_1:
781 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
782   ; w0 below is a reasonable guess but could change: it certainly comes into the
783   ;  function there.
784 ; CHECK-NEXT: cmp w0, w[[OLD]], uxtb
785 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lo
786 ; CHECK-NEXT: stxrb [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
787 ; CHECK-NEXT: cmp [[STATUS]], #0
788 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
789 ; CHECK: dmb ish
790
791 ; CHECK: mov x0, x[[OLD]]
792    ret i8 %old
793 }
794
795 define i16 @test_atomic_load_umax_i16(i16 %offset) nounwind {
796 ; CHECK: test_atomic_load_umax_i16:
797    %old = atomicrmw umax i16* @var16, i16 %offset seq_cst
798 ; CHECK: dmb ish
799 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
800 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
801
802 ; CHECK: .LBB{{[0-9]+}}_1:
803 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
804   ; w0 below is a reasonable guess but could change: it certainly comes into the
805   ;  function there.
806 ; CHECK-NEXT: cmp w0, w[[OLD]], uxth
807 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lo
808 ; CHECK-NEXT: stxrh [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
809 ; CHECK-NEXT: cmp [[STATUS]], #0
810 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
811 ; CHECK: dmb ish
812
813 ; CHECK: mov x0, x[[OLD]]
814    ret i16 %old
815 }
816
817 define i32 @test_atomic_load_umax_i32(i32 %offset) nounwind {
818 ; CHECK: test_atomic_load_umax_i32:
819    %old = atomicrmw umax i32* @var32, i32 %offset seq_cst
820 ; CHECK: dmb ish
821 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
822 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
823
824 ; CHECK: .LBB{{[0-9]+}}_1:
825 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
826   ; w0 below is a reasonable guess but could change: it certainly comes into the
827   ;  function there.
828 ; CHECK-NEXT: cmp w0, w[[OLD]]
829 ; CHECK-NEXT: csel [[NEW:w[0-9]+]], w[[OLD]], w0, lo
830 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
831 ; CHECK-NEXT: cmp [[STATUS]], #0
832 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
833 ; CHECK: dmb ish
834
835 ; CHECK: mov x0, x[[OLD]]
836    ret i32 %old
837 }
838
839 define i64 @test_atomic_load_umax_i64(i64 %offset) nounwind {
840 ; CHECK: test_atomic_load_umax_i64:
841    %old = atomicrmw umax i64* @var64, i64 %offset seq_cst
842 ; CHECK: dmb ish
843 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
844 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
845
846 ; CHECK: .LBB{{[0-9]+}}_1:
847 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
848   ; x0 below is a reasonable guess but could change: it certainly comes into the
849   ; function there.
850 ; CHECK-NEXT: cmp x0, x[[OLD]]
851 ; CHECK-NEXT: csel [[NEW:x[0-9]+]], x[[OLD]], x0, lo
852 ; CHECK-NEXT: stxr [[STATUS:w[0-9]+]], [[NEW]], [x[[ADDR]]]
853 ; CHECK-NEXT: cmp [[STATUS]], #0
854 ; CHECK-NEXT: b.ne .LBB{{[0-9]+}}_1
855 ; CHECK: dmb ish
856
857 ; CHECK: mov x0, x[[OLD]]
858    ret i64 %old
859 }
860
861 define i8 @test_atomic_cmpxchg_i8(i8 %wanted, i8 %new) nounwind {
862 ; CHECK: test_atomic_cmpxchg_i8:
863    %old = cmpxchg i8* @var8, i8 %wanted, i8 %new seq_cst
864 ; CHECK: dmb ish
865 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
866 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
867
868 ; CHECK: [[STARTAGAIN:.LBB[0-9]+_[0-9]+]]:
869 ; CHECK-NEXT: ldxrb w[[OLD:[0-9]+]], [x[[ADDR]]]
870   ; w0 below is a reasonable guess but could change: it certainly comes into the
871   ;  function there.
872 ; CHECK-NEXT: cmp w[[OLD]], w0
873 ; CHECK-NEXT: b.ne [[GET_OUT:.LBB[0-9]+_[0-9]+]]
874   ; As above, w1 is a reasonable guess.
875 ; CHECK: stxrb [[STATUS:w[0-9]+]], w1, [x[[ADDR]]]
876 ; CHECK-NEXT: cmp [[STATUS]], #0
877 ; CHECK-NEXT: b.ne [[STARTAGAIN]]
878 ; CHECK: dmb ish
879
880 ; CHECK: mov x0, x[[OLD]]
881    ret i8 %old
882 }
883
884 define i16 @test_atomic_cmpxchg_i16(i16 %wanted, i16 %new) nounwind {
885 ; CHECK: test_atomic_cmpxchg_i16:
886    %old = cmpxchg i16* @var16, i16 %wanted, i16 %new seq_cst
887 ; CHECK: dmb ish
888 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var16
889 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var16
890
891 ; CHECK: [[STARTAGAIN:.LBB[0-9]+_[0-9]+]]:
892 ; CHECK-NEXT: ldxrh w[[OLD:[0-9]+]], [x[[ADDR]]]
893   ; w0 below is a reasonable guess but could change: it certainly comes into the
894   ;  function there.
895 ; CHECK-NEXT: cmp w[[OLD]], w0
896 ; CHECK-NEXT: b.ne [[GET_OUT:.LBB[0-9]+_[0-9]+]]
897   ; As above, w1 is a reasonable guess.
898 ; CHECK: stxrh [[STATUS:w[0-9]+]], w1, [x[[ADDR]]]
899 ; CHECK-NEXT: cmp [[STATUS]], #0
900 ; CHECK-NEXT: b.ne [[STARTAGAIN]]
901 ; CHECK: dmb ish
902
903 ; CHECK: mov x0, x[[OLD]]
904    ret i16 %old
905 }
906
907 define i32 @test_atomic_cmpxchg_i32(i32 %wanted, i32 %new) nounwind {
908 ; CHECK: test_atomic_cmpxchg_i32:
909    %old = cmpxchg i32* @var32, i32 %wanted, i32 %new seq_cst
910 ; CHECK: dmb ish
911 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var32
912 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var32
913
914 ; CHECK: [[STARTAGAIN:.LBB[0-9]+_[0-9]+]]:
915 ; CHECK-NEXT: ldxr w[[OLD:[0-9]+]], [x[[ADDR]]]
916   ; w0 below is a reasonable guess but could change: it certainly comes into the
917   ;  function there.
918 ; CHECK-NEXT: cmp w[[OLD]], w0
919 ; CHECK-NEXT: b.ne [[GET_OUT:.LBB[0-9]+_[0-9]+]]
920   ; As above, w1 is a reasonable guess.
921 ; CHECK: stxr [[STATUS:w[0-9]+]], w1, [x[[ADDR]]]
922 ; CHECK-NEXT: cmp [[STATUS]], #0
923 ; CHECK-NEXT: b.ne [[STARTAGAIN]]
924 ; CHECK: dmb ish
925
926 ; CHECK: mov x0, x[[OLD]]
927    ret i32 %old
928 }
929
930 define i64 @test_atomic_cmpxchg_i64(i64 %wanted, i64 %new) nounwind {
931 ; CHECK: test_atomic_cmpxchg_i64:
932    %old = cmpxchg i64* @var64, i64 %wanted, i64 %new seq_cst
933 ; CHECK: dmb ish
934 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var64
935 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var64
936
937 ; CHECK: [[STARTAGAIN:.LBB[0-9]+_[0-9]+]]:
938 ; CHECK-NEXT: ldxr x[[OLD:[0-9]+]], [x[[ADDR]]]
939   ; w0 below is a reasonable guess but could change: it certainly comes into the
940   ;  function there.
941 ; CHECK-NEXT: cmp x[[OLD]], x0
942 ; CHECK-NEXT: b.ne [[GET_OUT:.LBB[0-9]+_[0-9]+]]
943   ; As above, w1 is a reasonable guess.
944 ; CHECK: stxr [[STATUS:w[0-9]+]], x1, [x[[ADDR]]]
945 ; CHECK-NEXT: cmp [[STATUS]], #0
946 ; CHECK-NEXT: b.ne [[STARTAGAIN]]
947 ; CHECK: dmb ish
948
949 ; CHECK: mov x0, x[[OLD]]
950    ret i64 %old
951 }
952
953 define i8 @test_atomic_load_monotonic_i8() nounwind {
954 ; CHECK: test_atomic_load_monotonic_i8:
955   %val = load atomic i8* @var8 monotonic, align 1
956 ; CHECK-NOT: dmb
957 ; CHECK: adrp x[[HIADDR:[0-9]+]], var8
958 ; CHECK: ldrb w0, [x[[HIADDR]], #:lo12:var8]
959 ; CHECK-NOT: dmb
960
961   ret i8 %val
962 }
963
964 define i8 @test_atomic_load_monotonic_regoff_i8(i64 %base, i64 %off) nounwind {
965 ; CHECK: test_atomic_load_monotonic_regoff_i8:
966   %addr_int = add i64 %base, %off
967   %addr = inttoptr i64 %addr_int to i8*
968
969   %val = load atomic i8* %addr monotonic, align 1
970 ; CHECK-NOT: dmb
971 ; CHECK: ldrb w0, [x0, x1]
972 ; CHECK-NOT: dmb
973
974   ret i8 %val
975 }
976
977 define i8 @test_atomic_load_acquire_i8() nounwind {
978 ; CHECK: test_atomic_load_acquire_i8:
979   %val = load atomic i8* @var8 acquire, align 1
980 ; CHECK: adrp [[TMPADDR:x[0-9]+]], var8
981 ; CHECK: add x[[ADDR:[0-9]+]], [[TMPADDR]], #:lo12:var8
982
983 ; CHECK: ldarb w0, [x[[ADDR]]]
984   ret i8 %val
985 }
986
987 define i8 @test_atomic_load_seq_cst_i8() nounwind {
988 ; CHECK: test_atomic_load_seq_cst_i8:
989   %val = load atomic i8* @var8 seq_cst, align 1
990 ; CHECK: adrp x[[HIADDR:[0-9]+]], var8
991 ; CHECK: ldrb w0, [x[[HIADDR]], #:lo12:var8]
992 ; CHECK: dmb ish
993   ret i8 %val
994 }
995
996 define i16 @test_atomic_load_monotonic_i16() nounwind {
997 ; CHECK: test_atomic_load_monotonic_i16:
998   %val = load atomic i16* @var16 monotonic, align 2
999 ; CHECK-NOT: dmb
1000 ; CHECK: adrp x[[HIADDR:[0-9]+]], var16
1001 ; CHECK: ldrh w0, [x[[HIADDR]], #:lo12:var16]
1002 ; CHECK-NOT: dmb
1003
1004   ret i16 %val
1005 }
1006
1007 define i32 @test_atomic_load_monotonic_regoff_i32(i64 %base, i64 %off) nounwind {
1008 ; CHECK: test_atomic_load_monotonic_regoff_i32:
1009   %addr_int = add i64 %base, %off
1010   %addr = inttoptr i64 %addr_int to i32*
1011
1012   %val = load atomic i32* %addr monotonic, align 4
1013 ; CHECK-NOT: dmb
1014 ; CHECK: ldr w0, [x0, x1]
1015 ; CHECK-NOT: dmb
1016
1017   ret i32 %val
1018 }
1019
1020 define i64 @test_atomic_load_seq_cst_i64() nounwind {
1021 ; CHECK: test_atomic_load_seq_cst_i64:
1022   %val = load atomic i64* @var64 seq_cst, align 8
1023 ; CHECK: adrp x[[HIADDR:[0-9]+]], var64
1024 ; CHECK: ldr x0, [x[[HIADDR]], #:lo12:var64]
1025 ; CHECK: dmb ish
1026   ret i64 %val
1027 }
1028
1029 define void @test_atomic_store_monotonic_i8(i8 %val) nounwind {
1030 ; CHECK: test_atomic_store_monotonic_i8:
1031   store atomic i8 %val, i8* @var8 monotonic, align 1
1032 ; CHECK: adrp x[[HIADDR:[0-9]+]], var8
1033 ; CHECK: strb w0, [x[[HIADDR]], #:lo12:var8]
1034
1035   ret void
1036 }
1037
1038 define void @test_atomic_store_monotonic_regoff_i8(i64 %base, i64 %off, i8 %val) nounwind {
1039 ; CHECK: test_atomic_store_monotonic_regoff_i8:
1040
1041   %addr_int = add i64 %base, %off
1042   %addr = inttoptr i64 %addr_int to i8*
1043
1044   store atomic i8 %val, i8* %addr monotonic, align 1
1045 ; CHECK: strb w2, [x0, x1]
1046
1047   ret void
1048 }
1049 define void @test_atomic_store_release_i8(i8 %val) nounwind {
1050 ; CHECK: test_atomic_store_release_i8:
1051   store atomic i8 %val, i8* @var8 release, align 1
1052 ; CHECK: adrp [[HIADDR:x[0-9]+]], var8
1053 ; CHECK: add x[[ADDR:[0-9]+]], [[HIADDR]], #:lo12:var8
1054 ; CHECK: stlrb w0, [x[[ADDR]]]
1055
1056   ret void
1057 }
1058
1059 define void @test_atomic_store_seq_cst_i8(i8 %val) nounwind {
1060 ; CHECK: test_atomic_store_seq_cst_i8:
1061   store atomic i8 %val, i8* @var8 seq_cst, align 1
1062 ; CHECK: adrp [[HIADDR:x[0-9]+]], var8
1063 ; CHECK: add x[[ADDR:[0-9]+]], [[HIADDR]], #:lo12:var8
1064 ; CHECK: stlrb w0, [x[[ADDR]]]
1065 ; CHECK: dmb ish
1066
1067   ret void
1068 }
1069
1070 define void @test_atomic_store_monotonic_i16(i16 %val) nounwind {
1071 ; CHECK: test_atomic_store_monotonic_i16:
1072   store atomic i16 %val, i16* @var16 monotonic, align 2
1073 ; CHECK: adrp x[[HIADDR:[0-9]+]], var16
1074 ; CHECK: strh w0, [x[[HIADDR]], #:lo12:var16]
1075
1076   ret void
1077 }
1078
1079 define void @test_atomic_store_monotonic_regoff_i32(i64 %base, i64 %off, i32 %val) nounwind {
1080 ; CHECK: test_atomic_store_monotonic_regoff_i32:
1081
1082   %addr_int = add i64 %base, %off
1083   %addr = inttoptr i64 %addr_int to i32*
1084
1085   store atomic i32 %val, i32* %addr monotonic, align 4
1086 ; CHECK: str w2, [x0, x1]
1087
1088   ret void
1089 }
1090
1091 define void @test_atomic_store_release_i64(i64 %val) nounwind {
1092 ; CHECK: test_atomic_store_release_i64:
1093   store atomic i64 %val, i64* @var64 release, align 8
1094 ; CHECK: adrp [[HIADDR:x[0-9]+]], var64
1095 ; CHECK: add x[[ADDR:[0-9]+]], [[HIADDR]], #:lo12:var64
1096 ; CHECK: stlr x0, [x[[ADDR]]]
1097
1098   ret void
1099 }