xref: /llvm-project/llvm/test/Transforms/AtomicExpand/ARM/atomic-expansion-v7.ll (revision fe42e72db29e48aa81eac2aa922afd90a7f01517)
1; RUN: opt -S -o - -mtriple=armv7-apple-ios7.0 -passes=atomic-expand -codegen-opt-level=1 %s | FileCheck %s
2
3define i8 @test_atomic_xchg_i8(ptr %ptr, i8 %xchgend) {
4; CHECK-LABEL: @test_atomic_xchg_i8
5; CHECK-NOT: dmb
6; CHECK: br label %[[LOOP:.*]]
7; CHECK: [[LOOP]]:
8; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
9; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
10; CHECK: [[NEWVAL32:%.*]] = zext i8 %xchgend to i32
11; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
12; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
13; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
14; CHECK: [[END]]:
15; CHECK-NOT: dmb
16; CHECK: ret i8 [[OLDVAL]]
17  %res = atomicrmw xchg ptr %ptr, i8 %xchgend monotonic
18  ret i8 %res
19}
20
21define i16 @test_atomic_add_i16(ptr %ptr, i16 %addend) {
22; CHECK-LABEL: @test_atomic_add_i16
23; CHECK: call void @llvm.arm.dmb(i32 11)
24; CHECK: br label %[[LOOP:.*]]
25; CHECK: [[LOOP]]:
26; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i16) %ptr)
27; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
28; CHECK: [[NEWVAL:%.*]] = add i16 [[OLDVAL]], %addend
29; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
30; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i16) %ptr)
31; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
32; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
33; CHECK: [[END]]:
34; CHECK: call void @llvm.arm.dmb(i32 11)
35; CHECK: ret i16 [[OLDVAL]]
36  %res = atomicrmw add ptr %ptr, i16 %addend seq_cst
37  ret i16 %res
38}
39
40define i32 @test_atomic_sub_i32(ptr %ptr, i32 %subend) {
41; CHECK-LABEL: @test_atomic_sub_i32
42; CHECK-NOT: dmb
43; CHECK: br label %[[LOOP:.*]]
44; CHECK: [[LOOP]]:
45; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %ptr)
46; CHECK: [[NEWVAL:%.*]] = sub i32 [[OLDVAL]], %subend
47; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL]], ptr elementtype(i32) %ptr)
48; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
49; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
50; CHECK: [[END]]:
51; CHECK: call void @llvm.arm.dmb(i32 11)
52; CHECK: ret i32 [[OLDVAL]]
53  %res = atomicrmw sub ptr %ptr, i32 %subend acquire
54  ret i32 %res
55}
56
57define i8 @test_atomic_and_i8(ptr %ptr, i8 %andend) {
58; CHECK-LABEL: @test_atomic_and_i8
59; CHECK: call void @llvm.arm.dmb(i32 11)
60; CHECK: br label %[[LOOP:.*]]
61; CHECK: [[LOOP]]:
62; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
63; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
64; CHECK: [[NEWVAL:%.*]] = and i8 [[OLDVAL]], %andend
65; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
66; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
67; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
68; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
69; CHECK: [[END]]:
70; CHECK-NOT: dmb
71; CHECK: ret i8 [[OLDVAL]]
72  %res = atomicrmw and ptr %ptr, i8 %andend release
73  ret i8 %res
74}
75
76define i16 @test_atomic_nand_i16(ptr %ptr, i16 %nandend) {
77; CHECK-LABEL: @test_atomic_nand_i16
78; CHECK: call void @llvm.arm.dmb(i32 11)
79; CHECK: br label %[[LOOP:.*]]
80; CHECK: [[LOOP]]:
81; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i16) %ptr)
82; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
83; CHECK: [[NEWVAL_TMP:%.*]] = and i16 [[OLDVAL]], %nandend
84; CHECK: [[NEWVAL:%.*]] = xor i16 [[NEWVAL_TMP]], -1
85; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
86; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i16) %ptr)
87; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
88; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
89; CHECK: [[END]]:
90; CHECK: call void @llvm.arm.dmb(i32 11)
91; CHECK: ret i16 [[OLDVAL]]
92  %res = atomicrmw nand ptr %ptr, i16 %nandend seq_cst
93  ret i16 %res
94}
95
96define i64 @test_atomic_or_i64(ptr %ptr, i64 %orend) {
97; CHECK-LABEL: @test_atomic_or_i64
98; CHECK: call void @llvm.arm.dmb(i32 11)
99; CHECK: br label %[[LOOP:.*]]
100; CHECK: [[LOOP]]:
101; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(ptr %ptr)
102; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
103; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
104; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
105; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
106; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
107; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
108; CHECK: [[NEWVAL:%.*]] = or i64 [[OLDVAL]], %orend
109; CHECK: [[NEWLO:%.*]] = trunc i64 [[NEWVAL]] to i32
110; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 [[NEWVAL]], 32
111; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
112; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], ptr %ptr)
113; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
114; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
115; CHECK: [[END]]:
116; CHECK: call void @llvm.arm.dmb(i32 11)
117; CHECK: ret i64 [[OLDVAL]]
118  %res = atomicrmw or ptr %ptr, i64 %orend seq_cst
119  ret i64 %res
120}
121
122define i8 @test_atomic_xor_i8(ptr %ptr, i8 %xorend) {
123; CHECK-LABEL: @test_atomic_xor_i8
124; CHECK: call void @llvm.arm.dmb(i32 11)
125; CHECK: br label %[[LOOP:.*]]
126; CHECK: [[LOOP]]:
127; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
128; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
129; CHECK: [[NEWVAL:%.*]] = xor i8 [[OLDVAL]], %xorend
130; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
131; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
132; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
133; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
134; CHECK: [[END]]:
135; CHECK: call void @llvm.arm.dmb(i32 11)
136; CHECK: ret i8 [[OLDVAL]]
137  %res = atomicrmw xor ptr %ptr, i8 %xorend seq_cst
138  ret i8 %res
139}
140
141define i8 @test_atomic_max_i8(ptr %ptr, i8 %maxend) {
142; CHECK-LABEL: @test_atomic_max_i8
143; CHECK: call void @llvm.arm.dmb(i32 11)
144; CHECK: br label %[[LOOP:.*]]
145; CHECK: [[LOOP]]:
146; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
147; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
148; CHECK: [[WANT_OLD:%.*]] = icmp sgt i8 [[OLDVAL]], %maxend
149; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %maxend
150; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
151; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
152; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
153; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
154; CHECK: [[END]]:
155; CHECK: call void @llvm.arm.dmb(i32 11)
156; CHECK: ret i8 [[OLDVAL]]
157  %res = atomicrmw max ptr %ptr, i8 %maxend seq_cst
158  ret i8 %res
159}
160
161define i8 @test_atomic_min_i8(ptr %ptr, i8 %minend) {
162; CHECK-LABEL: @test_atomic_min_i8
163; CHECK: call void @llvm.arm.dmb(i32 11)
164; CHECK: br label %[[LOOP:.*]]
165; CHECK: [[LOOP]]:
166; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
167; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
168; CHECK: [[WANT_OLD:%.*]] = icmp sle i8 [[OLDVAL]], %minend
169; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %minend
170; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
171; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
172; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
173; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
174; CHECK: [[END]]:
175; CHECK: call void @llvm.arm.dmb(i32 11)
176; CHECK: ret i8 [[OLDVAL]]
177  %res = atomicrmw min ptr %ptr, i8 %minend seq_cst
178  ret i8 %res
179}
180
181define i8 @test_atomic_umax_i8(ptr %ptr, i8 %umaxend) {
182; CHECK-LABEL: @test_atomic_umax_i8
183; CHECK: call void @llvm.arm.dmb(i32 11)
184; CHECK: br label %[[LOOP:.*]]
185; CHECK: [[LOOP]]:
186; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
187; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
188; CHECK: [[WANT_OLD:%.*]] = icmp ugt i8 [[OLDVAL]], %umaxend
189; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %umaxend
190; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
191; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
192; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
193; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
194; CHECK: [[END]]:
195; CHECK: call void @llvm.arm.dmb(i32 11)
196; CHECK: ret i8 [[OLDVAL]]
197  %res = atomicrmw umax ptr %ptr, i8 %umaxend seq_cst
198  ret i8 %res
199}
200
201define i8 @test_atomic_umin_i8(ptr %ptr, i8 %uminend) {
202; CHECK-LABEL: @test_atomic_umin_i8
203; CHECK: call void @llvm.arm.dmb(i32 11)
204; CHECK: br label %[[LOOP:.*]]
205; CHECK: [[LOOP]]:
206; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
207; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
208; CHECK: [[WANT_OLD:%.*]] = icmp ule i8 [[OLDVAL]], %uminend
209; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %uminend
210; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
211; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
212; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
213; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
214; CHECK: [[END]]:
215; CHECK: call void @llvm.arm.dmb(i32 11)
216; CHECK: ret i8 [[OLDVAL]]
217  %res = atomicrmw umin ptr %ptr, i8 %uminend seq_cst
218  ret i8 %res
219}
220
221define i8 @test_cmpxchg_i8_seqcst_seqcst(ptr %ptr, i8 %desired, i8 %newval) {
222; CHECK-LABEL: @test_cmpxchg_i8_seqcst_seqcst
223; CHECK: br label %[[START:.*]]
224
225; CHECK: [[START]]:
226; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
227; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
228; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i8 [[OLDVAL]], %desired
229; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
230
231; CHECK: [[FENCED_STORE]]:
232; CHECK: call void @llvm.arm.dmb(i32 11)
233; CHECK: br label %[[LOOP:.*]]
234
235; CHECK: [[LOOP]]:
236; CHECK: [[LOADED_LOOP:%.*]] = phi i8 [ [[OLDVAL]], %[[FENCED_STORE]] ], [ [[OLDVAL_LOOP:%.*]], %[[RELEASED_LOAD:.*]] ]
237; CHECK: [[NEWVAL32:%.*]] = zext i8 %newval to i32
238; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i8) %ptr)
239; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
240; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[RELEASED_LOAD]]
241
242; CHECK: [[RELEASED_LOAD]]:
243; CHECK: [[OLDVAL32_LOOP:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %ptr)
244; CHECK: [[OLDVAL_LOOP]] = trunc i32 [[OLDVAL32_LOOP]] to i8
245; CHECK: [[SHOULD_STORE_LOOP:%.*]] = icmp eq i8 [[OLDVAL_LOOP]], %desired
246; CHECK: br i1 [[SHOULD_STORE_LOOP]], label %[[LOOP]], label %[[NO_STORE_BB]]
247
248; CHECK: [[SUCCESS_BB]]:
249; CHECK: call void @llvm.arm.dmb(i32 11)
250; CHECK: br label %[[DONE:.*]]
251
252; CHECK: [[NO_STORE_BB]]:
253; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i8 [ [[OLDVAL]], %[[START]] ], [ [[OLDVAL_LOOP]], %[[RELEASED_LOAD]] ]
254; CHECK-NEXT: call void @llvm.arm.clrex()
255; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
256
257; CHECK: [[FAILURE_BB]]:
258; CHECK: [[LOADED_FAILURE:%.*]] = phi i8 [ [[LOADED_NO_STORE]], %[[NO_STORE_BB]] ]
259; CHECK: call void @llvm.arm.dmb(i32 11)
260; CHECK: br label %[[DONE]]
261
262; CHECK: [[DONE]]:
263; CHECK: [[LOADED:%.*]] = phi i8 [ [[LOADED_LOOP]], %[[SUCCESS_BB]] ], [ [[LOADED_FAILURE]], %[[FAILURE_BB]] ]
264; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
265; CHECK: ret i8 [[LOADED]]
266
267  %pairold = cmpxchg ptr %ptr, i8 %desired, i8 %newval seq_cst seq_cst
268  %old = extractvalue { i8, i1 } %pairold, 0
269  ret i8 %old
270}
271
272define i16 @test_cmpxchg_i16_seqcst_monotonic(ptr %ptr, i16 %desired, i16 %newval) {
273; CHECK-LABEL: @test_cmpxchg_i16_seqcst_monotonic
274; CHECK: br label %[[LOOP:.*]]
275
276; CHECK: [[LOOP]]:
277; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i16) %ptr)
278; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i16
279; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i16 [[OLDVAL]], %desired
280; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
281
282; CHECK: [[FENCED_STORE]]:
283; CHECK: call void @llvm.arm.dmb(i32 11)
284; CHECK: br label %[[LOOP:.*]]
285
286; CHECK: [[LOOP]]:
287; CHECK: [[LOADED_LOOP:%.*]] = phi i16 [ [[OLDVAL]], %[[FENCED_STORE]] ], [ [[OLDVAL_LOOP:%.*]], %[[RELEASED_LOAD:.*]] ]
288; CHECK: [[NEWVAL32:%.*]] = zext i16 %newval to i32
289; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0(i32 [[NEWVAL32]], ptr elementtype(i16) %ptr)
290; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
291; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[RELEASED_LOAD:.*]]
292
293; CHECK: [[RELEASED_LOAD]]:
294; CHECK: [[OLDVAL32_LOOP:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i16) %ptr)
295; CHECK: [[OLDVAL_LOOP]] = trunc i32 [[OLDVAL32_LOOP]] to i16
296; CHECK: [[SHOULD_STORE_LOOP:%.*]] = icmp eq i16 [[OLDVAL_LOOP]], %desired
297; CHECK: br i1 [[SHOULD_STORE_LOOP]], label %[[LOOP]], label %[[NO_STORE_BB]]
298
299; CHECK: [[SUCCESS_BB]]:
300; CHECK: call void @llvm.arm.dmb(i32 11)
301; CHECK: br label %[[DONE:.*]]
302
303; CHECK: [[NO_STORE_BB]]:
304; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i16 [ [[OLDVAL]], %[[START]] ], [ [[OLDVAL_LOOP]], %[[RELEASED_LOAD]] ]
305; CHECK-NEXT: call void @llvm.arm.clrex()
306; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
307
308; CHECK: [[FAILURE_BB]]:
309; CHECK-NEXT: [[LOADED_FAILURE:%.*]] = phi i16 [ [[LOADED_NO_STORE]], %[[NO_STORE_BB]] ]
310; CHECK-NOT: dmb
311; CHECK: br label %[[DONE]]
312
313; CHECK: [[DONE]]:
314; CHECK: [[LOADED:%.*]] = phi i16 [ [[LOADED_LOOP]], %[[SUCCESS_BB]] ], [ [[LOADED_FAILURE]], %[[FAILURE_BB]] ]
315; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
316; CHECK: ret i16 [[LOADED]]
317
318  %pairold = cmpxchg ptr %ptr, i16 %desired, i16 %newval seq_cst monotonic
319  %old = extractvalue { i16, i1 } %pairold, 0
320  ret i16 %old
321}
322
323define i32 @test_cmpxchg_i32_acquire_acquire(ptr %ptr, i32 %desired, i32 %newval) {
324; CHECK-LABEL: @test_cmpxchg_i32_acquire_acquire
325; CHECK-NOT: dmb
326; CHECK: br label %[[LOOP:.*]]
327
328; CHECK: [[LOOP]]:
329; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %ptr)
330; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i32 [[OLDVAL]], %desired
331; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
332
333; CHECK: [[FENCED_STORE]]:
334; CHECK-NEXT: br label %[[TRY_STORE:.*]]
335
336; CHECK: [[TRY_STORE]]:
337; CHECK: [[LOADED_TRYSTORE:%.*]] = phi i32 [ [[OLDVAL]], %[[FENCED_STORE]] ]
338; CHECK: [[TRYAGAIN:%.*]] =  call i32 @llvm.arm.strex.p0(i32 %newval, ptr elementtype(i32) %ptr)
339; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
340; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
341
342; CHECK: [[SUCCESS_BB]]:
343; CHECK: call void @llvm.arm.dmb(i32 11)
344; CHECK: br label %[[DONE:.*]]
345
346; CHECK: [[NO_STORE_BB]]:
347; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i32 [ [[OLDVAL]], %[[LOOP]] ]
348; CHECK-NEXT: call void @llvm.arm.clrex()
349; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
350
351; CHECK: [[FAILURE_BB]]:
352; CHECK: [[LOADED_FAILURE:%.*]] = phi i32 [ [[LOADED_NO_STORE]], %[[NO_STORE_BB]] ]
353; CHECK: call void @llvm.arm.dmb(i32 11)
354; CHECK: br label %[[DONE]]
355
356; CHECK: [[DONE]]:
357; CHECK: [[LOADED_EXIT:%.*]] = phi i32 [ [[LOADED_TRYSTORE]], %[[SUCCESS_BB]] ], [ [[LOADED_FAILURE]], %[[FAILURE_BB]] ]
358; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
359; CHECK: ret i32 [[LOADED_EXIT]]
360
361  %pairold = cmpxchg ptr %ptr, i32 %desired, i32 %newval acquire acquire
362  %old = extractvalue { i32, i1 } %pairold, 0
363  ret i32 %old
364}
365
366define i64 @test_cmpxchg_i64_monotonic_monotonic(ptr %ptr, i64 %desired, i64 %newval) {
367; CHECK-LABEL: @test_cmpxchg_i64_monotonic_monotonic
368; CHECK-NOT: dmb
369; CHECK: br label %[[LOOP:.*]]
370
371; CHECK: [[LOOP]]:
372; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(ptr %ptr)
373; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
374; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
375; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
376; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
377; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
378; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
379; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i64 [[OLDVAL]], %desired
380; CHECK: br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
381
382; CHECK: [[FENCED_STORE]]:
383; CHECK-NEXT: br label %[[TRY_STORE:.*]]
384
385; CHECK: [[TRY_STORE]]:
386; CHECK: [[LOADED_TRYSTORE:%.*]] = phi i64 [ [[OLDVAL]], %[[FENCED_STORE]] ]
387; CHECK: [[NEWLO:%.*]] = trunc i64 %newval to i32
388; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 %newval, 32
389; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
390; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], ptr %ptr)
391; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
392; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
393
394; CHECK: [[SUCCESS_BB]]:
395; CHECK-NOT: dmb
396; CHECK: br label %[[DONE:.*]]
397
398; CHECK: [[NO_STORE_BB]]:
399; CHECK-NEXT: [[LOADED_NO_STORE:%.*]] = phi i64 [ [[OLDVAL]], %[[LOOP]] ]
400; CHECK-NEXT: call void @llvm.arm.clrex()
401; CHECK-NEXT: br label %[[FAILURE_BB:.*]]
402
403; CHECK: [[FAILURE_BB]]:
404; CHECK-NEXT: [[LOADED_FAILURE:%.*]] = phi i64 [ [[LOADED_NO_STORE]], %[[NO_STORE_BB]] ]
405; CHECK-NOT: dmb
406; CHECK: br label %[[DONE]]
407
408; CHECK: [[DONE]]:
409; CHECK: [[LOADED_EXIT:%.*]] = phi i64 [ [[LOADED_TRYSTORE]], %[[SUCCESS_BB]] ], [ [[LOADED_FAILURE]], %[[FAILURE_BB]] ]
410; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
411; CHECK: ret i64 [[LOADED_EXIT]]
412
413  %pairold = cmpxchg ptr %ptr, i64 %desired, i64 %newval monotonic monotonic
414  %old = extractvalue { i64, i1 } %pairold, 0
415  ret i64 %old
416}
417
418define i32 @test_cmpxchg_minsize(ptr %addr, i32 %desired, i32 %new) minsize {
419; CHECK-LABEL: @test_cmpxchg_minsize
420; CHECK:     call void @llvm.arm.dmb(i32 11)
421; CHECK:     br label %[[START:.*]]
422
423; CHECK: [[START]]:
424; CHECK:     [[LOADED:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %addr)
425; CHECK:     [[SHOULD_STORE:%.*]] = icmp eq i32 [[LOADED]], %desired
426; CHECK:     br i1 [[SHOULD_STORE]], label %[[FENCED_STORE:.*]], label %[[NO_STORE_BB:.*]]
427
428; CHECK: [[FENCED_STORE]]:
429; CHECK-NEXT: br label %[[TRY_STORE:.*]]
430
431; CHECK: [[TRY_STORE]]:
432; CHECK:     [[LOADED_TRYSTORE:%.*]] = phi i32 [ [[LOADED]], %[[FENCED_STORE]] ]
433; CHECK:     [[STREX:%.*]] = call i32 @llvm.arm.strex.p0(i32 %new, ptr elementtype(i32) %addr)
434; CHECK:     [[SUCCESS:%.*]] = icmp eq i32 [[STREX]], 0
435; CHECK:     br i1 [[SUCCESS]], label %[[SUCCESS_BB:.*]], label %[[START]]
436
437; CHECK: [[SUCCESS_BB]]:
438; CHECK:     call void @llvm.arm.dmb(i32 11)
439; CHECK:     br label %[[END:.*]]
440
441; CHECK: [[NO_STORE_BB]]:
442; CHECK:     [[LOADED_NO_STORE:%.*]] = phi i32 [ [[LOADED]], %[[START]] ]
443; CHECK:     call void @llvm.arm.clrex()
444; CHECK:     br label %[[FAILURE_BB]]
445
446; CHECK: [[FAILURE_BB]]:
447; CHECK:     [[LOADED_FAILURE:%.*]] = phi i32 [ [[LOADED_NO_STORE]], %[[NO_STORE_BB]] ]
448; CHECK:     call void @llvm.arm.dmb(i32 11)
449; CHECK:     br label %[[END]]
450
451; CHECK: [[END]]:
452; CHECK: [[LOADED_EXIT:%.*]] = phi i32 [ [[LOADED_TRYSTORE]], %[[SUCCESS_BB]] ], [ [[LOADED_FAILURE]], %[[FAILURE_BB]] ]
453; CHECK:     [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
454; CHECK:     ret i32 [[LOADED_EXIT]]
455
456  %pair = cmpxchg ptr %addr, i32 %desired, i32 %new seq_cst seq_cst
457  %oldval = extractvalue { i32, i1 } %pair, 0
458  ret i32 %oldval
459}
460