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