xref: /llvm-project/llvm/test/CodeGen/ARM/cmpxchg-O0.ll (revision 9cf68679c4f45e79d67c94ef1f968c7c1213b610)
1; RUN: llc -verify-machineinstrs -mtriple=armv7-linux-gnu -O0 %s -o - | FileCheck %s
2; RUN: llc -verify-machineinstrs -mtriple=thumbv8-linux-gnu -O0 %s -o - | FileCheck %s
3; RUN: llc -verify-machineinstrs -mtriple=thumbv6m-none-eabi -O0 %s -o - | FileCheck %s --check-prefix=CHECK-T1
4
5; CHECK-T1-NOT: ldrex
6; CHECK-T1-NOT: strex
7
8define { i8, i1 } @test_cmpxchg_8(ptr %addr, i8 %desired, i8 %new) nounwind {
9; CHECK-LABEL: test_cmpxchg_8:
10; CHECK-DAG: mov [[ADDR:r[0-9]+]], r0
11; CHECK-DAG: mov [[NEW:r[0-9]+]], r2
12; CHECK:     dmb ish
13; CHECK:     uxtb [[DESIRED:r[0-9]+]], [[DESIRED]]
14; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
15; CHECK:     ldrexb [[OLD:[lr0-9]+]], [[[ADDR]]]
16; CHECK:     cmp [[OLD]], [[DESIRED]]
17; CHECK:     bne [[DONE:.LBB[0-9]+_[0-9]+]]
18; CHECK:     strexb [[STATUS:r[0-9]+]], [[NEW]], [[[ADDR]]]
19; CHECK:     cmp{{(\.w)?}} [[STATUS]], #0
20; CHECK:     bne [[RETRY]]
21; CHECK: [[DONE]]:
22; Materialisation of a boolean is done with sub/clz/lsr
23; CHECK:     uxtb [[CMP1:r[0-9]+]], [[DESIRED]]
24; CHECK:     sub{{(\.w|s)?}} [[CMP1]], [[OLD]], [[CMP1]]
25; CHECK:     clz [[CMP2:r[0-9]+]], [[CMP1]]
26; CHECK:     lsr{{(s)?}} {{r[0-9]+}}, [[CMP2]], #5
27; CHECK:     dmb ish
28  %res = cmpxchg ptr %addr, i8 %desired, i8 %new seq_cst monotonic
29  ret { i8, i1 } %res
30}
31
32define { i16, i1 } @test_cmpxchg_16(ptr %addr, i16 %desired, i16 %new) nounwind {
33; CHECK-LABEL: test_cmpxchg_16:
34; CHECK-DAG: mov [[ADDR:r[0-9]+]], r0
35; CHECK-DAG: mov [[NEW:r[0-9]+]], r2
36; CHECK:     dmb ish
37; CHECK:     uxth [[DESIRED:r[0-9]+]], [[DESIRED]]
38; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
39; CHECK:     ldrexh [[OLD:[lr0-9]+]], [[[ADDR]]]
40; CHECK:     cmp [[OLD]], [[DESIRED]]
41; CHECK:     bne [[DONE:.LBB[0-9]+_[0-9]+]]
42; CHECK:     strexh [[STATUS:r[0-9]+]], [[NEW]], [[[ADDR]]]
43; CHECK:     cmp{{(\.w)?}} [[STATUS]], #0
44; CHECK:     bne [[RETRY]]
45; CHECK: [[DONE]]:
46; Materialisation of a boolean is done with sub/clz/lsr
47; CHECK:     uxth [[CMP1:r[0-9]+]], [[DESIRED]]
48; CHECK:     sub{{(\.w|s)?}} [[CMP1]], [[OLD]], [[CMP1]]
49; CHECK:     clz [[CMP2:r[0-9]+]], [[CMP1]]
50; CHECK:     lsr{{(s)?}} {{r[0-9]+}}, [[CMP2]], #5
51; CHECK:     dmb ish
52  %res = cmpxchg ptr %addr, i16 %desired, i16 %new seq_cst monotonic
53  ret { i16, i1 } %res
54}
55
56define { i32, i1 } @test_cmpxchg_32(ptr %addr, i32 %desired, i32 %new) nounwind {
57; CHECK-LABEL: test_cmpxchg_32:
58; CHECK-DAG: mov [[ADDR:r[0-9]+]], r0
59; CHECK-DAG: mov [[NEW:r[0-9]+]], r2
60; CHECK:     dmb ish
61; CHECK-NOT:     uxt
62; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
63; CHECK:     ldrex [[OLD:r[0-9]+]], [[[ADDR]]]
64; CHECK:     cmp [[OLD]], [[DESIRED]]
65; CHECK:     bne [[DONE:.LBB[0-9]+_[0-9]+]]
66; CHECK:     strex [[STATUS:r[0-9]+]], [[NEW]], [[[ADDR]]]
67; CHECK:     cmp{{(\.w)?}} [[STATUS]], #0
68; CHECK:     bne [[RETRY]]
69; CHECK: [[DONE]]:
70; Materialisation of a boolean is done with sub/clz/lsr
71; CHECK:     sub{{(s)?}} [[CMP1:r[0-9]+]], [[OLD]], [[DESIRED]]
72; CHECK:     clz [[CMP2:r[0-9]+]], [[CMP1]]
73; CHECK:     lsr{{(s)?}} {{r[0-9]+}}, [[CMP2]], #5
74; CHECK:     dmb ish
75  %res = cmpxchg ptr %addr, i32 %desired, i32 %new seq_cst monotonic
76  ret { i32, i1 } %res
77}
78
79define { i64, i1 } @test_cmpxchg_64(ptr %addr, i64 %desired, i64 %new) nounwind {
80; CHECK-LABEL: test_cmpxchg_64:
81; CHECK:     dmb ish
82; CHECK-NOT: uxt
83; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
84; CHECK:     ldrexd [[OLDLO:r[0-9]+]], [[OLDHI:r[0-9]+]], [r0]
85; CHECK:     cmp [[OLDLO]], r6
86; CHECK:     cmpeq [[OLDHI]], r7
87; CHECK:     bne [[DONE:.LBB[0-9]+_[0-9]+]]
88; CHECK:     strexd [[STATUS:[lr0-9]+]], r8, r9, [r0]
89; CHECK:     cmp{{(\.w)?}} [[STATUS]], #0
90; CHECK:     bne [[RETRY]]
91; CHECK: [[DONE]]:
92; CHECK:     dmb ish
93  %res = cmpxchg ptr %addr, i64 %desired, i64 %new seq_cst monotonic
94  ret { i64, i1 } %res
95}
96
97define { i64, i1 } @test_nontrivial_args(ptr %addr, i64 %desired, i64 %new) {
98; CHECK-LABEL: test_nontrivial_args:
99; CHECK:     mov [[ADDR:r[0-9]+]], r0
100; CHECK:     dmb ish
101; CHECK-NOT: uxt
102; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
103; CHECK:     ldrexd [[OLDLO:r[0-9]+]], [[OLDHI:r[0-9]+]], [[[ADDR]]]
104; CHECK:     cmp [[OLDLO]], {{r[0-9]+}}
105; CHECK:     cmpeq [[OLDHI]], {{r[0-9]+}}
106; CHECK:     bne [[DONE:.LBB[0-9]+_[0-9]+]]
107; CHECK:     strexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [[[ADDR]]]
108; CHECK:     cmp{{(\.w)?}} [[STATUS]], #0
109; CHECK:     bne [[RETRY]]
110; CHECK: [[DONE]]:
111; CHECK:     dmb ish
112
113  %desired1 = add i64 %desired, 1
114  %new1 = add i64 %new, 1
115  %res = cmpxchg ptr %addr, i64 %desired1, i64 %new1 seq_cst seq_cst
116  ret { i64, i1 } %res
117}
118
119; The following used to trigger an assertion when creating a spill on thumb2
120; for a physreg with RC==GPRPairRegClass.
121; CHECK-LABEL: test_cmpxchg_spillbug:
122; CHECK: ldrexd
123; CHECK: strexd
124; CHECK: bne
125define void @test_cmpxchg_spillbug() {
126  %v = cmpxchg ptr undef, i64 undef, i64 undef seq_cst seq_cst
127  ret void
128}
129