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