xref: /llvm-project/llvm/test/CodeGen/AArch64/arm64-ldxr-stxr.ll (revision eff6b642583ace53aaed7947b92a43bcba283866)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD
3; RUN: llc < %s -mtriple=arm64-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
4
5%0 = type { i64, i64 }
6
7define dso_local i128 @f0(ptr %p) nounwind readonly {
8; CHECK-LABEL: f0:
9; CHECK:       // %bb.0: // %entry
10; CHECK-NEXT:    ldxp x0, x1, [x0]
11; CHECK-NEXT:    ret
12entry:
13  %ldrexd = tail call %0 @llvm.aarch64.ldxp(ptr %p)
14  %0 = extractvalue %0 %ldrexd, 1
15  %1 = extractvalue %0 %ldrexd, 0
16  %2 = zext i64 %0 to i128
17  %3 = zext i64 %1 to i128
18  %shl = shl nuw i128 %2, 64
19  %4 = or i128 %shl, %3
20  ret i128 %4
21}
22
23define dso_local i32 @f1(ptr %ptr, i128 %val) nounwind {
24; CHECK-LABEL: f1:
25; CHECK:       // %bb.0: // %entry
26; CHECK-NEXT:    stxp w8, x2, x3, [x0]
27; CHECK-NEXT:    mov w0, w8
28; CHECK-NEXT:    ret
29entry:
30  %tmp4 = trunc i128 %val to i64
31  %tmp6 = lshr i128 %val, 64
32  %tmp7 = trunc i128 %tmp6 to i64
33  %strexd = tail call i32 @llvm.aarch64.stxp(i64 %tmp4, i64 %tmp7, ptr %ptr)
34  ret i32 %strexd
35}
36
37declare %0 @llvm.aarch64.ldxp(ptr) nounwind
38declare i32 @llvm.aarch64.stxp(i64, i64, ptr) nounwind
39
40@var = dso_local global i64 0, align 8
41
42define dso_local void @test_load_i8(ptr %addr) {
43; CHECK-SD-LABEL: test_load_i8:
44; CHECK-SD:       // %bb.0:
45; CHECK-SD-NEXT:    ldxrb w8, [x0]
46; CHECK-SD-NEXT:    adrp x9, var
47; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
48; CHECK-SD-NEXT:    ret
49;
50; CHECK-GI-LABEL: test_load_i8:
51; CHECK-GI:       // %bb.0:
52; CHECK-GI-NEXT:    ldxrb w9, [x0]
53; CHECK-GI-NEXT:    adrp x8, var
54; CHECK-GI-NEXT:    and x9, x9, #0xff
55; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
56; CHECK-GI-NEXT:    ret
57
58  %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i8) %addr)
59  %shortval = trunc i64 %val to i8
60  %extval = zext i8 %shortval to i64
61  store i64 %extval, ptr @var, align 8
62  ret void
63}
64
65define dso_local void @test_load_i16(ptr %addr) {
66; CHECK-SD-LABEL: test_load_i16:
67; CHECK-SD:       // %bb.0:
68; CHECK-SD-NEXT:    ldxrh w8, [x0]
69; CHECK-SD-NEXT:    adrp x9, var
70; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
71; CHECK-SD-NEXT:    ret
72;
73; CHECK-GI-LABEL: test_load_i16:
74; CHECK-GI:       // %bb.0:
75; CHECK-GI-NEXT:    ldxrh w9, [x0]
76; CHECK-GI-NEXT:    adrp x8, var
77; CHECK-GI-NEXT:    and x9, x9, #0xffff
78; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
79; CHECK-GI-NEXT:    ret
80
81  %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i16) %addr)
82  %shortval = trunc i64 %val to i16
83  %extval = zext i16 %shortval to i64
84  store i64 %extval, ptr @var, align 8
85  ret void
86}
87
88define dso_local void @test_load_i32(ptr %addr) {
89; CHECK-SD-LABEL: test_load_i32:
90; CHECK-SD:       // %bb.0:
91; CHECK-SD-NEXT:    ldxr w8, [x0]
92; CHECK-SD-NEXT:    adrp x9, var
93; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
94; CHECK-SD-NEXT:    ret
95;
96; CHECK-GI-LABEL: test_load_i32:
97; CHECK-GI:       // %bb.0:
98; CHECK-GI-NEXT:    ldxr w9, [x0]
99; CHECK-GI-NEXT:    adrp x8, var
100; CHECK-GI-NEXT:    mov w9, w9
101; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
102; CHECK-GI-NEXT:    ret
103
104  %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %addr)
105  %shortval = trunc i64 %val to i32
106  %extval = zext i32 %shortval to i64
107  store i64 %extval, ptr @var, align 8
108  ret void
109}
110
111define dso_local void @test_load_i64(ptr %addr) {
112; CHECK-LABEL: test_load_i64:
113; CHECK:       // %bb.0:
114; CHECK-NEXT:    ldxr x8, [x0]
115; CHECK-NEXT:    adrp x9, var
116; CHECK-NEXT:    str x8, [x9, :lo12:var]
117; CHECK-NEXT:    ret
118
119  %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr)
120  store i64 %val, ptr @var, align 8
121  ret void
122}
123
124
125declare i64 @llvm.aarch64.ldxr.p0(ptr) nounwind
126
127define dso_local i32 @test_store_i8(i32, i8 %val, ptr %addr) {
128; CHECK-LABEL: test_store_i8:
129; CHECK:       // %bb.0:
130; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
131; CHECK-NEXT:    stxrb w0, w1, [x2]
132; CHECK-NEXT:    ret
133  %extval = zext i8 %val to i64
134  %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i8) %addr)
135  ret i32 %res
136}
137
138define dso_local i32 @test_store_i16(i32, i16 %val, ptr %addr) {
139; CHECK-LABEL: test_store_i16:
140; CHECK:       // %bb.0:
141; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
142; CHECK-NEXT:    stxrh w0, w1, [x2]
143; CHECK-NEXT:    ret
144  %extval = zext i16 %val to i64
145  %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i16) %addr)
146  ret i32 %res
147}
148
149define dso_local i32 @test_store_i32(i32, i32 %val, ptr %addr) {
150; CHECK-LABEL: test_store_i32:
151; CHECK:       // %bb.0:
152; CHECK-NEXT:    stxr w0, w1, [x2]
153; CHECK-NEXT:    ret
154  %extval = zext i32 %val to i64
155  %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i32) %addr)
156  ret i32 %res
157}
158
159define dso_local i32 @test_store_i64(i32, i64 %val, ptr %addr) {
160; CHECK-LABEL: test_store_i64:
161; CHECK:       // %bb.0:
162; CHECK-NEXT:    stxr w0, x1, [x2]
163; CHECK-NEXT:    ret
164  %res = call i32 @llvm.aarch64.stxr.p0(i64 %val, ptr elementtype(i64) %addr)
165  ret i32 %res
166}
167
168declare i32 @llvm.aarch64.stxr.p0(i64, ptr) nounwind
169
170define dso_local void @test_clear() {
171; CHECK-LABEL: test_clear:
172; CHECK:       // %bb.0:
173; CHECK-NEXT:    clrex
174; CHECK-NEXT:    ret
175  call void @llvm.aarch64.clrex()
176  ret void
177}
178
179declare void @llvm.aarch64.clrex() nounwind
180
181define dso_local i128 @test_load_acquire_i128(ptr %p) nounwind readonly {
182; CHECK-LABEL: test_load_acquire_i128:
183; CHECK:       // %bb.0: // %entry
184; CHECK-NEXT:    ldaxp x0, x1, [x0]
185; CHECK-NEXT:    ret
186entry:
187  %ldrexd = tail call %0 @llvm.aarch64.ldaxp(ptr %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 dso_local i32 @test_store_release_i128(ptr %ptr, i128 %val) nounwind {
198; CHECK-LABEL: test_store_release_i128:
199; CHECK:       // %bb.0: // %entry
200; CHECK-NEXT:    stlxp w8, x2, x3, [x0]
201; CHECK-NEXT:    mov w0, w8
202; CHECK-NEXT:    ret
203entry:
204  %tmp4 = trunc i128 %val to i64
205  %tmp6 = lshr i128 %val, 64
206  %tmp7 = trunc i128 %tmp6 to i64
207  %strexd = tail call i32 @llvm.aarch64.stlxp(i64 %tmp4, i64 %tmp7, ptr %ptr)
208  ret i32 %strexd
209}
210
211declare %0 @llvm.aarch64.ldaxp(ptr) nounwind
212declare i32 @llvm.aarch64.stlxp(i64, i64, ptr) nounwind
213
214define dso_local void @test_load_acquire_i8(ptr %addr) {
215; CHECK-SD-LABEL: test_load_acquire_i8:
216; CHECK-SD:       // %bb.0:
217; CHECK-SD-NEXT:    ldaxrb w8, [x0]
218; CHECK-SD-NEXT:    adrp x9, var
219; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
220; CHECK-SD-NEXT:    ret
221;
222; CHECK-GI-LABEL: test_load_acquire_i8:
223; CHECK-GI:       // %bb.0:
224; CHECK-GI-NEXT:    ldaxrb w9, [x0]
225; CHECK-GI-NEXT:    adrp x8, var
226; CHECK-GI-NEXT:    and x9, x9, #0xff
227; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
228; CHECK-GI-NEXT:    ret
229
230  %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i8) %addr)
231  %shortval = trunc i64 %val to i8
232  %extval = zext i8 %shortval to i64
233  store i64 %extval, ptr @var, align 8
234  ret void
235}
236
237define dso_local void @test_load_acquire_i16(ptr %addr) {
238; CHECK-SD-LABEL: test_load_acquire_i16:
239; CHECK-SD:       // %bb.0:
240; CHECK-SD-NEXT:    ldaxrh w8, [x0]
241; CHECK-SD-NEXT:    adrp x9, var
242; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
243; CHECK-SD-NEXT:    ret
244;
245; CHECK-GI-LABEL: test_load_acquire_i16:
246; CHECK-GI:       // %bb.0:
247; CHECK-GI-NEXT:    ldaxrh w9, [x0]
248; CHECK-GI-NEXT:    adrp x8, var
249; CHECK-GI-NEXT:    and x9, x9, #0xffff
250; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
251; CHECK-GI-NEXT:    ret
252
253  %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i16) %addr)
254  %shortval = trunc i64 %val to i16
255  %extval = zext i16 %shortval to i64
256  store i64 %extval, ptr @var, align 8
257  ret void
258}
259
260define dso_local void @test_load_acquire_i32(ptr %addr) {
261; CHECK-SD-LABEL: test_load_acquire_i32:
262; CHECK-SD:       // %bb.0:
263; CHECK-SD-NEXT:    ldaxr w8, [x0]
264; CHECK-SD-NEXT:    adrp x9, var
265; CHECK-SD-NEXT:    str x8, [x9, :lo12:var]
266; CHECK-SD-NEXT:    ret
267;
268; CHECK-GI-LABEL: test_load_acquire_i32:
269; CHECK-GI:       // %bb.0:
270; CHECK-GI-NEXT:    ldaxr w9, [x0]
271; CHECK-GI-NEXT:    adrp x8, var
272; CHECK-GI-NEXT:    mov w9, w9
273; CHECK-GI-NEXT:    str x9, [x8, :lo12:var]
274; CHECK-GI-NEXT:    ret
275
276  %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i32) %addr)
277  %shortval = trunc i64 %val to i32
278  %extval = zext i32 %shortval to i64
279  store i64 %extval, ptr @var, align 8
280  ret void
281}
282
283define dso_local void @test_load_acquire_i64(ptr %addr) {
284; CHECK-LABEL: test_load_acquire_i64:
285; CHECK:       // %bb.0:
286; CHECK-NEXT:    ldaxr x8, [x0]
287; CHECK-NEXT:    adrp x9, var
288; CHECK-NEXT:    str x8, [x9, :lo12:var]
289; CHECK-NEXT:    ret
290
291  %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr)
292  store i64 %val, ptr @var, align 8
293  ret void
294}
295
296
297declare i64 @llvm.aarch64.ldaxr.p0(ptr) nounwind
298
299define dso_local i32 @test_store_release_i8(i32, i8 %val, ptr %addr) {
300; CHECK-LABEL: test_store_release_i8:
301; CHECK:       // %bb.0:
302; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
303; CHECK-NEXT:    stlxrb w0, w1, [x2]
304; CHECK-NEXT:    ret
305  %extval = zext i8 %val to i64
306  %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i8) %addr)
307  ret i32 %res
308}
309
310define dso_local i32 @test_store_release_i16(i32, i16 %val, ptr %addr) {
311; CHECK-LABEL: test_store_release_i16:
312; CHECK:       // %bb.0:
313; CHECK-NEXT:    // kill: def $w1 killed $w1 def $x1
314; CHECK-NEXT:    stlxrh w0, w1, [x2]
315; CHECK-NEXT:    ret
316  %extval = zext i16 %val to i64
317  %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i16) %addr)
318  ret i32 %res
319}
320
321define dso_local i32 @test_store_release_i32(i32, i32 %val, ptr %addr) {
322; CHECK-LABEL: test_store_release_i32:
323; CHECK:       // %bb.0:
324; CHECK-NEXT:    stlxr w0, w1, [x2]
325; CHECK-NEXT:    ret
326  %extval = zext i32 %val to i64
327  %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i32) %addr)
328  ret i32 %res
329}
330
331define dso_local i32 @test_store_release_i64(i32, i64 %val, ptr %addr) {
332; CHECK-LABEL: test_store_release_i64:
333; CHECK:       // %bb.0:
334; CHECK-NEXT:    stlxr w0, x1, [x2]
335; CHECK-NEXT:    ret
336  %res = call i32 @llvm.aarch64.stlxr.p0(i64 %val, ptr elementtype(i64) %addr)
337  ret i32 %res
338}
339
340; The stxp result cannot be allocated to the same register as the inputs.
341define dso_local i32 @test_stxp_undef(ptr %p, i64 %x) nounwind {
342; CHECK-LABEL: test_stxp_undef:
343; CHECK:       // %bb.0:
344; CHECK-NEXT:    stxp w8, x9, x1, [x0]
345; CHECK-NEXT:    mov w0, w8
346; CHECK-NEXT:    ret
347  %res = call i32 @llvm.aarch64.stxp(i64 undef, i64 %x, ptr %p)
348  ret i32 %res
349}
350
351; Same as previous test, but using inline asm.
352define dso_local i32 @test_stxp_undef_inline_asm(ptr %p, i64 %x) nounwind {
353; CHECK-LABEL: test_stxp_undef_inline_asm:
354; CHECK:       // %bb.0:
355; CHECK-NEXT:    //APP
356; CHECK-NEXT:    stxp w8, x9, x1, [x0]
357; CHECK-NEXT:    //NO_APP
358; CHECK-NEXT:    mov w0, w8
359; CHECK-NEXT:    ret
360  %res = call i32 asm sideeffect "stxp ${0:w}, ${2}, ${3}, [${1}]", "=&r,r,r,r,~{memory}"(ptr %p, i64 undef, i64 %x)
361  ret i32 %res
362}
363
364declare i32 @llvm.aarch64.stlxr.p0(i64, ptr) nounwind
365