1; RUN: llc < %s -mtriple=arm64-linux-gnu -verify-machineinstrs -mcpu=cyclone | FileCheck %s
2
3@var = global i128 0
4
5define i128 @val_compare_and_swap(i128* %p, i128 %oldval, i128 %newval) {
6; CHECK-LABEL: val_compare_and_swap:
7; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
8; CHECK: ldaxp   [[RESULTLO:x[0-9]+]], [[RESULTHI:x[0-9]+]], [x[[ADDR:[0-9]+]]]
9; CHECK-DAG: eor     [[MISMATCH_LO:x[0-9]+]], [[RESULTLO]], x2
10; CHECK-DAG: eor     [[MISMATCH_HI:x[0-9]+]], [[RESULTHI]], x3
11; CHECK: orr [[MISMATCH:x[0-9]+]], [[MISMATCH_LO]], [[MISMATCH_HI]]
12; CHECK: cbnz    [[MISMATCH]], [[DONE:.LBB[0-9]+_[0-9]+]]
13; CHECK: stxp   [[SCRATCH_RES:w[0-9]+]], x4, x5, [x[[ADDR]]]
14; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
15; CHECK: [[DONE]]:
16  %pair = cmpxchg i128* %p, i128 %oldval, i128 %newval acquire acquire
17  %val = extractvalue { i128, i1 } %pair, 0
18  ret i128 %val
19}
20
21define void @fetch_and_nand(i128* %p, i128 %bits) {
22; CHECK-LABEL: fetch_and_nand:
23; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
24; CHECK: ldxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
25; CHECK-DAG: and    [[TMP_REGLO:x[0-9]+]], [[DEST_REGLO]], x2
26; CHECK-DAG: and    [[TMP_REGHI:x[0-9]+]], [[DEST_REGHI]], x3
27; CHECK-DAG: mvn    [[SCRATCH_REGLO:x[0-9]+]], [[TMP_REGLO]]
28; CHECK-DAG: mvn    [[SCRATCH_REGHI:x[0-9]+]], [[TMP_REGHI]]
29; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
30; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
31
32; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
33  %val = atomicrmw nand i128* %p, i128 %bits release
34  store i128 %val, i128* @var, align 16
35  ret void
36}
37
38define void @fetch_and_or(i128* %p, i128 %bits) {
39; CHECK-LABEL: fetch_and_or:
40; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
41; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
42; CHECK-DAG: orr    [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2
43; CHECK-DAG: orr    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3
44; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
45; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
46
47; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
48  %val = atomicrmw or i128* %p, i128 %bits seq_cst
49  store i128 %val, i128* @var, align 16
50  ret void
51}
52
53define void @fetch_and_add(i128* %p, i128 %bits) {
54; CHECK-LABEL: fetch_and_add:
55; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
56; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
57; CHECK: adds   [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2
58; CHECK: adcs   [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3
59; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
60; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
61
62; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
63  %val = atomicrmw add i128* %p, i128 %bits seq_cst
64  store i128 %val, i128* @var, align 16
65  ret void
66}
67
68define void @fetch_and_sub(i128* %p, i128 %bits) {
69; CHECK-LABEL: fetch_and_sub:
70; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
71; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
72; CHECK: subs   [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2
73; CHECK: sbcs    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3
74; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
75; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
76
77; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
78  %val = atomicrmw sub i128* %p, i128 %bits seq_cst
79  store i128 %val, i128* @var, align 16
80  ret void
81}
82
83define void @fetch_and_min(i128* %p, i128 %bits) {
84; CHECK-LABEL: fetch_and_min:
85; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
86; CHECK: ldaxp   [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
87; CHECK: cmp     [[DEST_REGLO]], x2
88; CHECK: cset    [[LOCMP:w[0-9]+]], ls
89; CHECK: cmp     [[DEST_REGHI:x[0-9]+]], x3
90; CHECK: cset    [[HICMP:w[0-9]+]], le
91; CHECK: csel    [[CMP:w[0-9]+]], [[LOCMP]], [[HICMP]], eq
92; CHECK: cmp     [[CMP]], #0
93; CHECK-DAG: csel    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3, ne
94; CHECK-DAG: csel    [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2, ne
95; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
96; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
97
98; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
99  %val = atomicrmw min i128* %p, i128 %bits seq_cst
100  store i128 %val, i128* @var, align 16
101  ret void
102}
103
104define void @fetch_and_max(i128* %p, i128 %bits) {
105; CHECK-LABEL: fetch_and_max:
106; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
107; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
108; CHECK: cmp     [[DEST_REGLO]], x2
109; CHECK: cset    [[LOCMP:w[0-9]+]], hi
110; CHECK: cmp     [[DEST_REGHI:x[0-9]+]], x3
111; CHECK: cset    [[HICMP:w[0-9]+]], gt
112; CHECK: csel    [[CMP:w[0-9]+]], [[LOCMP]], [[HICMP]], eq
113; CHECK: cmp     [[CMP]], #0
114; CHECK-DAG: csel    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3, ne
115; CHECK-DAG: csel    [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2, ne
116; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
117; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
118
119; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
120  %val = atomicrmw max i128* %p, i128 %bits seq_cst
121  store i128 %val, i128* @var, align 16
122  ret void
123}
124
125define void @fetch_and_umin(i128* %p, i128 %bits) {
126; CHECK-LABEL: fetch_and_umin:
127; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
128; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
129; CHECK: cmp     [[DEST_REGLO]], x2
130; CHECK: cset    [[LOCMP:w[0-9]+]], ls
131; CHECK: cmp     [[DEST_REGHI:x[0-9]+]], x3
132; CHECK: cset    [[HICMP:w[0-9]+]], ls
133; CHECK: csel    [[CMP:w[0-9]+]], [[LOCMP]], [[HICMP]], eq
134; CHECK: cmp     [[CMP]], #0
135; CHECK-DAG: csel    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3, ne
136; CHECK-DAG: csel    [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2, ne
137; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
138; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
139
140; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
141  %val = atomicrmw umin i128* %p, i128 %bits seq_cst
142  store i128 %val, i128* @var, align 16
143  ret void
144}
145
146define void @fetch_and_umax(i128* %p, i128 %bits) {
147; CHECK-LABEL: fetch_and_umax:
148; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
149; CHECK: ldaxp  [[DEST_REGLO:x[0-9]+]], [[DEST_REGHI:x[0-9]+]], [x0]
150; CHECK: cmp     [[DEST_REGLO]], x2
151; CHECK: cset    [[LOCMP:w[0-9]+]], hi
152; CHECK: cmp     [[DEST_REGHI:x[0-9]+]], x3
153; CHECK: cset    [[HICMP:w[0-9]+]], hi
154; CHECK: csel    [[CMP:w[0-9]+]], [[LOCMP]], [[HICMP]], eq
155; CHECK: cmp     [[CMP]], #0
156; CHECK-DAG: csel    [[SCRATCH_REGHI:x[0-9]+]], [[DEST_REGHI]], x3, ne
157; CHECK-DAG: csel    [[SCRATCH_REGLO:x[0-9]+]], [[DEST_REGLO]], x2, ne
158; CHECK: stlxp  [[SCRATCH_RES:w[0-9]+]], [[SCRATCH_REGLO]], [[SCRATCH_REGHI]], [x0]
159; CHECK: cbnz   [[SCRATCH_RES]], [[LABEL]]
160
161; CHECK-DAG: stp    [[DEST_REGLO]], [[DEST_REGHI]]
162  %val = atomicrmw umax i128* %p, i128 %bits seq_cst
163  store i128 %val, i128* @var, align 16
164  ret void
165}
166
167define i128 @atomic_load_seq_cst(i128* %p) {
168; CHECK-LABEL: atomic_load_seq_cst:
169; CHECK-NOT: dmb
170; CHECK-LABEL: ldaxp
171; CHECK-NOT: dmb
172   %r = load atomic i128, i128* %p seq_cst, align 16
173   ret i128 %r
174}
175
176define i128 @atomic_load_relaxed(i64, i64, i128* %p) {
177; CHECK-LABEL: atomic_load_relaxed:
178; CHECK-NOT: dmb
179; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
180; CHECK: ldxp [[LO:x[0-9]+]], [[HI:x[0-9]+]], [x2]
181; CHECK-NEXT: stxp [[SUCCESS:w[0-9]+]], [[LO]], [[HI]], [x2]
182; CHECK: cbnz [[SUCCESS]], [[LABEL]]
183; CHECK-NOT: dmb
184   %r = load atomic i128, i128* %p monotonic, align 16
185   ret i128 %r
186}
187
188
189define void @atomic_store_seq_cst(i128 %in, i128* %p) {
190; CHECK-LABEL: atomic_store_seq_cst:
191; CHECK-NOT: dmb
192; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
193; CHECK: ldaxp xzr, [[IGNORED:x[0-9]+]], [x2]
194; CHECK: stlxp [[SUCCESS:w[0-9]+]], x0, x1, [x2]
195; CHECK: cbnz [[SUCCESS]], [[LABEL]]
196; CHECK-NOT: dmb
197   store atomic i128 %in, i128* %p seq_cst, align 16
198   ret void
199}
200
201define void @atomic_store_release(i128 %in, i128* %p) {
202; CHECK-LABEL: atomic_store_release:
203; CHECK-NOT: dmb
204; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
205; CHECK: ldxp xzr, [[IGNORED:x[0-9]+]], [x2]
206; CHECK: stlxp [[SUCCESS:w[0-9]+]], x0, x1, [x2]
207; CHECK: cbnz [[SUCCESS]], [[LABEL]]
208; CHECK-NOT: dmb
209   store atomic i128 %in, i128* %p release, align 16
210   ret void
211}
212
213define void @atomic_store_relaxed(i128 %in, i128* %p) {
214; CHECK-LABEL: atomic_store_relaxed:
215; CHECK-NOT: dmb
216; CHECK: [[LABEL:.?LBB[0-9]+_[0-9]+]]:
217; CHECK: ldxp xzr, [[IGNORED:x[0-9]+]], [x2]
218; CHECK: stxp [[SUCCESS:w[0-9]+]], x0, x1, [x2]
219; CHECK: cbnz [[SUCCESS]], [[LABEL]]
220; CHECK-NOT: dmb
221   store atomic i128 %in, i128* %p unordered, align 16
222   ret void
223}
224