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