1; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s
2; RUN: llc < %s -global-isel -global-isel-abort=2 -pass-remarks-missed=gisel* -mtriple=arm64-linux-gnu 2>&1 | FileCheck %s --check-prefixes=GISEL,FALLBACK
3
4%0 = type { i64, i64 }
5
6define i128 @f0(i8* %p) nounwind readonly {
7; CHECK-LABEL: f0:
8; CHECK: ldxp {{x[0-9]+}}, {{x[0-9]+}}, [x0]
9entry:
10  %ldrexd = tail call %0 @llvm.aarch64.ldxp(i8* %p)
11  %0 = extractvalue %0 %ldrexd, 1
12  %1 = extractvalue %0 %ldrexd, 0
13  %2 = zext i64 %0 to i128
14  %3 = zext i64 %1 to i128
15  %shl = shl nuw i128 %2, 64
16  %4 = or i128 %shl, %3
17  ret i128 %4
18}
19
20define i32 @f1(i8* %ptr, i128 %val) nounwind {
21; CHECK-LABEL: f1:
22; CHECK: stxp {{w[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, [x0]
23entry:
24  %tmp4 = trunc i128 %val to i64
25  %tmp6 = lshr i128 %val, 64
26  %tmp7 = trunc i128 %tmp6 to i64
27  %strexd = tail call i32 @llvm.aarch64.stxp(i64 %tmp4, i64 %tmp7, i8* %ptr)
28  ret i32 %strexd
29}
30
31declare %0 @llvm.aarch64.ldxp(i8*) nounwind
32declare i32 @llvm.aarch64.stxp(i64, i64, i8*) nounwind
33
34@var = global i64 0, align 8
35
36; FALLBACK-NOT: remark:{{.*}}test_load_i8
37define void @test_load_i8(i8* %addr) {
38; CHECK-LABEL: test_load_i8:
39; CHECK: ldxrb w[[LOADVAL:[0-9]+]], [x0]
40; CHECK-NOT: uxtb
41; CHECK-NOT: and
42; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
43
44; GISEL-LABEL: test_load_i8:
45; GISEL: ldxrb w[[LOADVAL:[0-9]+]], [x0]
46; GISEL-NOT: uxtb
47; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
48  %val = call i64 @llvm.aarch64.ldxr.p0i8(i8* %addr)
49  %shortval = trunc i64 %val to i8
50  %extval = zext i8 %shortval to i64
51  store i64 %extval, i64* @var, align 8
52  ret void
53}
54
55; FALLBACK-NOT: remark:{{.*}}test_load_i16
56define void @test_load_i16(i16* %addr) {
57; CHECK-LABEL: test_load_i16:
58; CHECK: ldxrh w[[LOADVAL:[0-9]+]], [x0]
59; CHECK-NOT: uxth
60; CHECK-NOT: and
61; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
62
63; GISEL-LABEL: test_load_i16:
64; GISEL: ldxrh w[[LOADVAL:[0-9]+]], [x0]
65; GISEL-NOT: uxtb
66; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
67  %val = call i64 @llvm.aarch64.ldxr.p0i16(i16* %addr)
68  %shortval = trunc i64 %val to i16
69  %extval = zext i16 %shortval to i64
70  store i64 %extval, i64* @var, align 8
71  ret void
72}
73
74; FALLBACK-NOT: remark:{{.*}}test_load_i32
75define void @test_load_i32(i32* %addr) {
76; CHECK-LABEL: test_load_i32:
77; CHECK: ldxr w[[LOADVAL:[0-9]+]], [x0]
78; CHECK-NOT: uxtw
79; CHECK-NOT: and
80; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
81
82; GISEL-LABEL: test_load_i32:
83; GISEL: ldxr w[[LOADVAL:[0-9]+]], [x0]
84; GISEL-NOT: uxtb
85; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
86  %val = call i64 @llvm.aarch64.ldxr.p0i32(i32* %addr)
87  %shortval = trunc i64 %val to i32
88  %extval = zext i32 %shortval to i64
89  store i64 %extval, i64* @var, align 8
90  ret void
91}
92
93; FALLBACK-NOT: remark:{{.*}}test_load_i64
94define void @test_load_i64(i64* %addr) {
95; CHECK-LABEL: test_load_i64:
96; CHECK: ldxr x[[LOADVAL:[0-9]+]], [x0]
97; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
98
99; GISEL-LABEL: test_load_i64:
100; GISEL: ldxr x[[LOADVAL:[0-9]+]], [x0]
101; GISEL-NOT: uxtb
102; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
103  %val = call i64 @llvm.aarch64.ldxr.p0i64(i64* %addr)
104  store i64 %val, i64* @var, align 8
105  ret void
106}
107
108
109declare i64 @llvm.aarch64.ldxr.p0i8(i8*) nounwind
110declare i64 @llvm.aarch64.ldxr.p0i16(i16*) nounwind
111declare i64 @llvm.aarch64.ldxr.p0i32(i32*) nounwind
112declare i64 @llvm.aarch64.ldxr.p0i64(i64*) nounwind
113
114; FALLBACK-NOT: remark:{{.*}}test_store_i8
115define i32 @test_store_i8(i32, i8 %val, i8* %addr) {
116; CHECK-LABEL: test_store_i8:
117; CHECK-NOT: uxtb
118; CHECK-NOT: and
119; CHECK: stxrb w0, w1, [x2]
120; GISEL-LABEL: test_store_i8:
121; GISEL-NOT: uxtb
122; GISEL-NOT: and
123; GISEL: stxrb w0, w1, [x2]
124  %extval = zext i8 %val to i64
125  %res = call i32 @llvm.aarch64.stxr.p0i8(i64 %extval, i8* %addr)
126  ret i32 %res
127}
128
129; FALLBACK-NOT: remark:{{.*}}test_store_i16
130define i32 @test_store_i16(i32, i16 %val, i16* %addr) {
131; CHECK-LABEL: test_store_i16:
132; CHECK-NOT: uxth
133; CHECK-NOT: and
134; CHECK: stxrh w0, w1, [x2]
135; GISEL-LABEL: test_store_i16:
136; GISEL-NOT: uxth
137; GISEL-NOT: and
138; GISEL: stxrh w0, w1, [x2]
139  %extval = zext i16 %val to i64
140  %res = call i32 @llvm.aarch64.stxr.p0i16(i64 %extval, i16* %addr)
141  ret i32 %res
142}
143
144; FALLBACK-NOT: remark:{{.*}}test_store_i32
145define i32 @test_store_i32(i32, i32 %val, i32* %addr) {
146; CHECK-LABEL: test_store_i32:
147; CHECK-NOT: uxtw
148; CHECK-NOT: and
149; CHECK: stxr w0, w1, [x2]
150; GISEL-LABEL: test_store_i32:
151; GISEL-NOT: uxtw
152; GISEL-NOT: and
153; GISEL: stxr w0, w1, [x2]
154  %extval = zext i32 %val to i64
155  %res = call i32 @llvm.aarch64.stxr.p0i32(i64 %extval, i32* %addr)
156  ret i32 %res
157}
158
159; FALLBACK-NOT: remark:{{.*}}test_store_i64
160define i32 @test_store_i64(i32, i64 %val, i64* %addr) {
161; CHECK-LABEL: test_store_i64:
162; CHECK: stxr w0, x1, [x2]
163; GISEL-LABEL: test_store_i64:
164; GISEL: stxr w0, x1, [x2]
165  %res = call i32 @llvm.aarch64.stxr.p0i64(i64 %val, i64* %addr)
166  ret i32 %res
167}
168
169declare i32 @llvm.aarch64.stxr.p0i8(i64, i8*) nounwind
170declare i32 @llvm.aarch64.stxr.p0i16(i64, i16*) nounwind
171declare i32 @llvm.aarch64.stxr.p0i32(i64, i32*) nounwind
172declare i32 @llvm.aarch64.stxr.p0i64(i64, i64*) nounwind
173
174; CHECK: test_clear:
175; CHECK: clrex
176define void @test_clear() {
177  call void @llvm.aarch64.clrex()
178  ret void
179}
180
181declare void @llvm.aarch64.clrex() nounwind
182
183define i128 @test_load_acquire_i128(i8* %p) nounwind readonly {
184; CHECK-LABEL: test_load_acquire_i128:
185; CHECK: ldaxp {{x[0-9]+}}, {{x[0-9]+}}, [x0]
186entry:
187  %ldrexd = tail call %0 @llvm.aarch64.ldaxp(i8* %p)
188  %0 = extractvalue %0 %ldrexd, 1
189  %1 = extractvalue %0 %ldrexd, 0
190  %2 = zext i64 %0 to i128
191  %3 = zext i64 %1 to i128
192  %shl = shl nuw i128 %2, 64
193  %4 = or i128 %shl, %3
194  ret i128 %4
195}
196
197define i32 @test_store_release_i128(i8* %ptr, i128 %val) nounwind {
198; CHECK-LABEL: test_store_release_i128:
199; CHECK: stlxp {{w[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, [x0]
200entry:
201  %tmp4 = trunc i128 %val to i64
202  %tmp6 = lshr i128 %val, 64
203  %tmp7 = trunc i128 %tmp6 to i64
204  %strexd = tail call i32 @llvm.aarch64.stlxp(i64 %tmp4, i64 %tmp7, i8* %ptr)
205  ret i32 %strexd
206}
207
208declare %0 @llvm.aarch64.ldaxp(i8*) nounwind
209declare i32 @llvm.aarch64.stlxp(i64, i64, i8*) nounwind
210
211; FALLBACK-NOT: remark:{{.*}}test_load_acquire_i8
212define void @test_load_acquire_i8(i8* %addr) {
213; CHECK-LABEL: test_load_acquire_i8:
214; CHECK: ldaxrb w[[LOADVAL:[0-9]+]], [x0]
215; CHECK-NOT: uxtb
216; CHECK-NOT: and
217; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
218
219; GISEL-LABEL: test_load_acquire_i8:
220; GISEL: ldaxrb w[[LOADVAL:[0-9]+]], [x0]
221; GISEL-DAG: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
222  %val = call i64 @llvm.aarch64.ldaxr.p0i8(i8* %addr)
223  %shortval = trunc i64 %val to i8
224  %extval = zext i8 %shortval to i64
225  store i64 %extval, i64* @var, align 8
226  ret void
227}
228
229; FALLBACK-NOT: remark:{{.*}}test_load_acquire_i16
230define void @test_load_acquire_i16(i16* %addr) {
231; CHECK-LABEL: test_load_acquire_i16:
232; CHECK: ldaxrh w[[LOADVAL:[0-9]+]], [x0]
233; CHECK-NOT: uxth
234; CHECK-NOT: and
235; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
236
237; GISEL-LABEL: test_load_acquire_i16:
238; GISEL: ldaxrh w[[LOADVAL:[0-9]+]], [x0]
239; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
240  %val = call i64 @llvm.aarch64.ldaxr.p0i16(i16* %addr)
241  %shortval = trunc i64 %val to i16
242  %extval = zext i16 %shortval to i64
243  store i64 %extval, i64* @var, align 8
244  ret void
245}
246
247; FALLBACK-NOT: remark:{{.*}}test_load_acquire_i32
248define void @test_load_acquire_i32(i32* %addr) {
249; CHECK-LABEL: test_load_acquire_i32:
250; CHECK: ldaxr w[[LOADVAL:[0-9]+]], [x0]
251; CHECK-NOT: uxtw
252; CHECK-NOT: and
253; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
254
255; GISEL-LABEL: test_load_acquire_i32:
256; GISEL: ldaxr w[[LOADVAL:[0-9]+]], [x0]
257; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
258  %val = call i64 @llvm.aarch64.ldaxr.p0i32(i32* %addr)
259  %shortval = trunc i64 %val to i32
260  %extval = zext i32 %shortval to i64
261  store i64 %extval, i64* @var, align 8
262  ret void
263}
264
265; FALLBACK-NOT: remark:{{.*}}test_load_acquire_i64
266define void @test_load_acquire_i64(i64* %addr) {
267; CHECK-LABEL: test_load_acquire_i64:
268; CHECK: ldaxr x[[LOADVAL:[0-9]+]], [x0]
269; CHECK: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
270
271; GISEL-LABEL: test_load_acquire_i64:
272; GISEL: ldaxr x[[LOADVAL:[0-9]+]], [x0]
273; GISEL: str x[[LOADVAL]], [{{x[0-9]+}}, :lo12:var]
274  %val = call i64 @llvm.aarch64.ldaxr.p0i64(i64* %addr)
275  store i64 %val, i64* @var, align 8
276  ret void
277}
278
279
280declare i64 @llvm.aarch64.ldaxr.p0i8(i8*) nounwind
281declare i64 @llvm.aarch64.ldaxr.p0i16(i16*) nounwind
282declare i64 @llvm.aarch64.ldaxr.p0i32(i32*) nounwind
283declare i64 @llvm.aarch64.ldaxr.p0i64(i64*) nounwind
284
285; FALLBACK-NOT: remark:{{.*}}test_store_release_i8
286define i32 @test_store_release_i8(i32, i8 %val, i8* %addr) {
287; CHECK-LABEL: test_store_release_i8:
288; CHECK-NOT: uxtb
289; CHECK-NOT: and
290; CHECK: stlxrb w0, w1, [x2]
291; GISEL-LABEL: test_store_release_i8:
292; GISEL-NOT: uxtb
293; GISEL-NOT: and
294; GISEL: stlxrb w0, w1, [x2]
295  %extval = zext i8 %val to i64
296  %res = call i32 @llvm.aarch64.stlxr.p0i8(i64 %extval, i8* %addr)
297  ret i32 %res
298}
299
300; FALLBACK-NOT: remark:{{.*}}test_store_release_i16
301define i32 @test_store_release_i16(i32, i16 %val, i16* %addr) {
302; CHECK-LABEL: test_store_release_i16:
303; CHECK-NOT: uxth
304; CHECK-NOT: and
305; CHECK: stlxrh w0, w1, [x2]
306; GISEL-LABEL: test_store_release_i16:
307; GISEL-NOT: uxth
308; GISEL-NOT: and
309; GISEL: stlxrh w0, w1, [x2]
310  %extval = zext i16 %val to i64
311  %res = call i32 @llvm.aarch64.stlxr.p0i16(i64 %extval, i16* %addr)
312  ret i32 %res
313}
314
315; FALLBACK-NOT: remark:{{.*}}test_store_release_i32
316define i32 @test_store_release_i32(i32, i32 %val, i32* %addr) {
317; CHECK-LABEL: test_store_release_i32:
318; CHECK-NOT: uxtw
319; CHECK-NOT: and
320; CHECK: stlxr w0, w1, [x2]
321; GISEL-LABEL: test_store_release_i32:
322; GISEL-NOT: uxtw
323; GISEL-NOT: and
324; GISEL: stlxr w0, w1, [x2]
325  %extval = zext i32 %val to i64
326  %res = call i32 @llvm.aarch64.stlxr.p0i32(i64 %extval, i32* %addr)
327  ret i32 %res
328}
329
330; FALLBACK-NOT: remark:{{.*}}test_store_release_i64
331define i32 @test_store_release_i64(i32, i64 %val, i64* %addr) {
332; CHECK-LABEL: test_store_release_i64:
333; CHECK: stlxr w0, x1, [x2]
334; GISEL-LABEL: test_store_release_i64:
335; GISEL: stlxr w0, x1, [x2]
336  %res = call i32 @llvm.aarch64.stlxr.p0i64(i64 %val, i64* %addr)
337  ret i32 %res
338}
339
340declare i32 @llvm.aarch64.stlxr.p0i8(i64, i8*) nounwind
341declare i32 @llvm.aarch64.stlxr.p0i16(i64, i16*) nounwind
342declare i32 @llvm.aarch64.stlxr.p0i32(i64, i32*) nounwind
343declare i32 @llvm.aarch64.stlxr.p0i64(i64, i64*) nounwind
344