xref: /llvm-project/llvm/test/CodeGen/ARM/atomic-op.ll (revision bed1c7f061aa12417aa081e334afdba45767b938)
1; RUN: llc < %s -mtriple=armv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix CHECK-ARMV7
2; RUN: llc < %s -mtriple=thumbv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-T2
3; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-T1
4; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs -mcpu=cortex-m0 | FileCheck %s --check-prefix=CHECK-T1-M0
5; RUN: llc < %s -mtriple=thumbv7--none-eabi -thread-model single -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-BAREMETAL
6
7target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
8
9; CHECK-LABEL: _func:
10define void @func(i32 %argc, ptr %argv) nounwind {
11entry:
12	%argc.addr = alloca i32		; <ptr> [#uses=1]
13	%argv.addr = alloca ptr		; <ptr> [#uses=1]
14	%val1 = alloca i32		; <ptr> [#uses=2]
15	%val2 = alloca i32		; <ptr> [#uses=15]
16	%andt = alloca i32		; <ptr> [#uses=2]
17	%ort = alloca i32		; <ptr> [#uses=2]
18	%xort = alloca i32		; <ptr> [#uses=2]
19	%old = alloca i32		; <ptr> [#uses=18]
20	%temp = alloca i32		; <ptr> [#uses=2]
21	store i32 %argc, ptr %argc.addr
22	store ptr %argv, ptr %argv.addr
23	store i32 0, ptr %val1
24	store i32 31, ptr %val2
25	store i32 3855, ptr %andt
26	store i32 3855, ptr %ort
27	store i32 3855, ptr %xort
28	store i32 4, ptr %temp
29	%tmp = load i32, ptr %temp
30	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
31  ; CHECK: ldrex
32  ; CHECK: add
33  ; CHECK: strex
34  ; CHECK-T1: bl ___sync_fetch_and_add_4
35  ; CHECK-T1-M0: bl ___atomic_fetch_add_4
36  ; CHECK-BAREMETAL: add
37  ; CHECK-BAREMETAL-NOT: __sync
38  %0 = atomicrmw add ptr %val1, i32 %tmp monotonic
39	store i32 %0, ptr %old
40	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
41  ; CHECK: ldrex
42  ; CHECK: sub
43  ; CHECK: strex
44  ; CHECK-T1: bl ___sync_fetch_and_sub_4
45  ; CHECK-T1-M0: bl ___atomic_fetch_sub_4
46  ; CHECK-BAREMETAL: sub
47  ; CHECK-BAREMETAL-NOT: __sync
48  %1 = atomicrmw sub ptr %val2, i32 30 monotonic
49	store i32 %1, ptr %old
50	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
51  ; CHECK: ldrex
52  ; CHECK: add
53  ; CHECK: strex
54  ; CHECK-T1: bl ___sync_fetch_and_add_4
55  ; CHECK-T1-M0: bl ___atomic_fetch_add_4
56  ; CHECK-BAREMETAL: add
57  ; CHECK-BAREMETAL-NOT: __sync
58  %2 = atomicrmw add ptr %val2, i32 1 monotonic
59	store i32 %2, ptr %old
60	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
61  ; CHECK: ldrex
62  ; CHECK: sub
63  ; CHECK: strex
64  ; CHECK-T1: bl ___sync_fetch_and_sub_4
65  ; CHECK-T1-M0: bl ___atomic_fetch_sub_4
66  ; CHECK-BAREMETAL: sub
67  ; CHECK-BAREMETAL-NOT: __sync
68  %3 = atomicrmw sub ptr %val2, i32 1 monotonic
69	store i32 %3, ptr %old
70	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
71  ; CHECK: ldrex
72  ; CHECK: and
73  ; CHECK: strex
74  ; CHECK-T1: bl ___sync_fetch_and_and_4
75  ; CHECK-T1-M0: bl ___atomic_fetch_and_4
76  ; CHECK-BAREMETAL: and
77  ; CHECK-BAREMETAL-NOT: __sync
78  %4 = atomicrmw and ptr %andt, i32 4080 monotonic
79	store i32 %4, ptr %old
80	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
81  ; CHECK: ldrex
82  ; CHECK: or
83  ; CHECK: strex
84  ; CHECK-T1: bl ___sync_fetch_and_or_4
85  ; CHECK-T1-M0: bl ___atomic_fetch_or_4
86  ; CHECK-BAREMETAL: or
87  ; CHECK-BAREMETAL-NOT: __sync
88  %5 = atomicrmw or ptr %ort, i32 4080 monotonic
89	store i32 %5, ptr %old
90	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
91  ; CHECK: ldrex
92  ; CHECK: eor
93  ; CHECK: strex
94  ; CHECK-T1: bl ___sync_fetch_and_xor_4
95  ; CHECK-T1-M0: bl ___atomic_fetch_xor_4
96  ; CHECK-BAREMETAL: eor
97  ; CHECK-BAREMETAL-NOT: __sync
98  %6 = atomicrmw xor ptr %xort, i32 4080 monotonic
99	store i32 %6, ptr %old
100	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
101  ; CHECK: ldrex
102  ; CHECK: cmp
103  ; CHECK: strex
104  ; CHECK-T1: bl ___sync_fetch_and_min_4
105  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
106  ; CHECK-BAREMETAL: cmp
107  ; CHECK-BAREMETAL-NOT: __sync
108  %7 = atomicrmw min ptr %val2, i32 16 monotonic
109	store i32 %7, ptr %old
110	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
111	%neg = sub i32 0, 1
112  ; CHECK: ldrex
113  ; CHECK: cmp
114  ; CHECK: strex
115  ; CHECK-T1: bl ___sync_fetch_and_min_4
116  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
117  ; CHECK-BAREMETAL: cmp
118  ; CHECK-BAREMETAL-NOT: __sync
119  %8 = atomicrmw min ptr %val2, i32 %neg monotonic
120	store i32 %8, ptr %old
121	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
122  ; CHECK: ldrex
123  ; CHECK: cmp
124  ; CHECK: strex
125  ; CHECK-T1: bl ___sync_fetch_and_max_4
126  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
127  ; CHECK-BAREMETAL: cmp
128  ; CHECK-BAREMETAL-NOT: __sync
129  %9 = atomicrmw max ptr %val2, i32 1 monotonic
130	store i32 %9, ptr %old
131	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
132  ; CHECK: ldrex
133  ; CHECK: bic
134  ; CHECK-NOT: cmp
135  ; CHECK: strex
136  ; CHECK-T1: bl ___sync_fetch_and_max_4
137  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
138  ; CHECK-BAREMETAL: bic
139  ; CHECK-BAREMETAL-NOT: __sync
140  %10 = atomicrmw max ptr %val2, i32 0 monotonic
141	store i32 %10, ptr %old
142	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
143  ; CHECK: ldrex
144  ; CHECK: cmp
145  ; CHECK: strex
146  ; CHECK-T1: bl ___sync_fetch_and_umin_4
147  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
148  ; CHECK-BAREMETAL: cmp
149  ; CHECK-BAREMETAL-NOT: __sync
150  %11 = atomicrmw umin ptr %val2, i32 16 monotonic
151	store i32 %11, ptr %old
152	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
153	%uneg = sub i32 0, 1
154  ; CHECK: ldrex
155  ; CHECK: cmp
156  ; CHECK: strex
157  ; CHECK-T1: bl ___sync_fetch_and_umin_4
158  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
159  ; CHECK-BAREMETAL: cmp
160  ; CHECK-BAREMETAL-NOT: __sync
161  %12 = atomicrmw umin ptr %val2, i32 %uneg monotonic
162	store i32 %12, ptr %old
163	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
164  ; CHECK: ldrex
165  ; CHECK: strex
166  ; CHECK: cmp
167  ; CHECK-T1: bl ___sync_fetch_and_umax_4
168  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
169  ; CHECK-BAREMETAL: cmp
170  ; CHECK-BAREMETAL-NOT: __sync
171  %13 = atomicrmw umax ptr %val2, i32 1 monotonic
172	store i32 %13, ptr %old
173	call void asm sideeffect "", "~{memory},~{dirflag},~{fpsr},~{flags}"()
174  ; CHECK: ldrex
175  ; CHECK: strex
176  ; CHECK: cmp
177  ; CHECK-T1: bl ___sync_fetch_and_umax_4
178  ; CHECK-T1-M0: bl ___atomic_compare_exchange_4
179  ; CHECK-BAREMETAL: cmp
180  ; CHECK-BAREMETAL-NOT: __sync
181  %14 = atomicrmw umax ptr %val2, i32 0 monotonic
182	store i32 %14, ptr %old
183
184  ret void
185}
186
187; CHECK-LABEL: _func2:
188define void @func2() nounwind {
189entry:
190  %val = alloca i16
191  %old = alloca i16
192  store i16 31, ptr %val
193  ; CHECK: ldrex
194  ; CHECK: strex
195  ; CHECK: cmp
196  ; CHECK-T1: bl ___sync_fetch_and_umin_2
197  ; CHECK-T1-M0: bl ___atomic_compare_exchange_2
198  ; CHECK-BAREMETAL: cmp
199  ; CHECK-BAREMETAL-NOT: __sync
200  %0 = atomicrmw umin ptr %val, i16 16 monotonic
201  store i16 %0, ptr %old
202  %uneg = sub i16 0, 1
203  ; CHECK: ldrex
204  ; CHECK: strex
205  ; CHECK: cmp
206  ; CHECK-T1: bl ___sync_fetch_and_umin_2
207  ; CHECK-T1-M0: bl ___atomic_compare_exchange_2
208  ; CHECK-BAREMETAL: cmp
209  ; CHECK-BAREMETAL-NOT: __sync
210  %1 = atomicrmw umin ptr %val, i16 %uneg monotonic
211  store i16 %1, ptr %old
212  ; CHECK: ldrex
213  ; CHECK: cmp
214  ; CHECK: strex
215  ; CHECK-T1: bl ___sync_fetch_and_umax_2
216  ; CHECK-T1-M0: bl ___atomic_compare_exchange_2
217  ; CHECK-BAREMETAL: cmp
218  ; CHECK-BAREMETAL-NOT: __sync
219  %2 = atomicrmw umax ptr %val, i16 1 monotonic
220  store i16 %2, ptr %old
221  ; CHECK: ldrex
222  ; CHECK: strex
223  ; CHECK: cmp
224  ; CHECK-T1: bl ___sync_fetch_and_umax_2
225  ; CHECK-T1-M0: bl ___atomic_compare_exchange_2
226  ; CHECK-BAREMETAL: cmp
227  ; CHECK-BAREMETAL-NOT: __sync
228  %3 = atomicrmw umax ptr %val, i16 0 monotonic
229  store i16 %3, ptr %old
230  ret void
231}
232
233; CHECK-LABEL: _func3:
234define void @func3() nounwind {
235entry:
236  %val = alloca i8
237  %old = alloca i8
238  store i8 31, ptr %val
239  ; CHECK: ldrex
240  ; CHECK: strex
241  ; CHECK: cmp
242  ; CHECK-T1: bl ___sync_fetch_and_umin_1
243  ; CHECK-T1-M0: bl ___atomic_compare_exchange_1
244  ; CHECK-BAREMETAL: cmp
245  ; CHECK-BAREMETAL-NOT: __sync
246  %0 = atomicrmw umin ptr %val, i8 16 monotonic
247  store i8 %0, ptr %old
248  ; CHECK: ldrex
249  ; CHECK: strex
250  ; CHECK: cmp
251  ; CHECK-T1: bl ___sync_fetch_and_umin_1
252  ; CHECK-T1-M0: bl ___atomic_compare_exchange_1
253  ; CHECK-BAREMETAL: cmp
254  ; CHECK-BAREMETAL-NOT: __sync
255  %uneg = sub i8 0, 1
256  %1 = atomicrmw umin ptr %val, i8 %uneg monotonic
257  store i8 %1, ptr %old
258  ; CHECK: ldrex
259  ; CHECK: strex
260  ; CHECK: cmp
261  ; CHECK-T1: bl ___sync_fetch_and_umax_1
262  ; CHECK-T1-M0: bl ___atomic_compare_exchange_1
263  ; CHECK-BAREMETAL: cmp
264  ; CHECK-BAREMETAL-NOT: __sync
265  %2 = atomicrmw umax ptr %val, i8 1 monotonic
266  store i8 %2, ptr %old
267  ; CHECK: ldrex
268  ; CHECK: strex
269  ; CHECK: cmp
270  ; CHECK-T1: bl ___sync_fetch_and_umax_1
271  ; CHECK-T1-M0: bl ___atomic_compare_exchange_1
272  ; CHECK-BAREMETAL: cmp
273  ; CHECK-BAREMETAL-NOT: __sync
274  %3 = atomicrmw umax ptr %val, i8 0 monotonic
275  store i8 %3, ptr %old
276  ret void
277}
278
279; CHECK-LABEL: _func4:
280; This function should not need to use callee-saved registers.
281; rdar://problem/12203728
282; CHECK-NOT: r4
283define i32 @func4(ptr %p) nounwind optsize ssp {
284entry:
285  %0 = atomicrmw add ptr %p, i32 1 monotonic
286  ret i32 %0
287}
288
289define i32 @test_cmpxchg_fail_order(ptr %addr, i32 %desired, i32 %new) {
290; CHECK-LABEL: test_cmpxchg_fail_order:
291
292  %pair = cmpxchg ptr %addr, i32 %desired, i32 %new seq_cst monotonic
293  %oldval = extractvalue { i32, i1 } %pair, 0
294; CHECK-ARMV7:     mov     r[[ADDR:[0-9]+]], r0
295; CHECK-ARMV7:     ldrex   [[OLDVAL:r[0-9]+]], [r0]
296; CHECK-ARMV7:     cmp     [[OLDVAL]], r1
297; CHECK-ARMV7:     bne     [[FAIL_BB:\.?LBB[0-9]+_[0-9]+]]
298; CHECK-ARMV7:     dmb ish
299; CHECK-ARMV7: [[LOOP_BB:\.?LBB.*]]:
300; CHECK-ARMV7:     strex   [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]]
301; CHECK-ARMV7:     cmp     [[SUCCESS]], #0
302; CHECK-ARMV7:     beq     [[SUCCESS_BB:\.?LBB.*]]
303; CHECK-ARMV7:     ldrex   [[OLDVAL]], [r[[ADDR]]]
304; CHECK-ARMV7:     cmp     [[OLDVAL]], r1
305; CHECK-ARMV7:     beq     [[LOOP_BB]]
306; CHECK-ARMV7: [[FAIL_BB]]:
307; CHECK-ARMV7:     clrex
308; CHECK-ARMV7:     bx      lr
309; CHECK-ARMV7: [[SUCCESS_BB]]:
310; CHECK-ARMV7:     dmb     ish
311; CHECK-ARMV7:     bx      lr
312
313; CHECK-T2:     mov     r[[ADDR:[0-9]+]], r0
314; CHECK-T2:     ldrex   [[OLDVAL:r[0-9]+]], [r0]
315; CHECK-T2:     cmp     [[OLDVAL]], r1
316; CHECK-T2:     bne     [[FAIL_BB:\.?LBB.*]]
317; CHECK-T2:     dmb ish
318; CHECK-T2: [[LOOP_BB:\.?LBB.*]]:
319; CHECK-T2:     strex   [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]]
320; CHECK-T2:     cmp     [[SUCCESS]], #0
321; CHECK-T2:     dmbeq   ish
322; CHECK-T2:     bxeq    lr
323; CHECK-T2:     ldrex   [[OLDVAL]], [r[[ADDR]]]
324; CHECK-T2:     cmp     [[OLDVAL]], r1
325; CHECK-T2:     beq     [[LOOP_BB]]
326; CHECK-T2:     clrex
327
328  ret i32 %oldval
329}
330
331define i32 @test_cmpxchg_fail_order1(ptr %addr, i32 %desired, i32 %new) {
332; CHECK-LABEL: test_cmpxchg_fail_order1:
333
334  %pair = cmpxchg ptr %addr, i32 %desired, i32 %new acquire acquire
335  %oldval = extractvalue { i32, i1 } %pair, 0
336; CHECK-NOT:     dmb ish
337; CHECK: [[LOOP_BB:\.?LBB[0-9]+_1]]:
338; CHECK:     ldrex   [[OLDVAL:r[0-9]+]], [r[[ADDR:[0-9]+]]]
339; CHECK:     cmp     [[OLDVAL]], r1
340; CHECK:     bne     [[FAIL_BB:\.?LBB[0-9]+_[0-9]+]]
341; CHECK:     strex   [[SUCCESS:r[0-9]+]], r2, [r[[ADDR]]]
342; CHECK:     cmp     [[SUCCESS]], #0
343; CHECK:     bne     [[LOOP_BB]]
344; CHECK:     dmb     ish
345; CHECK:     bx      lr
346; CHECK: [[FAIL_BB]]:
347; CHECK-NEXT: clrex
348; CHECK:     dmb     ish
349; CHECK:     bx      lr
350
351  ret i32 %oldval
352}
353
354define i32 @load_load_add_acquire(ptr %mem1, ptr %mem2) nounwind {
355; CHECK-LABEL: load_load_add_acquire
356  %val1 = load atomic i32, ptr %mem1 acquire, align 4
357  %val2 = load atomic i32, ptr %mem2 acquire, align 4
358  %tmp = add i32 %val1, %val2
359
360; CHECK: ldr {{r[0-9]}}, [r0]
361; CHECK: dmb
362; CHECK: ldr {{r[0-9]}}, [r1]
363; CHECK: dmb
364; CHECK: add r0,
365
366; CHECK-T1-M0: __atomic_load_4
367; CHECK-T1-M0: __atomic_load_4
368
369; CHECK-T1: ___sync_val_compare_and_swap_4
370; CHECK-T1: ___sync_val_compare_and_swap_4
371
372; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r0]
373; CHECK-BAREMETAL-NOT: dmb
374; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r1]
375; CHECK-BAREMETAL-NOT: dmb
376; CHECK-BAREMETAL: add r0,
377
378  ret i32 %tmp
379}
380
381define void @store_store_release(ptr %mem1, i32 %val1, ptr %mem2, i32 %val2) {
382; CHECK-LABEL: store_store_release
383  store atomic i32 %val1, ptr %mem1 release, align 4
384  store atomic i32 %val2, ptr %mem2 release, align 4
385
386; CHECK: dmb
387; CHECK: str r1, [r0]
388; CHECK: dmb
389; CHECK: str r3, [r2]
390
391; CHECK-T1: ___sync_lock_test_and_set
392; CHECK-T1: ___sync_lock_test_and_set
393
394; CHECK-T1-M0: __atomic_store_4
395; CHECK-T1-M0: __atomic_store_4
396
397; CHECK-BAREMETAL-NOT: dmb
398; CHECK-BAREMETAL: str r1, [r0]
399; CHECK-BAREMETAL-NOT: dmb
400; CHECK-BAREMETAL: str r3, [r2]
401
402  ret void
403}
404
405define void @load_fence_store_monotonic(ptr %mem1, ptr %mem2) {
406; CHECK-LABEL: load_fence_store_monotonic
407  %val = load atomic i32, ptr %mem1 monotonic, align 4
408  fence seq_cst
409  store atomic i32 %val, ptr %mem2 monotonic, align 4
410
411; CHECK: ldr [[R0:r[0-9]]], [r0]
412; CHECK: dmb
413; CHECK: str [[R0]], [r1]
414
415; CHECK-T1-M0: __atomic_load_4
416; CHECK-T1-M0: dmb
417; CHECK-T1-M0: __atomic_store_4
418
419; CHECK-T1: ldr [[R0:r[0-9]]], [{{r[0-9]+}}]
420; CHECK-T1: {{dmb|bl ___sync_synchronize}}
421; CHECK-T1: str [[R0]], [{{r[0-9]+}}]
422
423; CHECK-BAREMETAL: ldr [[R0:r[0-9]]], [r0]
424; CHECK-BAREMETAL-NOT: dmb
425; CHECK-BAREMETAL: str [[R0]], [r1]
426
427  ret void
428}
429