ARM: expand atomic ldrex/strex loops in IR
[oota-llvm.git] / test / CodeGen / ARM / atomic-ops-v8.ll
1 ; RUN: llc -mtriple=armv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
2 ; RUN: llc -mtriple=thumbv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-THUMB
3
4 @var8 = global i8 0
5 @var16 = global i16 0
6 @var32 = global i32 0
7 @var64 = global i64 0
8
9 define i8 @test_atomic_load_add_i8(i8 %offset) nounwind {
10 ; CHECK-LABEL: test_atomic_load_add_i8:
11    %old = atomicrmw add i8* @var8, i8 %offset seq_cst
12 ; CHECK-NOT: dmb
13 ; CHECK-NOT: mcr
14 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
15 ; CHECK: movt r[[ADDR]], :upper16:var8
16
17 ; CHECK: .LBB{{[0-9]+}}_1:
18 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
19   ; r0 below is a reasonable guess but could change: it certainly comes into the
20   ;  function there.
21 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
22 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
23 ; CHECK-NEXT: cmp [[STATUS]], #0
24 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
25 ; CHECK-NOT: dmb
26 ; CHECK-NOT: mcr
27
28 ; CHECK: mov r0, r[[OLD]]
29    ret i8 %old
30 }
31
32 define i16 @test_atomic_load_add_i16(i16 %offset) nounwind {
33 ; CHECK-LABEL: test_atomic_load_add_i16:
34    %old = atomicrmw add i16* @var16, i16 %offset acquire
35 ; CHECK-NOT: dmb
36 ; CHECK-NOT: mcr
37 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
38 ; CHECK: movt r[[ADDR]], :upper16:var16
39
40 ; CHECK: .LBB{{[0-9]+}}_1:
41 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
42   ; r0 below is a reasonable guess but could change: it certainly comes into the
43   ;  function there.
44 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
45 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
46 ; CHECK-NEXT: cmp [[STATUS]], #0
47 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
48 ; CHECK-NOT: dmb
49 ; CHECK-NOT: mcr
50
51 ; CHECK: mov r0, r[[OLD]]
52    ret i16 %old
53 }
54
55 define i32 @test_atomic_load_add_i32(i32 %offset) nounwind {
56 ; CHECK-LABEL: test_atomic_load_add_i32:
57    %old = atomicrmw add i32* @var32, i32 %offset release
58 ; CHECK-NOT: dmb
59 ; CHECK-NOT: mcr
60 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
61 ; CHECK: movt r[[ADDR]], :upper16:var32
62
63 ; CHECK: .LBB{{[0-9]+}}_1:
64 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
65   ; r0 below is a reasonable guess but could change: it certainly comes into the
66   ;  function there.
67 ; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
68 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
69 ; CHECK-NEXT: cmp [[STATUS]], #0
70 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
71 ; CHECK-NOT: dmb
72 ; CHECK-NOT: mcr
73
74 ; CHECK: mov r0, r[[OLD]]
75    ret i32 %old
76 }
77
78 define void @test_atomic_load_add_i64(i64 %offset) nounwind {
79 ; CHECK-LABEL: test_atomic_load_add_i64:
80    %old = atomicrmw add i64* @var64, i64 %offset monotonic
81 ; CHECK-NOT: dmb
82 ; CHECK-NOT: mcr
83 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
84 ; CHECK: movt r[[ADDR]], :upper16:var64
85
86 ; CHECK: .LBB{{[0-9]+}}_1:
87 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]]
88   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
89   ; function there.
90 ; CHECK-NEXT: adds{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0
91 ; CHECK-NEXT: adc{{(\.w)?}}  [[NEW2:r[0-9]+]], r[[OLD2]], r1
92 ; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]]
93 ; CHECK-NEXT: cmp [[STATUS]], #0
94 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
95 ; CHECK-NOT: dmb
96 ; CHECK-NOT: mcr
97
98 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
99   store i64 %old, i64* @var64
100    ret void
101 }
102
103 define i8 @test_atomic_load_sub_i8(i8 %offset) nounwind {
104 ; CHECK-LABEL: test_atomic_load_sub_i8:
105    %old = atomicrmw sub i8* @var8, i8 %offset monotonic
106 ; CHECK-NOT: dmb
107 ; CHECK-NOT: mcr
108 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
109 ; CHECK: movt r[[ADDR]], :upper16:var8
110
111 ; CHECK: .LBB{{[0-9]+}}_1:
112 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]]
113   ; r0 below is a reasonable guess but could change: it certainly comes into the
114   ;  function there.
115 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
116 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
117 ; CHECK-NEXT: cmp [[STATUS]], #0
118 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
119 ; CHECK-NOT: dmb
120 ; CHECK-NOT: mcr
121
122 ; CHECK: mov r0, r[[OLD]]
123    ret i8 %old
124 }
125
126 define i16 @test_atomic_load_sub_i16(i16 %offset) nounwind {
127 ; CHECK-LABEL: test_atomic_load_sub_i16:
128    %old = atomicrmw sub i16* @var16, i16 %offset release
129 ; CHECK-NOT: dmb
130 ; CHECK-NOT: mcr
131 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
132 ; CHECK: movt r[[ADDR]], :upper16:var16
133
134 ; CHECK: .LBB{{[0-9]+}}_1:
135 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]]
136   ; r0 below is a reasonable guess but could change: it certainly comes into the
137   ;  function there.
138 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
139 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
140 ; CHECK-NEXT: cmp [[STATUS]], #0
141 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
142 ; CHECK-NOT: dmb
143 ; CHECK-NOT: mcr
144
145 ; CHECK: mov r0, r[[OLD]]
146    ret i16 %old
147 }
148
149 define i32 @test_atomic_load_sub_i32(i32 %offset) nounwind {
150 ; CHECK-LABEL: test_atomic_load_sub_i32:
151    %old = atomicrmw sub i32* @var32, i32 %offset acquire
152 ; CHECK-NOT: dmb
153 ; CHECK-NOT: mcr
154 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
155 ; CHECK: movt r[[ADDR]], :upper16:var32
156
157 ; CHECK: .LBB{{[0-9]+}}_1:
158 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
159   ; r0 below is a reasonable guess but could change: it certainly comes into the
160   ;  function there.
161 ; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0
162 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
163 ; CHECK-NEXT: cmp [[STATUS]], #0
164 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
165 ; CHECK-NOT: dmb
166 ; CHECK-NOT: mcr
167
168 ; CHECK: mov r0, r[[OLD]]
169    ret i32 %old
170 }
171
172 define void @test_atomic_load_sub_i64(i64 %offset) nounwind {
173 ; CHECK-LABEL: test_atomic_load_sub_i64:
174    %old = atomicrmw sub i64* @var64, i64 %offset seq_cst
175 ; CHECK-NOT: dmb
176 ; CHECK-NOT: mcr
177 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
178 ; CHECK: movt r[[ADDR]], :upper16:var64
179
180 ; CHECK: .LBB{{[0-9]+}}_1:
181 ; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]]
182   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
183   ; function there.
184 ; CHECK-NEXT: subs{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0
185 ; CHECK-NEXT: sbc{{(\.w)?}}  [[NEW2:r[0-9]+]], r[[OLD2]], r1
186 ; CHECK-NEXT: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]]
187 ; CHECK-NEXT: cmp [[STATUS]], #0
188 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
189 ; CHECK-NOT: dmb
190 ; CHECK-NOT: mcr
191
192 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
193    store i64 %old, i64* @var64
194    ret void
195 }
196
197 define i8 @test_atomic_load_and_i8(i8 %offset) nounwind {
198 ; CHECK-LABEL: test_atomic_load_and_i8:
199    %old = atomicrmw and i8* @var8, i8 %offset release
200 ; CHECK-NOT: dmb
201 ; CHECK-NOT: mcr
202 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
203 ; CHECK: movt r[[ADDR]], :upper16:var8
204
205 ; CHECK: .LBB{{[0-9]+}}_1:
206 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]]
207   ; r0 below is a reasonable guess but could change: it certainly comes into the
208   ;  function there.
209 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
210 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
211 ; CHECK-NEXT: cmp [[STATUS]], #0
212 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
213 ; CHECK-NOT: dmb
214 ; CHECK-NOT: mcr
215
216 ; CHECK: mov r0, r[[OLD]]
217    ret i8 %old
218 }
219
220 define i16 @test_atomic_load_and_i16(i16 %offset) nounwind {
221 ; CHECK-LABEL: test_atomic_load_and_i16:
222    %old = atomicrmw and i16* @var16, i16 %offset monotonic
223 ; CHECK-NOT: dmb
224 ; CHECK-NOT: mcr
225 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
226 ; CHECK: movt r[[ADDR]], :upper16:var16
227
228 ; CHECK: .LBB{{[0-9]+}}_1:
229 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]]
230   ; r0 below is a reasonable guess but could change: it certainly comes into the
231   ;  function there.
232 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
233 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
234 ; CHECK-NEXT: cmp [[STATUS]], #0
235 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
236 ; CHECK-NOT: dmb
237 ; CHECK-NOT: mcr
238
239 ; CHECK: mov r0, r[[OLD]]
240    ret i16 %old
241 }
242
243 define i32 @test_atomic_load_and_i32(i32 %offset) nounwind {
244 ; CHECK-LABEL: test_atomic_load_and_i32:
245    %old = atomicrmw and i32* @var32, i32 %offset seq_cst
246 ; CHECK-NOT: dmb
247 ; CHECK-NOT: mcr
248 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
249 ; CHECK: movt r[[ADDR]], :upper16:var32
250
251 ; CHECK: .LBB{{[0-9]+}}_1:
252 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
253   ; r0 below is a reasonable guess but could change: it certainly comes into the
254   ;  function there.
255 ; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
256 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
257 ; CHECK-NEXT: cmp [[STATUS]], #0
258 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
259 ; CHECK-NOT: dmb
260 ; CHECK-NOT: mcr
261
262 ; CHECK: mov r0, r[[OLD]]
263    ret i32 %old
264 }
265
266 define void @test_atomic_load_and_i64(i64 %offset) nounwind {
267 ; CHECK-LABEL: test_atomic_load_and_i64:
268    %old = atomicrmw and i64* @var64, i64 %offset acquire
269 ; CHECK-NOT: dmb
270 ; CHECK-NOT: mcr
271 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
272 ; CHECK: movt r[[ADDR]], :upper16:var64
273
274 ; CHECK: .LBB{{[0-9]+}}_1:
275 ; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]]
276   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
277   ; function there.
278 ; CHECK-DAG: and{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0
279 ; CHECK-DAG: and{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1
280 ; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]]
281 ; CHECK-NEXT: cmp [[STATUS]], #0
282 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
283 ; CHECK-NOT: dmb
284 ; CHECK-NOT: mcr
285
286 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
287    store i64 %old, i64* @var64
288    ret void
289 }
290
291 define i8 @test_atomic_load_or_i8(i8 %offset) nounwind {
292 ; CHECK-LABEL: test_atomic_load_or_i8:
293    %old = atomicrmw or i8* @var8, i8 %offset seq_cst
294 ; CHECK-NOT: dmb
295 ; CHECK-NOT: mcr
296 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
297 ; CHECK: movt r[[ADDR]], :upper16:var8
298
299 ; CHECK: .LBB{{[0-9]+}}_1:
300 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
301   ; r0 below is a reasonable guess but could change: it certainly comes into the
302   ;  function there.
303 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
304 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
305 ; CHECK-NEXT: cmp [[STATUS]], #0
306 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
307 ; CHECK-NOT: dmb
308 ; CHECK-NOT: mcr
309
310 ; CHECK: mov r0, r[[OLD]]
311    ret i8 %old
312 }
313
314 define i16 @test_atomic_load_or_i16(i16 %offset) nounwind {
315 ; CHECK-LABEL: test_atomic_load_or_i16:
316    %old = atomicrmw or i16* @var16, i16 %offset monotonic
317 ; CHECK-NOT: dmb
318 ; CHECK-NOT: mcr
319 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
320 ; CHECK: movt r[[ADDR]], :upper16:var16
321
322 ; CHECK: .LBB{{[0-9]+}}_1:
323 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]]
324   ; r0 below is a reasonable guess but could change: it certainly comes into the
325   ;  function there.
326 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
327 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
328 ; CHECK-NEXT: cmp [[STATUS]], #0
329 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
330 ; CHECK-NOT: dmb
331 ; CHECK-NOT: mcr
332
333 ; CHECK: mov r0, r[[OLD]]
334    ret i16 %old
335 }
336
337 define i32 @test_atomic_load_or_i32(i32 %offset) nounwind {
338 ; CHECK-LABEL: test_atomic_load_or_i32:
339    %old = atomicrmw or i32* @var32, i32 %offset acquire
340 ; CHECK-NOT: dmb
341 ; CHECK-NOT: mcr
342 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
343 ; CHECK: movt r[[ADDR]], :upper16:var32
344
345 ; CHECK: .LBB{{[0-9]+}}_1:
346 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
347   ; r0 below is a reasonable guess but could change: it certainly comes into the
348   ;  function there.
349 ; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
350 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
351 ; CHECK-NEXT: cmp [[STATUS]], #0
352 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
353 ; CHECK-NOT: dmb
354 ; CHECK-NOT: mcr
355
356 ; CHECK: mov r0, r[[OLD]]
357    ret i32 %old
358 }
359
360 define void @test_atomic_load_or_i64(i64 %offset) nounwind {
361 ; CHECK-LABEL: test_atomic_load_or_i64:
362    %old = atomicrmw or i64* @var64, i64 %offset release
363 ; CHECK-NOT: dmb
364 ; CHECK-NOT: mcr
365 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
366 ; CHECK: movt r[[ADDR]], :upper16:var64
367
368 ; CHECK: .LBB{{[0-9]+}}_1:
369 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]]
370   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
371   ; function there.
372 ; CHECK-DAG: orr{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0
373 ; CHECK-DAG: orr{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1
374 ; CHECK: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]]
375 ; CHECK-NEXT: cmp [[STATUS]], #0
376 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
377 ; CHECK-NOT: dmb
378 ; CHECK-NOT: mcr
379
380 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
381    store i64 %old, i64* @var64
382    ret void
383 }
384
385 define i8 @test_atomic_load_xor_i8(i8 %offset) nounwind {
386 ; CHECK-LABEL: test_atomic_load_xor_i8:
387    %old = atomicrmw xor i8* @var8, i8 %offset acquire
388 ; CHECK-NOT: dmb
389 ; CHECK-NOT: mcr
390 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
391 ; CHECK: movt r[[ADDR]], :upper16:var8
392
393 ; CHECK: .LBB{{[0-9]+}}_1:
394 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
395   ; r0 below is a reasonable guess but could change: it certainly comes into the
396   ;  function there.
397 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
398 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
399 ; CHECK-NEXT: cmp [[STATUS]], #0
400 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
401 ; CHECK-NOT: dmb
402 ; CHECK-NOT: mcr
403
404 ; CHECK: mov r0, r[[OLD]]
405    ret i8 %old
406 }
407
408 define i16 @test_atomic_load_xor_i16(i16 %offset) nounwind {
409 ; CHECK-LABEL: test_atomic_load_xor_i16:
410    %old = atomicrmw xor i16* @var16, i16 %offset release
411 ; CHECK-NOT: dmb
412 ; CHECK-NOT: mcr
413 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
414 ; CHECK: movt r[[ADDR]], :upper16:var16
415
416 ; CHECK: .LBB{{[0-9]+}}_1:
417 ; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]]
418   ; r0 below is a reasonable guess but could change: it certainly comes into the
419   ;  function there.
420 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
421 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
422 ; CHECK-NEXT: cmp [[STATUS]], #0
423 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
424 ; CHECK-NOT: dmb
425 ; CHECK-NOT: mcr
426
427 ; CHECK: mov r0, r[[OLD]]
428    ret i16 %old
429 }
430
431 define i32 @test_atomic_load_xor_i32(i32 %offset) nounwind {
432 ; CHECK-LABEL: test_atomic_load_xor_i32:
433    %old = atomicrmw xor i32* @var32, i32 %offset seq_cst
434 ; CHECK-NOT: dmb
435 ; CHECK-NOT: mcr
436 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
437 ; CHECK: movt r[[ADDR]], :upper16:var32
438
439 ; CHECK: .LBB{{[0-9]+}}_1:
440 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
441   ; r0 below is a reasonable guess but could change: it certainly comes into the
442   ;  function there.
443 ; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0
444 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]]
445 ; CHECK-NEXT: cmp [[STATUS]], #0
446 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
447 ; CHECK-NOT: dmb
448 ; CHECK-NOT: mcr
449
450 ; CHECK: mov r0, r[[OLD]]
451    ret i32 %old
452 }
453
454 define void @test_atomic_load_xor_i64(i64 %offset) nounwind {
455 ; CHECK-LABEL: test_atomic_load_xor_i64:
456    %old = atomicrmw xor i64* @var64, i64 %offset monotonic
457 ; CHECK-NOT: dmb
458 ; CHECK-NOT: mcr
459 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
460 ; CHECK: movt r[[ADDR]], :upper16:var64
461
462 ; CHECK: .LBB{{[0-9]+}}_1:
463 ; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]]
464   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
465   ; function there.
466 ; CHECK-DAG: eor{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0
467 ; CHECK-DAG: eor{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1
468 ; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]]
469 ; CHECK-NEXT: cmp [[STATUS]], #0
470 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
471 ; CHECK-NOT: dmb
472 ; CHECK-NOT: mcr
473
474 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
475    store i64 %old, i64* @var64
476    ret void
477 }
478
479 define i8 @test_atomic_load_xchg_i8(i8 %offset) nounwind {
480 ; CHECK-LABEL: test_atomic_load_xchg_i8:
481    %old = atomicrmw xchg i8* @var8, i8 %offset monotonic
482 ; CHECK-NOT: dmb
483 ; CHECK-NOT: mcr
484 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
485 ; CHECK: movt r[[ADDR]], :upper16:var8
486
487 ; CHECK: .LBB{{[0-9]+}}_1:
488 ; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]]
489   ; r0 below is a reasonable guess but could change: it certainly comes into the
490   ;  function there.
491 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r0, [r[[ADDR]]]
492 ; CHECK-NEXT: cmp [[STATUS]], #0
493 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
494 ; CHECK-NOT: dmb
495 ; CHECK-NOT: mcr
496
497 ; CHECK: mov r0, r[[OLD]]
498    ret i8 %old
499 }
500
501 define i16 @test_atomic_load_xchg_i16(i16 %offset) nounwind {
502 ; CHECK-LABEL: test_atomic_load_xchg_i16:
503    %old = atomicrmw xchg i16* @var16, i16 %offset seq_cst
504 ; CHECK-NOT: dmb
505 ; CHECK-NOT: mcr
506 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
507 ; CHECK: movt r[[ADDR]], :upper16:var16
508
509 ; CHECK: .LBB{{[0-9]+}}_1:
510 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
511   ; r0 below is a reasonable guess but could change: it certainly comes into the
512   ;  function there.
513 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r0, [r[[ADDR]]]
514 ; CHECK-NEXT: cmp [[STATUS]], #0
515 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
516 ; CHECK-NOT: dmb
517 ; CHECK-NOT: mcr
518
519 ; CHECK: mov r0, r[[OLD]]
520    ret i16 %old
521 }
522
523 define i32 @test_atomic_load_xchg_i32(i32 %offset) nounwind {
524 ; CHECK-LABEL: test_atomic_load_xchg_i32:
525    %old = atomicrmw xchg i32* @var32, i32 %offset release
526 ; CHECK-NOT: dmb
527 ; CHECK-NOT: mcr
528 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
529 ; CHECK: movt r[[ADDR]], :upper16:var32
530
531 ; CHECK: .LBB{{[0-9]+}}_1:
532 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
533   ; r0 below is a reasonable guess but could change: it certainly comes into the
534   ;  function there.
535 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r0, [r[[ADDR]]]
536 ; CHECK-NEXT: cmp [[STATUS]], #0
537 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
538 ; CHECK-NOT: dmb
539 ; CHECK-NOT: mcr
540
541 ; CHECK: mov r0, r[[OLD]]
542    ret i32 %old
543 }
544
545 define void @test_atomic_load_xchg_i64(i64 %offset) nounwind {
546 ; CHECK-LABEL: test_atomic_load_xchg_i64:
547    %old = atomicrmw xchg i64* @var64, i64 %offset acquire
548 ; CHECK-NOT: dmb
549 ; CHECK-NOT: mcr
550 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
551 ; CHECK: movt r[[ADDR]], :upper16:var64
552
553 ; CHECK: .LBB{{[0-9]+}}_1:
554 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]]
555   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
556   ; function there.
557 ; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], r0, r1, [r[[ADDR]]]
558 ; CHECK-NEXT: cmp [[STATUS]], #0
559 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
560 ; CHECK-NOT: dmb
561 ; CHECK-NOT: mcr
562
563 ; CHECK: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
564    store i64 %old, i64* @var64
565    ret void
566 }
567
568 define i8 @test_atomic_load_min_i8(i8 signext %offset) nounwind {
569 ; CHECK-LABEL: test_atomic_load_min_i8:
570    %old = atomicrmw min i8* @var8, i8 %offset acquire
571 ; CHECK-NOT: dmb
572 ; CHECK-NOT: mcr
573 ; CHECK-DAG: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
574 ; CHECK-DAG: movt [[ADDR]], :upper16:var8
575
576 ; CHECK: .LBB{{[0-9]+}}_1:
577 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
578 ; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]]
579   ; r0 below is a reasonable guess but could change: it certainly comes into the
580   ;  function there.
581 ; CHECK-NEXT: cmp r[[OLDX]], r0
582 ; Thumb mode: it le
583 ; CHECK:      movle r[[OLDX]], r[[OLD]]
584 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]]]
585 ; CHECK-NEXT: cmp [[STATUS]], #0
586 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
587 ; CHECK-NOT: dmb
588 ; CHECK-NOT: mcr
589
590 ; CHECK: mov r0, r[[OLD]]
591    ret i8 %old
592 }
593
594 define i16 @test_atomic_load_min_i16(i16 signext %offset) nounwind {
595 ; CHECK-LABEL: test_atomic_load_min_i16:
596    %old = atomicrmw min i16* @var16, i16 %offset release
597 ; CHECK-NOT: dmb
598 ; CHECK-NOT: mcr
599 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
600 ; CHECK: movt [[ADDR]], :upper16:var16
601
602 ; CHECK: .LBB{{[0-9]+}}_1:
603 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
604 ; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]]
605   ; r0 below is a reasonable guess but could change: it certainly comes into the
606   ;  function there.
607 ; CHECK-NEXT: cmp r[[OLDX]], r0
608 ; Thumb mode: it le
609 ; CHECK:      movle r[[OLDX]], r[[OLD]]
610 ; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]]
611 ; CHECK-NEXT: cmp [[STATUS]], #0
612 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
613 ; CHECK-NOT: dmb
614 ; CHECK-NOT: mcr
615
616 ; CHECK: mov r0, r[[OLD]]
617    ret i16 %old
618 }
619
620 define i32 @test_atomic_load_min_i32(i32 %offset) nounwind {
621 ; CHECK-LABEL: test_atomic_load_min_i32:
622    %old = atomicrmw min i32* @var32, i32 %offset monotonic
623 ; CHECK-NOT: dmb
624 ; CHECK-NOT: mcr
625 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
626 ; CHECK: movt r[[ADDR]], :upper16:var32
627
628 ; CHECK: .LBB{{[0-9]+}}_1:
629 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
630   ; r0 below is a reasonable guess but could change: it certainly comes into the
631   ;  function there.
632 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
633 ; CHECK-NEXT: cmp r[[OLD]], r0
634 ; Thumb mode: it le
635 ; CHECK:      movle r[[NEW]], r[[OLD]]
636 ; CHECK-NEXT: strex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]]
637 ; CHECK-NEXT: cmp [[STATUS]], #0
638 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
639 ; CHECK-NOT: dmb
640 ; CHECK-NOT: mcr
641
642 ; CHECK: mov r0, r[[OLD]]
643    ret i32 %old
644 }
645
646 define void @test_atomic_load_min_i64(i64 %offset) nounwind {
647 ; CHECK-LABEL: test_atomic_load_min_i64:
648    %old = atomicrmw min i64* @var64, i64 %offset seq_cst
649 ; CHECK-NOT: dmb
650 ; CHECK-NOT: mcr
651 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
652 ; CHECK: movt r[[ADDR]], :upper16:var64
653
654 ; CHECK: .LBB{{[0-9]+}}_1:
655 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
656   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
657   ; function there.
658 ; CHECK-ARM: mov [[LOCARRY:r[0-9]+|lr]], #0
659 ; CHECK-ARM: mov [[HICARRY:r[0-9]+|lr]], #0
660 ; CHECK-ARM: cmp [[OLD1]], r0
661 ; CHECK-ARM: movwls [[LOCARRY]], #1
662 ; CHECK-ARM: cmp [[OLD2]], r1
663 ; CHECK-ARM: movwle [[HICARRY]], #1
664 ; CHECK-ARM: moveq [[HICARRY]], [[LOCARRY]]
665 ; CHECK-ARM: cmp [[HICARRY]], #0
666 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1
667 ; CHECK-ARM: movne [[MINHI]], [[OLD2]]
668 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0
669 ; CHECK-ARM: movne [[MINLO]], [[OLD1]]
670 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]]
671 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]]
672 ; CHECK-NEXT: cmp [[STATUS]], #0
673 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
674 ; CHECK-NOT: dmb
675 ; CHECK-NOT: mcr
676
677 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
678    store i64 %old, i64* @var64
679    ret void
680 }
681
682 define i8 @test_atomic_load_max_i8(i8 signext %offset) nounwind {
683 ; CHECK-LABEL: test_atomic_load_max_i8:
684    %old = atomicrmw max i8* @var8, i8 %offset seq_cst
685 ; CHECK-NOT: dmb
686 ; CHECK-NOT: mcr
687 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
688 ; CHECK: movt [[ADDR]], :upper16:var8
689
690 ; CHECK: .LBB{{[0-9]+}}_1:
691 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
692 ; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]]
693   ; r0 below is a reasonable guess but could change: it certainly comes into the
694   ;  function there.
695 ; CHECK-NEXT: cmp r[[OLDX]], r0
696 ; Thumb mode: it gt
697 ; CHECK:      movgt r[[OLDX]], r[[OLD]]
698 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]]
699 ; CHECK-NEXT: cmp [[STATUS]], #0
700 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
701 ; CHECK-NOT: dmb
702 ; CHECK-NOT: mcr
703
704 ; CHECK: mov r0, r[[OLD]]
705    ret i8 %old
706 }
707
708 define i16 @test_atomic_load_max_i16(i16 signext %offset) nounwind {
709 ; CHECK-LABEL: test_atomic_load_max_i16:
710    %old = atomicrmw max i16* @var16, i16 %offset acquire
711 ; CHECK-NOT: dmb
712 ; CHECK-NOT: mcr
713 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
714 ; CHECK: movt r[[ADDR]], :upper16:var16
715
716 ; CHECK: .LBB{{[0-9]+}}_1:
717 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
718 ; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]]
719   ; r0 below is a reasonable guess but could change: it certainly comes into the
720   ;  function there.
721 ; CHECK-NEXT: cmp r[[OLDX]], r0
722 ; Thumb mode: it gt
723 ; CHECK:      movgt r[[OLDX]], r[[OLD]]
724 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[OLDX]], [r[[ADDR]]]
725 ; CHECK-NEXT: cmp [[STATUS]], #0
726 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
727 ; CHECK-NOT: dmb
728 ; CHECK-NOT: mcr
729
730 ; CHECK: mov r0, r[[OLD]]
731    ret i16 %old
732 }
733
734 define i32 @test_atomic_load_max_i32(i32 %offset) nounwind {
735 ; CHECK-LABEL: test_atomic_load_max_i32:
736    %old = atomicrmw max i32* @var32, i32 %offset release
737 ; CHECK-NOT: dmb
738 ; CHECK-NOT: mcr
739 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
740 ; CHECK: movt r[[ADDR]], :upper16:var32
741
742 ; CHECK: .LBB{{[0-9]+}}_1:
743 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
744   ; r0 below is a reasonable guess but could change: it certainly comes into the
745   ;  function there.
746 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
747 ; CHECK-NEXT: cmp r[[OLD]], r0
748 ; Thumb mode: it gt
749 ; CHECK:      movgt r[[NEW]], r[[OLD]]
750 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]]
751 ; CHECK-NEXT: cmp [[STATUS]], #0
752 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
753 ; CHECK-NOT: dmb
754 ; CHECK-NOT: mcr
755
756 ; CHECK: mov r0, r[[OLD]]
757    ret i32 %old
758 }
759
760 define void @test_atomic_load_max_i64(i64 %offset) nounwind {
761 ; CHECK-LABEL: test_atomic_load_max_i64:
762    %old = atomicrmw max i64* @var64, i64 %offset monotonic
763 ; CHECK-NOT: dmb
764 ; CHECK-NOT: mcr
765 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
766 ; CHECK: movt r[[ADDR]], :upper16:var64
767
768 ; CHECK: .LBB{{[0-9]+}}_1:
769 ; CHECK: ldrexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
770   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
771   ; function there.
772 ; CHECK-ARM: mov [[LOCARRY:r[0-9]+|lr]], #0
773 ; CHECK-ARM: mov [[HICARRY:r[0-9]+|lr]], #0
774 ; CHECK-ARM: cmp [[OLD1]], r0
775 ; CHECK-ARM: movwhi [[LOCARRY]], #1
776 ; CHECK-ARM: cmp [[OLD2]], r1
777 ; CHECK-ARM: movwgt [[HICARRY]], #1
778 ; CHECK-ARM: moveq [[HICARRY]], [[LOCARRY]]
779 ; CHECK-ARM: cmp [[HICARRY]], #0
780 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1
781 ; CHECK-ARM: movne [[MINHI]], [[OLD2]]
782 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0
783 ; CHECK-ARM: movne [[MINLO]], [[OLD1]]
784 ; CHECK-ARM: strexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]]
785 ; CHECK-THUMB: strexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]]
786 ; CHECK-NEXT: cmp [[STATUS]], #0
787 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
788 ; CHECK-NOT: dmb
789 ; CHECK-NOT: mcr
790
791 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
792    store i64 %old, i64* @var64
793    ret void
794 }
795
796 define i8 @test_atomic_load_umin_i8(i8 zeroext %offset) nounwind {
797 ; CHECK-LABEL: test_atomic_load_umin_i8:
798    %old = atomicrmw umin i8* @var8, i8 %offset monotonic
799 ; CHECK-NOT: dmb
800 ; CHECK-NOT: mcr
801 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
802 ; CHECK: movt [[ADDR]], :upper16:var8
803
804 ; CHECK: .LBB{{[0-9]+}}_1:
805 ; CHECK: ldrexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
806   ; r0 below is a reasonable guess but could change: it certainly comes into the
807   ;  function there.
808 ; CHECK-NEXT: uxtb r[[OLDX]], r[[OLD]]
809 ; CHECK-NEXT: cmp r[[OLDX]], r0
810 ; Thumb mode: it ls
811 ; CHECK:      movls r[[NEW]], r[[OLD]]
812 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
813 ; CHECK-NEXT: cmp [[STATUS]], #0
814 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
815 ; CHECK-NOT: dmb
816 ; CHECK-NOT: mcr
817
818 ; CHECK: mov r0, r[[OLD]]
819    ret i8 %old
820 }
821
822 define i16 @test_atomic_load_umin_i16(i16 zeroext %offset) nounwind {
823 ; CHECK-LABEL: test_atomic_load_umin_i16:
824    %old = atomicrmw umin i16* @var16, i16 %offset acquire
825 ; CHECK-NOT: dmb
826 ; CHECK-NOT: mcr
827 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
828 ; CHECK: movt [[ADDR]], :upper16:var16
829
830 ; CHECK: .LBB{{[0-9]+}}_1:
831 ; CHECK: ldaexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
832   ; r0 below is a reasonable guess but could change: it certainly comes into the
833   ;  function there.
834 ; CHECK-NEXT: uxth r[[OLDX]], r[[OLD]]
835 ; CHECK-NEXT: cmp r[[OLDX]], r0
836 ; Thumb mode: it ls
837 ; CHECK:      movls r[[NEW]], r[[OLD]]
838 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
839 ; CHECK-NEXT: cmp [[STATUS]], #0
840 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
841 ; CHECK-NOT: dmb
842 ; CHECK-NOT: mcr
843
844 ; CHECK: mov r0, r[[OLD]]
845    ret i16 %old
846 }
847
848 define i32 @test_atomic_load_umin_i32(i32 %offset) nounwind {
849 ; CHECK-LABEL: test_atomic_load_umin_i32:
850    %old = atomicrmw umin i32* @var32, i32 %offset seq_cst
851 ; CHECK-NOT: dmb
852 ; CHECK-NOT: mcr
853 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
854 ; CHECK: movt r[[ADDR]], :upper16:var32
855
856 ; CHECK: .LBB{{[0-9]+}}_1:
857 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
858   ; r0 below is a reasonable guess but could change: it certainly comes into the
859   ;  function there.
860 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
861 ; CHECK-NEXT: cmp r[[OLD]], r0
862 ; Thumb mode: it ls
863 ; CHECK:      movls r[[NEW]], r[[OLD]]
864 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]]
865 ; CHECK-NEXT: cmp [[STATUS]], #0
866 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
867 ; CHECK-NOT: dmb
868 ; CHECK-NOT: mcr
869
870 ; CHECK: mov r0, r[[OLD]]
871    ret i32 %old
872 }
873
874 define void @test_atomic_load_umin_i64(i64 %offset) nounwind {
875 ; CHECK-LABEL: test_atomic_load_umin_i64:
876    %old = atomicrmw umin i64* @var64, i64 %offset seq_cst
877 ; CHECK-NOT: dmb
878 ; CHECK-NOT: mcr
879 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
880 ; CHECK: movt r[[ADDR]], :upper16:var64
881
882 ; CHECK: .LBB{{[0-9]+}}_1:
883 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
884   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
885   ; function there.
886 ; CHECK-ARM: mov [[LOCARRY:r[0-9]+|lr]], #0
887 ; CHECK-ARM: mov [[HICARRY:r[0-9]+|lr]], #0
888 ; CHECK-ARM: cmp [[OLD1]], r0
889 ; CHECK-ARM: movwls [[LOCARRY]], #1
890 ; CHECK-ARM: cmp [[OLD2]], r1
891 ; CHECK-ARM: movwls [[HICARRY]], #1
892 ; CHECK-ARM: moveq [[HICARRY]], [[LOCARRY]]
893 ; CHECK-ARM: cmp [[HICARRY]], #0
894 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1
895 ; CHECK-ARM: movne [[MINHI]], [[OLD2]]
896 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0
897 ; CHECK-ARM: movne [[MINLO]], [[OLD1]]
898 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]]
899 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]]
900 ; CHECK-NEXT: cmp [[STATUS]], #0
901 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
902 ; CHECK-NOT: dmb
903 ; CHECK-NOT: mcr
904
905 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
906    store i64 %old, i64* @var64
907    ret void
908 }
909
910 define i8 @test_atomic_load_umax_i8(i8 zeroext %offset) nounwind {
911 ; CHECK-LABEL: test_atomic_load_umax_i8:
912    %old = atomicrmw umax i8* @var8, i8 %offset acq_rel
913 ; CHECK-NOT: dmb
914 ; CHECK-NOT: mcr
915 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
916 ; CHECK: movt [[ADDR]], :upper16:var8
917
918 ; CHECK: .LBB{{[0-9]+}}_1:
919 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
920   ; r0 below is a reasonable guess but could change: it certainly comes into the
921   ;  function there.
922 ; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
923 ; CHECK-NEXT: cmp r[[OLDX]], r0
924 ; Thumb mode: it hi
925 ; CHECK:      movhi r[[NEW]], r[[OLD]]
926 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
927 ; CHECK-NEXT: cmp [[STATUS]], #0
928 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
929 ; CHECK-NOT: dmb
930 ; CHECK-NOT: mcr
931
932 ; CHECK: mov r0, r[[OLD]]
933    ret i8 %old
934 }
935
936 define i16 @test_atomic_load_umax_i16(i16 zeroext %offset) nounwind {
937 ; CHECK-LABEL: test_atomic_load_umax_i16:
938    %old = atomicrmw umax i16* @var16, i16 %offset monotonic
939 ; CHECK-NOT: dmb
940 ; CHECK-NOT: mcr
941 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
942 ; CHECK: movt [[ADDR]], :upper16:var16
943
944 ; CHECK: .LBB{{[0-9]+}}_1:
945 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
946   ; r0 below is a reasonable guess but could change: it certainly comes into the
947   ;  function there.
948 ; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
949 ; CHECK-NEXT: cmp r[[OLDX]], r0
950 ; Thumb mode: it hi
951 ; CHECK:      movhi r[[NEW]], r[[OLD]]
952 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
953 ; CHECK-NEXT: cmp [[STATUS]], #0
954 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
955 ; CHECK-NOT: dmb
956 ; CHECK-NOT: mcr
957
958 ; CHECK: mov r0, r[[OLD]]
959    ret i16 %old
960 }
961
962 define i32 @test_atomic_load_umax_i32(i32 %offset) nounwind {
963 ; CHECK-LABEL: test_atomic_load_umax_i32:
964    %old = atomicrmw umax i32* @var32, i32 %offset seq_cst
965 ; CHECK-NOT: dmb
966 ; CHECK-NOT: mcr
967 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
968 ; CHECK: movt r[[ADDR]], :upper16:var32
969
970 ; CHECK: .LBB{{[0-9]+}}_1:
971 ; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]]
972   ; r0 below is a reasonable guess but could change: it certainly comes into the
973   ;  function there.
974 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
975 ; CHECK-NEXT: cmp r[[OLD]], r0
976 ; Thumb mode: it hi
977 ; CHECK:      movhi r[[NEW]], r[[OLD]]
978 ; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]]
979 ; CHECK-NEXT: cmp [[STATUS]], #0
980 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
981 ; CHECK-NOT: dmb
982 ; CHECK-NOT: mcr
983
984 ; CHECK: mov r0, r[[OLD]]
985    ret i32 %old
986 }
987
988 define void @test_atomic_load_umax_i64(i64 %offset) nounwind {
989 ; CHECK-LABEL: test_atomic_load_umax_i64:
990    %old = atomicrmw umax i64* @var64, i64 %offset seq_cst
991 ; CHECK-NOT: dmb
992 ; CHECK-NOT: mcr
993 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
994 ; CHECK: movt r[[ADDR]], :upper16:var64
995
996 ; CHECK: .LBB{{[0-9]+}}_1:
997 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
998   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
999   ; function there.
1000 ; CHECK-ARM: mov [[LOCARRY:r[0-9]+|lr]], #0
1001 ; CHECK-ARM: mov [[HICARRY:r[0-9]+|lr]], #0
1002 ; CHECK-ARM: cmp [[OLD1]], r0
1003 ; CHECK-ARM: movwhi [[LOCARRY]], #1
1004 ; CHECK-ARM: cmp [[OLD2]], r1
1005 ; CHECK-ARM: movwhi [[HICARRY]], #1
1006 ; CHECK-ARM: moveq [[HICARRY]], [[LOCARRY]]
1007 ; CHECK-ARM: cmp [[HICARRY]], #0
1008 ; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1
1009 ; CHECK-ARM: movne [[MINHI]], [[OLD2]]
1010 ; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0
1011 ; CHECK-ARM: movne [[MINLO]], [[OLD1]]
1012 ; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]]
1013 ; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]]
1014 ; CHECK-NEXT: cmp [[STATUS]], #0
1015 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1016 ; CHECK-NOT: dmb
1017 ; CHECK-NOT: mcr
1018
1019 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
1020    store i64 %old, i64* @var64
1021    ret void
1022 }
1023
1024 define i8 @test_atomic_cmpxchg_i8(i8 zeroext %wanted, i8 zeroext %new) nounwind {
1025 ; CHECK-LABEL: test_atomic_cmpxchg_i8:
1026    %old = cmpxchg i8* @var8, i8 %wanted, i8 %new acquire acquire
1027 ; CHECK-NOT: dmb
1028 ; CHECK-NOT: mcr
1029 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1030 ; CHECK: movt r[[ADDR]], :upper16:var8
1031
1032 ; CHECK: .LBB{{[0-9]+}}_1:
1033 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
1034   ; r0 below is a reasonable guess but could change: it certainly comes into the
1035   ;  function there.
1036 ; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
1037 ; CHECK-NEXT: cmp r[[OLDX]], r0
1038 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1039 ; CHECK-NEXT: BB#2:
1040   ; As above, r1 is a reasonable guess.
1041 ; CHECK: strexb [[STATUS:r[0-9]+]], r1, {{.*}}[[ADDR]]
1042 ; CHECK-NEXT: cmp [[STATUS]], #0
1043 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1044 ; CHECK-NOT: dmb
1045 ; CHECK-NOT: mcr
1046
1047 ; CHECK: mov r0, r[[OLD]]
1048    ret i8 %old
1049 }
1050
1051 define i16 @test_atomic_cmpxchg_i16(i16 zeroext %wanted, i16 zeroext %new) nounwind {
1052 ; CHECK-LABEL: test_atomic_cmpxchg_i16:
1053    %old = cmpxchg i16* @var16, i16 %wanted, i16 %new seq_cst seq_cst
1054 ; CHECK-NOT: dmb
1055 ; CHECK-NOT: mcr
1056 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1057 ; CHECK: movt r[[ADDR]], :upper16:var16
1058
1059 ; CHECK: .LBB{{[0-9]+}}_1:
1060 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
1061   ; r0 below is a reasonable guess but could change: it certainly comes into the
1062   ;  function there.
1063 ; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
1064 ; CHECK-NEXT: cmp r[[OLDX]], r0
1065 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1066 ; CHECK-NEXT: BB#2:
1067   ; As above, r1 is a reasonable guess.
1068 ; CHECK: stlexh [[STATUS:r[0-9]+]], r1, [r[[ADDR]]]
1069 ; CHECK-NEXT: cmp [[STATUS]], #0
1070 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1071 ; CHECK-NOT: dmb
1072 ; CHECK-NOT: mcr
1073
1074 ; CHECK: mov r0, r[[OLD]]
1075    ret i16 %old
1076 }
1077
1078 define i32 @test_atomic_cmpxchg_i32(i32 %wanted, i32 %new) nounwind {
1079 ; CHECK-LABEL: test_atomic_cmpxchg_i32:
1080    %old = cmpxchg i32* @var32, i32 %wanted, i32 %new release monotonic
1081 ; CHECK-NOT: dmb
1082 ; CHECK-NOT: mcr
1083 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
1084 ; CHECK: movt r[[ADDR]], :upper16:var32
1085
1086 ; CHECK: .LBB{{[0-9]+}}_1:
1087 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
1088   ; r0 below is a reasonable guess but could change: it certainly comes into the
1089   ;  function there.
1090 ; CHECK-NEXT: cmp r[[OLD]], r0
1091 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1092 ; CHECK-NEXT: BB#2:
1093   ; As above, r1 is a reasonable guess.
1094 ; CHECK: stlex [[STATUS:r[0-9]+]], r1, [r[[ADDR]]]
1095 ; CHECK-NEXT: cmp [[STATUS]], #0
1096 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1097 ; CHECK-NOT: dmb
1098 ; CHECK-NOT: mcr
1099
1100 ; CHECK: mov r0, r[[OLD]]
1101    ret i32 %old
1102 }
1103
1104 define void @test_atomic_cmpxchg_i64(i64 %wanted, i64 %new) nounwind {
1105 ; CHECK-LABEL: test_atomic_cmpxchg_i64:
1106    %old = cmpxchg i64* @var64, i64 %wanted, i64 %new monotonic monotonic
1107 ; CHECK-NOT: dmb
1108 ; CHECK-NOT: mcr
1109 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1110 ; CHECK: movt r[[ADDR]], :upper16:var64
1111
1112 ; CHECK: .LBB{{[0-9]+}}_1:
1113 ; CHECK: ldrexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]]
1114   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
1115   ; function there.
1116 ; CHECK-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0
1117 ; CHECK-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1
1118 ; CHECK: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_LO]], [[MISMATCH_HI]]
1119 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1120 ; CHECK-NEXT: BB#2:
1121   ; As above, r2, r3 is a reasonable guess.
1122 ; CHECK: strexd [[STATUS:r[0-9]+]], r2, r3, [r[[ADDR]]]
1123 ; CHECK-NEXT: cmp [[STATUS]], #0
1124 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1125 ; CHECK-NOT: dmb
1126 ; CHECK-NOT: mcr
1127
1128 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
1129    store i64 %old, i64* @var64
1130    ret void
1131 }
1132
1133 define i8 @test_atomic_load_monotonic_i8() nounwind {
1134 ; CHECK-LABEL: test_atomic_load_monotonic_i8:
1135   %val = load atomic i8* @var8 monotonic, align 1
1136 ; CHECK-NOT: dmb
1137 ; CHECK-NOT: mcr
1138 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1139 ; CHECK: movt r[[ADDR]], :upper16:var8
1140 ; CHECK: ldrb r0, [r[[ADDR]]]
1141 ; CHECK-NOT: dmb
1142 ; CHECK-NOT: mcr
1143
1144   ret i8 %val
1145 }
1146
1147 define i8 @test_atomic_load_monotonic_regoff_i8(i64 %base, i64 %off) nounwind {
1148 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i8:
1149   %addr_int = add i64 %base, %off
1150   %addr = inttoptr i64 %addr_int to i8*
1151
1152   %val = load atomic i8* %addr monotonic, align 1
1153 ; CHECK-NOT: dmb
1154 ; CHECK-NOT: mcr
1155 ; CHECK: ldrb r0, [r0, r2]
1156 ; CHECK-NOT: dmb
1157 ; CHECK-NOT: mcr
1158
1159   ret i8 %val
1160 }
1161
1162 define i8 @test_atomic_load_acquire_i8() nounwind {
1163 ; CHECK-LABEL: test_atomic_load_acquire_i8:
1164   %val = load atomic i8* @var8 acquire, align 1
1165 ; CHECK-NOT: dmb
1166 ; CHECK-NOT: mcr
1167 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1168 ; CHECK-NOT: dmb
1169 ; CHECK-NOT: mcr
1170 ; CHECK: movt r[[ADDR]], :upper16:var8
1171 ; CHECK-NOT: dmb
1172 ; CHECK-NOT: mcr
1173 ; CHECK: ldab r0, [r[[ADDR]]]
1174 ; CHECK-NOT: dmb
1175 ; CHECK-NOT: mcr
1176   ret i8 %val
1177 }
1178
1179 define i8 @test_atomic_load_seq_cst_i8() nounwind {
1180 ; CHECK-LABEL: test_atomic_load_seq_cst_i8:
1181   %val = load atomic i8* @var8 seq_cst, align 1
1182 ; CHECK-NOT: dmb
1183 ; CHECK-NOT: mcr
1184 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1185 ; CHECK-NOT: dmb
1186 ; CHECK-NOT: mcr
1187 ; CHECK: movt r[[ADDR]], :upper16:var8
1188 ; CHECK-NOT: dmb
1189 ; CHECK-NOT: mcr
1190 ; CHECK: ldab r0, [r[[ADDR]]]
1191 ; CHECK-NOT: dmb
1192 ; CHECK-NOT: mcr
1193   ret i8 %val
1194 }
1195
1196 define i16 @test_atomic_load_monotonic_i16() nounwind {
1197 ; CHECK-LABEL: test_atomic_load_monotonic_i16:
1198   %val = load atomic i16* @var16 monotonic, align 2
1199 ; CHECK-NOT: dmb
1200 ; CHECK-NOT: mcr
1201 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1202 ; CHECK-NOT: dmb
1203 ; CHECK-NOT: mcr
1204 ; CHECK: movt r[[ADDR]], :upper16:var16
1205 ; CHECK-NOT: dmb
1206 ; CHECK-NOT: mcr
1207 ; CHECK: ldrh r0, [r[[ADDR]]]
1208 ; CHECK-NOT: dmb
1209 ; CHECK-NOT: mcr
1210
1211   ret i16 %val
1212 }
1213
1214 define i32 @test_atomic_load_monotonic_regoff_i32(i64 %base, i64 %off) nounwind {
1215 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i32:
1216   %addr_int = add i64 %base, %off
1217   %addr = inttoptr i64 %addr_int to i32*
1218
1219   %val = load atomic i32* %addr monotonic, align 4
1220 ; CHECK-NOT: dmb
1221 ; CHECK-NOT: mcr
1222 ; CHECK: ldr r0, [r0, r2]
1223 ; CHECK-NOT: dmb
1224 ; CHECK-NOT: mcr
1225
1226   ret i32 %val
1227 }
1228
1229 define i64 @test_atomic_load_seq_cst_i64() nounwind {
1230 ; CHECK-LABEL: test_atomic_load_seq_cst_i64:
1231   %val = load atomic i64* @var64 seq_cst, align 8
1232 ; CHECK-NOT: dmb
1233 ; CHECK-NOT: mcr
1234 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1235 ; CHECK-NOT: dmb
1236 ; CHECK-NOT: mcr
1237 ; CHECK: movt r[[ADDR]], :upper16:var64
1238 ; CHECK-NOT: dmb
1239 ; CHECK-NOT: mcr
1240 ; CHECK: ldaexd r0, r1, [r[[ADDR]]]
1241 ; CHECK-NOT: dmb
1242 ; CHECK-NOT: mcr
1243   ret i64 %val
1244 }
1245
1246 define void @test_atomic_store_monotonic_i8(i8 %val) nounwind {
1247 ; CHECK-LABEL: test_atomic_store_monotonic_i8:
1248   store atomic i8 %val, i8* @var8 monotonic, align 1
1249 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1250 ; CHECK: movt r[[ADDR]], :upper16:var8
1251 ; CHECK: strb r0, [r[[ADDR]]]
1252
1253   ret void
1254 }
1255
1256 define void @test_atomic_store_monotonic_regoff_i8(i64 %base, i64 %off, i8 %val) nounwind {
1257 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i8:
1258
1259   %addr_int = add i64 %base, %off
1260   %addr = inttoptr i64 %addr_int to i8*
1261
1262   store atomic i8 %val, i8* %addr monotonic, align 1
1263 ; CHECK: ldrb{{(\.w)?}} [[VAL:r[0-9]+]], [sp]
1264 ; CHECK: strb [[VAL]], [r0, r2]
1265
1266   ret void
1267 }
1268
1269 define void @test_atomic_store_release_i8(i8 %val) nounwind {
1270 ; CHECK-LABEL: test_atomic_store_release_i8:
1271   store atomic i8 %val, i8* @var8 release, align 1
1272 ; CHECK-NOT: dmb
1273 ; CHECK-NOT: mcr
1274 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1275 ; CHECK-NOT: dmb
1276 ; CHECK-NOT: mcr
1277 ; CHECK: movt r[[ADDR]], :upper16:var8
1278 ; CHECK-NOT: dmb
1279 ; CHECK-NOT: mcr
1280 ; CHECK: stlb r0, [r[[ADDR]]]
1281 ; CHECK-NOT: dmb
1282 ; CHECK-NOT: mcr
1283   ret void
1284 }
1285
1286 define void @test_atomic_store_seq_cst_i8(i8 %val) nounwind {
1287 ; CHECK-LABEL: test_atomic_store_seq_cst_i8:
1288   store atomic i8 %val, i8* @var8 seq_cst, align 1
1289 ; CHECK-NOT: dmb
1290 ; CHECK-NOT: mcr
1291 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1292 ; CHECK-NOT: dmb
1293 ; CHECK-NOT: mcr
1294 ; CHECK: movt r[[ADDR]], :upper16:var8
1295 ; CHECK-NOT: dmb
1296 ; CHECK-NOT: mcr
1297 ; CHECK: stlb r0, [r[[ADDR]]]
1298 ; CHECK-NOT: dmb
1299 ; CHECK-NOT: mcr
1300   ret void
1301 }
1302
1303 define void @test_atomic_store_monotonic_i16(i16 %val) nounwind {
1304 ; CHECK-LABEL: test_atomic_store_monotonic_i16:
1305   store atomic i16 %val, i16* @var16 monotonic, align 2
1306 ; CHECK-NOT: dmb
1307 ; CHECK-NOT: mcr
1308 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1309 ; CHECK-NOT: dmb
1310 ; CHECK-NOT: mcr
1311 ; CHECK: movt r[[ADDR]], :upper16:var16
1312 ; CHECK-NOT: dmb
1313 ; CHECK-NOT: mcr
1314 ; CHECK: strh r0, [r[[ADDR]]]
1315 ; CHECK-NOT: dmb
1316 ; CHECK-NOT: mcr
1317   ret void
1318 }
1319
1320 define void @test_atomic_store_monotonic_regoff_i32(i64 %base, i64 %off, i32 %val) nounwind {
1321 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i32:
1322
1323   %addr_int = add i64 %base, %off
1324   %addr = inttoptr i64 %addr_int to i32*
1325
1326   store atomic i32 %val, i32* %addr monotonic, align 4
1327 ; CHECK-NOT: dmb
1328 ; CHECK-NOT: mcr
1329 ; CHECK: ldr [[VAL:r[0-9]+]], [sp]
1330 ; CHECK-NOT: dmb
1331 ; CHECK-NOT: mcr
1332 ; CHECK: str [[VAL]], [r0, r2]
1333 ; CHECK-NOT: dmb
1334 ; CHECK-NOT: mcr
1335
1336   ret void
1337 }
1338
1339 define void @test_atomic_store_release_i64(i64 %val) nounwind {
1340 ; CHECK-LABEL: test_atomic_store_release_i64:
1341   store atomic i64 %val, i64* @var64 release, align 8
1342 ; CHECK-NOT: dmb
1343 ; CHECK-NOT: mcr
1344 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var64
1345 ; CHECK: movt [[ADDR]], :upper16:var64
1346
1347 ; CHECK: .LBB{{[0-9]+}}_1:
1348   ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
1349   ; function there.
1350 ; CHECK: stlexd [[STATUS:r[0-9]+]], r0, r1, {{.*}}[[ADDR]]
1351 ; CHECK-NEXT: cmp [[STATUS]], #0
1352 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1353 ; CHECK-NOT: dmb
1354 ; CHECK-NOT: mcr
1355
1356   ret void
1357 }
1358
1359 define i32 @not.barriers(i32* %var, i1 %cond) {
1360 ; CHECK-LABEL: not.barriers:
1361   br i1 %cond, label %atomic_ver, label %simple_ver
1362 simple_ver:
1363   %oldval = load i32* %var
1364   %newval = add nsw i32 %oldval, -1
1365   store i32 %newval, i32* %var
1366   br label %somewhere
1367 atomic_ver:
1368   fence seq_cst
1369   %val = atomicrmw add i32* %var, i32 -1 monotonic
1370   fence seq_cst
1371   br label %somewhere
1372 ; CHECK: dmb
1373 ; CHECK: ldrex
1374 ; CHECK: dmb
1375   ; The key point here is that the second dmb isn't immediately followed by the
1376   ; simple_ver basic block, which LLVM attempted to do when DMB had been marked
1377   ; with isBarrier. For now, look for something that looks like "somewhere".
1378 ; CHECK-NEXT: {{mov|bx}}
1379 somewhere:
1380   %combined = phi i32 [ %val, %atomic_ver ], [ %newval, %simple_ver]
1381   ret i32 %combined
1382 }