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]+|lr]], [[OLD2:r[0-9]+|lr]], [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]+|lr]], [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]+|lr]], [[OLD2:r[0-9]+|lr]], [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]+|lr]], [[OLD2:r[0-9]+|lr]], [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-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
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
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
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:
1077 ; CHECK-NEXT: .LBB{{[0-9]+}}_4:
1081 ; CHECK-ARM: mov r0, r[[OLD]]
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
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
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
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
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:
1110 ; CHECK-NEXT: .LBB{{[0-9]+}}_4:
1114 ; CHECK-ARM: mov r0, r[[OLD]]
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
1125 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32
1126 ; CHECK: movt r[[ADDR]], :upper16:var32
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
1132 ; CHECK-NEXT: cmp r[[OLD]], r0
1133 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
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:
1142 ; CHECK-NEXT: .LBB{{[0-9]+}}_4:
1146 ; CHECK: str{{(.w)?}} r[[OLD]],
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
1156 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1157 ; CHECK: movt r[[ADDR]], :upper16:var64
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
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
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:
1180 ; CHECK-NEXT: .LBB{{[0-9]+}}_4:
1184 ; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]]
1185 store i64 %old, i64* @var64
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
1194 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1195 ; CHECK: movt r[[ADDR]], :upper16:var8
1196 ; CHECK: ldrb r0, [r[[ADDR]]]
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*
1208 %val = load atomic i8, i8* %addr monotonic, align 1
1211 ; CHECK-LE: ldrb r0, [r0, r2]
1212 ; CHECK-BE: ldrb r0, [r1, r3]
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
1224 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1227 ; CHECK: movt r[[ADDR]], :upper16:var8
1230 ; CHECK: ldab r0, [r[[ADDR]]]
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
1241 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1244 ; CHECK: movt r[[ADDR]], :upper16:var8
1247 ; CHECK: ldab r0, [r[[ADDR]]]
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
1258 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1261 ; CHECK: movt r[[ADDR]], :upper16:var16
1264 ; CHECK: ldrh r0, [r[[ADDR]]]
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*
1276 %val = load atomic i32, i32* %addr monotonic, align 4
1279 ; CHECK-LE: ldr r0, [r0, r2]
1280 ; CHECK-BE: ldr r0, [r1, r3]
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
1292 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64
1295 ; CHECK: movt r[[ADDR]], :upper16:var64
1298 ; CHECK: ldaexd r0, r1, [r[[ADDR]]]
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]]]
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:
1317 %addr_int = add i64 %base, %off
1318 %addr = inttoptr i64 %addr_int to i8*
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]
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
1334 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1337 ; CHECK: movt r[[ADDR]], :upper16:var8
1340 ; CHECK: stlb r0, [r[[ADDR]]]
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
1351 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8
1354 ; CHECK: movt r[[ADDR]], :upper16:var8
1357 ; CHECK: stlb r0, [r[[ADDR]]]
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
1368 ; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16
1371 ; CHECK: movt r[[ADDR]], :upper16:var16
1374 ; CHECK: strh r0, [r[[ADDR]]]
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:
1383 %addr_int = add i64 %base, %off
1384 %addr = inttoptr i64 %addr_int to i32*
1386 store atomic i32 %val, i32* %addr monotonic, align 4
1389 ; CHECK: ldr [[VAL:r[0-9]+]], [sp]
1392 ; CHECK-LE: str [[VAL]], [r0, r2]
1393 ; CHECK-BE: str [[VAL]], [r1, r3]
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
1405 ; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var64
1406 ; CHECK: movt [[ADDR]], :upper16:var64
1408 ; CHECK: .LBB{{[0-9]+}}_1:
1409 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the
1411 ; CHECK: stlexd [[STATUS:r[0-9]+]], r0, r1, {{.*}}[[ADDR]]
1412 ; CHECK-NEXT: cmp [[STATUS]], #0
1413 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_1
1420 define i32 @not.barriers(i32* %var, i1 %cond) {
1421 ; CHECK-LABEL: not.barriers:
1422 br i1 %cond, label %atomic_ver, label %simple_ver
1424 %oldval = load i32, i32* %var
1425 %newval = add nsw i32 %oldval, -1
1426 store i32 %newval, i32* %var
1430 %val = atomicrmw add i32* %var, i32 -1 monotonic
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}}
1441 %combined = phi i32 [ %val, %atomic_ver ], [ %newval, %simple_ver]