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
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
16 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
17 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
30 ; CHECK: mov r0, r[[OLD]]
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
39 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
40 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
53 ; CHECK: mov r0, r[[OLD]]
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
62 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
63 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
76 ; CHECK: mov r0, r[[OLD]]
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
85 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
86 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
102 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
103 store i64 %old, i64* @var64
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
112 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
113 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
126 ; CHECK: mov r0, r[[OLD]]
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
135 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
136 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
149 ; CHECK: mov r0, r[[OLD]]
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
158 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
159 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
172 ; CHECK: mov r0, r[[OLD]]
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
181 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
182 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
198 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
199 store i64 %old, i64* @var64
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
208 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
209 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
222 ; CHECK: mov r0, r[[OLD]]
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
231 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
232 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
245 ; CHECK: mov r0, r[[OLD]]
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
254 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
255 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
268 ; CHECK: mov r0, r[[OLD]]
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
277 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
278 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
294 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
295 store i64 %old, i64* @var64
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
304 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
305 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
318 ; CHECK: mov r0, r[[OLD]]
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
327 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
328 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
341 ; CHECK: mov r0, r[[OLD]]
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
350 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
351 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
364 ; CHECK: mov r0, r[[OLD]]
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
373 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
374 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
390 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
391 store i64 %old, i64* @var64
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
400 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
401 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
414 ; CHECK: mov r0, r[[OLD]]
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
423 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
424 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
437 ; CHECK: mov r0, r[[OLD]]
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
446 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
447 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
460 ; CHECK: mov r0, r[[OLD]]
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
469 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
470 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
486 ; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]]
487 store i64 %old, i64* @var64
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
496 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
497 ; CHECK: movt r[[ADDR]], :upper16:var8
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
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
509 ; CHECK: mov r0, r[[OLD]]
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
518 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
519 ; CHECK: movt r[[ADDR]], :upper16:var16
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
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
531 ; CHECK: mov r0, r[[OLD]]
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
540 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
541 ; CHECK: movt r[[ADDR]], :upper16:var32
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
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
553 ; CHECK: mov r0, r[[OLD]]
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
562 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
563 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
575 ; CHECK: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
576 store i64 %old, i64* @var64
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
585 ; CHECK-DAG: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
586 ; CHECK-DAG: movt [[ADDR]], :upper16:var8
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
593 ; CHECK-NEXT: cmp r[[OLDX]], r0
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
602 ; CHECK: mov r0, r[[OLD]]
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
611 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
612 ; CHECK: movt [[ADDR]], :upper16:var16
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
619 ; CHECK-NEXT: cmp r[[OLDX]], r0
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
628 ; CHECK: mov r0, r[[OLD]]
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
637 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
638 ; CHECK: movt r[[ADDR]], :upper16:var32
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
644 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
645 ; CHECK-NEXT: cmp r[[OLD]], r0
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
654 ; CHECK: mov r0, r[[OLD]]
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
663 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
664 ; CHECK: movt r[[ADDR]], :upper16:var64
666 ; CHECK: .LBB{{[0-9]+}}_1:
667 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
668 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
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
693 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
694 store i64 %old, i64* @var64
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
703 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
704 ; CHECK: movt [[ADDR]], :upper16:var8
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
711 ; CHECK-NEXT: cmp r[[OLDX]], r0
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
720 ; CHECK: mov r0, r[[OLD]]
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
729 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
730 ; CHECK: movt r[[ADDR]], :upper16:var16
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
737 ; CHECK-NEXT: cmp r[[OLDX]], r0
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
746 ; CHECK: mov r0, r[[OLD]]
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
755 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
756 ; CHECK: movt r[[ADDR]], :upper16:var32
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
762 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
763 ; CHECK-NEXT: cmp r[[OLD]], r0
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
772 ; CHECK: mov r0, r[[OLD]]
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
781 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
782 ; CHECK: movt r[[ADDR]], :upper16:var64
784 ; CHECK: .LBB{{[0-9]+}}_1:
785 ; CHECK: ldrexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
786 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
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
811 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
812 store i64 %old, i64* @var64
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
821 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
822 ; CHECK: movt [[ADDR]], :upper16:var8
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
828 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
829 ; CHECK-NEXT: cmp r[[OLD]], r0
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
838 ; CHECK: mov r0, r[[OLD]]
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
847 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
848 ; CHECK: movt [[ADDR]], :upper16:var16
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
854 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
855 ; CHECK-NEXT: cmp r[[OLD]], r0
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
864 ; CHECK: mov r0, r[[OLD]]
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
873 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
874 ; CHECK: movt r[[ADDR]], :upper16:var32
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
880 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
881 ; CHECK-NEXT: cmp r[[OLD]], r0
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
890 ; CHECK: mov r0, r[[OLD]]
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
899 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
900 ; CHECK: movt r[[ADDR]], :upper16:var64
902 ; CHECK: .LBB{{[0-9]+}}_1:
903 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
904 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
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
929 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
930 store i64 %old, i64* @var64
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
939 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8
940 ; CHECK: movt [[ADDR]], :upper16:var8
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
946 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
947 ; CHECK-NEXT: cmp r[[OLD]], r0
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
956 ; CHECK: mov r0, r[[OLD]]
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
965 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16
966 ; CHECK: movt [[ADDR]], :upper16:var16
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
972 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
973 ; CHECK-NEXT: cmp r[[OLD]], r0
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
982 ; CHECK: mov r0, r[[OLD]]
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
991 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
992 ; CHECK: movt r[[ADDR]], :upper16:var32
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
998 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
999 ; CHECK-NEXT: cmp r[[OLD]], r0
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
1008 ; CHECK: mov r0, r[[OLD]]
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
1017 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1018 ; CHECK: movt r[[ADDR]], :upper16:var64
1020 ; CHECK: .LBB{{[0-9]+}}_1:
1021 ; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+]], [r[[ADDR]]]
1022 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
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
1047 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
1048 store i64 %old, i64* @var64
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
1058 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1059 ; CHECK: movt r[[ADDR]], :upper16:var8
1061 ; CHECK: .LBB{{[0-9]+}}_1:
1062 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
1063 ; r0 below is a reasonable guess but could change: it certainly comes into the
1065 ; CHECK-NEXT: cmp r[[OLD]], r0
1066 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1068 ; As above, r1 is a reasonable guess.
1069 ; CHECK: strexb [[STATUS:r[0-9]+]], r1, {{.*}}[[ADDR]]
1070 ; CHECK-NEXT: cmp [[STATUS]], #0
1071 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1075 ; CHECK: mov r0, r[[OLD]]
1079 define i16 @test_atomic_cmpxchg_i16(i16 zeroext %wanted, i16 zeroext %new) nounwind {
1080 ; CHECK-LABEL: test_atomic_cmpxchg_i16:
1081 %pair = cmpxchg i16* @var16, i16 %wanted, i16 %new seq_cst seq_cst
1082 %old = extractvalue { i16, i1 } %pair, 0
1085 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1086 ; CHECK: movt r[[ADDR]], :upper16:var16
1088 ; CHECK: .LBB{{[0-9]+}}_1:
1089 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
1090 ; r0 below is a reasonable guess but could change: it certainly comes into the
1092 ; CHECK-NEXT: cmp r[[OLD]], r0
1093 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1095 ; As above, r1 is a reasonable guess.
1096 ; CHECK: stlexh [[STATUS:r[0-9]+]], r1, [r[[ADDR]]]
1097 ; CHECK-NEXT: cmp [[STATUS]], #0
1098 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1102 ; CHECK: mov r0, r[[OLD]]
1106 define void @test_atomic_cmpxchg_i32(i32 %wanted, i32 %new) nounwind {
1107 ; CHECK-LABEL: test_atomic_cmpxchg_i32:
1108 %pair = cmpxchg i32* @var32, i32 %wanted, i32 %new release monotonic
1109 %old = extractvalue { i32, i1 } %pair, 0
1110 store i32 %old, i32* @var32
1113 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
1114 ; CHECK: movt r[[ADDR]], :upper16:var32
1116 ; CHECK: .LBB{{[0-9]+}}_1:
1117 ; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]]
1118 ; r0 below is a reasonable guess but could change: it certainly comes into the
1120 ; CHECK-NEXT: cmp r[[OLD]], r0
1121 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1123 ; As above, r1 is a reasonable guess.
1124 ; CHECK: stlex [[STATUS:r[0-9]+]], r1, [r[[ADDR]]]
1125 ; CHECK-NEXT: cmp [[STATUS]], #0
1126 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1130 ; CHECK: str{{(.w)?}} r[[OLD]],
1134 define void @test_atomic_cmpxchg_i64(i64 %wanted, i64 %new) nounwind {
1135 ; CHECK-LABEL: test_atomic_cmpxchg_i64:
1136 %pair = cmpxchg i64* @var64, i64 %wanted, i64 %new monotonic monotonic
1137 %old = extractvalue { i64, i1 } %pair, 0
1140 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1141 ; CHECK: movt r[[ADDR]], :upper16:var64
1143 ; CHECK: .LBB{{[0-9]+}}_1:
1144 ; CHECK: ldrexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]]
1145 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
1147 ; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0
1148 ; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1
1149 ; CHECK-LE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_LO]], [[MISMATCH_HI]]
1150 ; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1
1151 ; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0
1152 ; CHECK-BE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_HI]], [[MISMATCH_LO]]
1153 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
1155 ; As above, r2, r3 is a reasonable guess.
1156 ; CHECK: strexd [[STATUS:r[0-9]+]], r2, r3, [r[[ADDR]]]
1157 ; CHECK-NEXT: cmp [[STATUS]], #0
1158 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1162 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
1163 store i64 %old, i64* @var64
1167 define i8 @test_atomic_load_monotonic_i8() nounwind {
1168 ; CHECK-LABEL: test_atomic_load_monotonic_i8:
1169 %val = load atomic i8* @var8 monotonic, align 1
1172 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1173 ; CHECK: movt r[[ADDR]], :upper16:var8
1174 ; CHECK: ldrb r0, [r[[ADDR]]]
1181 define i8 @test_atomic_load_monotonic_regoff_i8(i64 %base, i64 %off) nounwind {
1182 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i8:
1183 %addr_int = add i64 %base, %off
1184 %addr = inttoptr i64 %addr_int to i8*
1186 %val = load atomic i8* %addr monotonic, align 1
1189 ; CHECK-LE: ldrb r0, [r0, r2]
1190 ; CHECK-BE: ldrb r0, [r1, r3]
1197 define i8 @test_atomic_load_acquire_i8() nounwind {
1198 ; CHECK-LABEL: test_atomic_load_acquire_i8:
1199 %val = load atomic i8* @var8 acquire, align 1
1202 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1205 ; CHECK: movt r[[ADDR]], :upper16:var8
1208 ; CHECK: ldab r0, [r[[ADDR]]]
1214 define i8 @test_atomic_load_seq_cst_i8() nounwind {
1215 ; CHECK-LABEL: test_atomic_load_seq_cst_i8:
1216 %val = load atomic i8* @var8 seq_cst, align 1
1219 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1222 ; CHECK: movt r[[ADDR]], :upper16:var8
1225 ; CHECK: ldab r0, [r[[ADDR]]]
1231 define i16 @test_atomic_load_monotonic_i16() nounwind {
1232 ; CHECK-LABEL: test_atomic_load_monotonic_i16:
1233 %val = load atomic i16* @var16 monotonic, align 2
1236 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1239 ; CHECK: movt r[[ADDR]], :upper16:var16
1242 ; CHECK: ldrh r0, [r[[ADDR]]]
1249 define i32 @test_atomic_load_monotonic_regoff_i32(i64 %base, i64 %off) nounwind {
1250 ; CHECK-LABEL: test_atomic_load_monotonic_regoff_i32:
1251 %addr_int = add i64 %base, %off
1252 %addr = inttoptr i64 %addr_int to i32*
1254 %val = load atomic i32* %addr monotonic, align 4
1257 ; CHECK-LE: ldr r0, [r0, r2]
1258 ; CHECK-BE: ldr r0, [r1, r3]
1265 define i64 @test_atomic_load_seq_cst_i64() nounwind {
1266 ; CHECK-LABEL: test_atomic_load_seq_cst_i64:
1267 %val = load atomic i64* @var64 seq_cst, align 8
1270 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1273 ; CHECK: movt r[[ADDR]], :upper16:var64
1276 ; CHECK: ldaexd r0, r1, [r[[ADDR]]]
1282 define void @test_atomic_store_monotonic_i8(i8 %val) nounwind {
1283 ; CHECK-LABEL: test_atomic_store_monotonic_i8:
1284 store atomic i8 %val, i8* @var8 monotonic, align 1
1285 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1286 ; CHECK: movt r[[ADDR]], :upper16:var8
1287 ; CHECK: strb r0, [r[[ADDR]]]
1292 define void @test_atomic_store_monotonic_regoff_i8(i64 %base, i64 %off, i8 %val) nounwind {
1293 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i8:
1295 %addr_int = add i64 %base, %off
1296 %addr = inttoptr i64 %addr_int to i8*
1298 store atomic i8 %val, i8* %addr monotonic, align 1
1299 ; CHECK-LE: ldrb{{(\.w)?}} [[VAL:r[0-9]+]], [sp]
1300 ; CHECK-LE: strb [[VAL]], [r0, r2]
1301 ; CHECK-BE: ldrb{{(\.w)?}} [[VAL:r[0-9]+]], [sp, #3]
1302 ; CHECK-BE: strb [[VAL]], [r1, r3]
1307 define void @test_atomic_store_release_i8(i8 %val) nounwind {
1308 ; CHECK-LABEL: test_atomic_store_release_i8:
1309 store atomic i8 %val, i8* @var8 release, align 1
1312 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1315 ; CHECK: movt r[[ADDR]], :upper16:var8
1318 ; CHECK: stlb r0, [r[[ADDR]]]
1324 define void @test_atomic_store_seq_cst_i8(i8 %val) nounwind {
1325 ; CHECK-LABEL: test_atomic_store_seq_cst_i8:
1326 store atomic i8 %val, i8* @var8 seq_cst, align 1
1329 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1332 ; CHECK: movt r[[ADDR]], :upper16:var8
1335 ; CHECK: stlb r0, [r[[ADDR]]]
1341 define void @test_atomic_store_monotonic_i16(i16 %val) nounwind {
1342 ; CHECK-LABEL: test_atomic_store_monotonic_i16:
1343 store atomic i16 %val, i16* @var16 monotonic, align 2
1346 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1349 ; CHECK: movt r[[ADDR]], :upper16:var16
1352 ; CHECK: strh r0, [r[[ADDR]]]
1358 define void @test_atomic_store_monotonic_regoff_i32(i64 %base, i64 %off, i32 %val) nounwind {
1359 ; CHECK-LABEL: test_atomic_store_monotonic_regoff_i32:
1361 %addr_int = add i64 %base, %off
1362 %addr = inttoptr i64 %addr_int to i32*
1364 store atomic i32 %val, i32* %addr monotonic, align 4
1367 ; CHECK: ldr [[VAL:r[0-9]+]], [sp]
1370 ; CHECK-LE: str [[VAL]], [r0, r2]
1371 ; CHECK-BE: str [[VAL]], [r1, r3]
1378 define void @test_atomic_store_release_i64(i64 %val) nounwind {
1379 ; CHECK-LABEL: test_atomic_store_release_i64:
1380 store atomic i64 %val, i64* @var64 release, align 8
1383 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var64
1384 ; CHECK: movt [[ADDR]], :upper16:var64
1386 ; CHECK: .LBB{{[0-9]+}}_1:
1387 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
1389 ; CHECK: stlexd [[STATUS:r[0-9]+]], r0, r1, {{.*}}[[ADDR]]
1390 ; CHECK-NEXT: cmp [[STATUS]], #0
1391 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1398 define i32 @not.barriers(i32* %var, i1 %cond) {
1399 ; CHECK-LABEL: not.barriers:
1400 br i1 %cond, label %atomic_ver, label %simple_ver
1402 %oldval = load i32* %var
1403 %newval = add nsw i32 %oldval, -1
1404 store i32 %newval, i32* %var
1408 %val = atomicrmw add i32* %var, i32 -1 monotonic
1414 ; The key point here is that the second dmb isn't immediately followed by the
1415 ; simple_ver basic block, which LLVM attempted to do when DMB had been marked
1416 ; with isBarrier. For now, look for something that looks like "somewhere".
1417 ; CHECK-NEXT: {{mov|bx}}
1419 %combined = phi i32 [ %val, %atomic_ver ], [ %newval, %simple_ver]