1; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
2
3; Test loads and stores with custom alignment values.
4
5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6target triple = "wasm32-unknown-unknown"
7
8;===----------------------------------------------------------------------------
9; Loads
10;===----------------------------------------------------------------------------
11
12; CHECK-LABEL: ldi64_a1:
13; CHECK-NEXT: .functype ldi64_a1 (i32) -> (i64){{$}}
14; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
15; CHECK-NEXT: return $pop[[NUM]]{{$}}
16define i64 @ldi64_a1(i64 *%p) {
17  %v = load i64, i64* %p, align 1
18  ret i64 %v
19}
20
21; CHECK-LABEL: ldi64_a2:
22; CHECK-NEXT: .functype ldi64_a2 (i32) -> (i64){{$}}
23; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
24; CHECK-NEXT: return $pop[[NUM]]{{$}}
25define i64 @ldi64_a2(i64 *%p) {
26  %v = load i64, i64* %p, align 2
27  ret i64 %v
28}
29
30; CHECK-LABEL: ldi64_a4:
31; CHECK-NEXT: .functype ldi64_a4 (i32) -> (i64){{$}}
32; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}}
33; CHECK-NEXT: return $pop[[NUM]]{{$}}
34define i64 @ldi64_a4(i64 *%p) {
35  %v = load i64, i64* %p, align 4
36  ret i64 %v
37}
38
39; 8 is the default alignment for i64 so no attribute is needed.
40
41; CHECK-LABEL: ldi64_a8:
42; CHECK-NEXT: .functype ldi64_a8 (i32) -> (i64){{$}}
43; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
44; CHECK-NEXT: return $pop[[NUM]]{{$}}
45define i64 @ldi64_a8(i64 *%p) {
46  %v = load i64, i64* %p, align 8
47  ret i64 %v
48}
49
50; The default alignment in LLVM is the same as the defualt alignment in wasm.
51
52; CHECK-LABEL: ldi64:
53; CHECK-NEXT: .functype ldi64 (i32) -> (i64){{$}}
54; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
55; CHECK-NEXT: return $pop[[NUM]]{{$}}
56define i64 @ldi64(i64 *%p) {
57  %v = load i64, i64* %p
58  ret i64 %v
59}
60
61; 16 is greater than the default alignment so it is ignored.
62
63; CHECK-LABEL: ldi64_a16:
64; CHECK-NEXT: .functype ldi64_a16 (i32) -> (i64){{$}}
65; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
66; CHECK-NEXT: return $pop[[NUM]]{{$}}
67define i64 @ldi64_a16(i64 *%p) {
68  %v = load i64, i64* %p, align 16
69  ret i64 %v
70}
71
72;===----------------------------------------------------------------------------
73; Extending loads
74;===----------------------------------------------------------------------------
75
76; CHECK-LABEL: ldi8_a1:
77; CHECK-NEXT: .functype ldi8_a1 (i32) -> (i64){{$}}
78; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
79; CHECK-NEXT: return $pop[[NUM]]{{$}}
80define i64 @ldi8_a1(i8 *%p) {
81  %v = load i8, i8* %p, align 1
82  %w = zext i8 %v to i64
83  ret i64 %w
84}
85
86; CHECK-LABEL: ldi8_a2:
87; CHECK-NEXT: .functype ldi8_a2 (i32) -> (i64){{$}}
88; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
89; CHECK-NEXT: return $pop[[NUM]]{{$}}
90define i64 @ldi8_a2(i8 *%p) {
91  %v = load i8, i8* %p, align 2
92  %w = zext i8 %v to i64
93  ret i64 %w
94}
95
96; CHECK-LABEL: ldi16_a1:
97; CHECK-NEXT: .functype ldi16_a1 (i32) -> (i64){{$}}
98; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
99; CHECK-NEXT: return $pop[[NUM]]{{$}}
100define i64 @ldi16_a1(i16 *%p) {
101  %v = load i16, i16* %p, align 1
102  %w = zext i16 %v to i64
103  ret i64 %w
104}
105
106; CHECK-LABEL: ldi16_a2:
107; CHECK-NEXT: .functype ldi16_a2 (i32) -> (i64){{$}}
108; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
109; CHECK-NEXT: return $pop[[NUM]]{{$}}
110define i64 @ldi16_a2(i16 *%p) {
111  %v = load i16, i16* %p, align 2
112  %w = zext i16 %v to i64
113  ret i64 %w
114}
115
116; CHECK-LABEL: ldi16_a4:
117; CHECK-NEXT: .functype ldi16_a4 (i32) -> (i64){{$}}
118; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
119; CHECK-NEXT: return $pop[[NUM]]{{$}}
120define i64 @ldi16_a4(i16 *%p) {
121  %v = load i16, i16* %p, align 4
122  %w = zext i16 %v to i64
123  ret i64 %w
124}
125
126; CHECK-LABEL: ldi32_a1:
127; CHECK-NEXT: .functype ldi32_a1 (i32) -> (i64){{$}}
128; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
129; CHECK-NEXT: return $pop[[NUM]]{{$}}
130define i64 @ldi32_a1(i32 *%p) {
131  %v = load i32, i32* %p, align 1
132  %w = zext i32 %v to i64
133  ret i64 %w
134}
135
136; CHECK-LABEL: ldi32_a2:
137; CHECK-NEXT: .functype ldi32_a2 (i32) -> (i64){{$}}
138; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
139; CHECK-NEXT: return $pop[[NUM]]{{$}}
140define i64 @ldi32_a2(i32 *%p) {
141  %v = load i32, i32* %p, align 2
142  %w = zext i32 %v to i64
143  ret i64 %w
144}
145
146; CHECK-LABEL: ldi32_a4:
147; CHECK-NEXT: .functype ldi32_a4 (i32) -> (i64){{$}}
148; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
149; CHECK-NEXT: return $pop[[NUM]]{{$}}
150define i64 @ldi32_a4(i32 *%p) {
151  %v = load i32, i32* %p, align 4
152  %w = zext i32 %v to i64
153  ret i64 %w
154}
155
156; CHECK-LABEL: ldi32_a8:
157; CHECK-NEXT: .functype ldi32_a8 (i32) -> (i64){{$}}
158; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
159; CHECK-NEXT: return $pop[[NUM]]{{$}}
160define i64 @ldi32_a8(i32 *%p) {
161  %v = load i32, i32* %p, align 8
162  %w = zext i32 %v to i64
163  ret i64 %w
164}
165
166;===----------------------------------------------------------------------------
167; Stores
168;===----------------------------------------------------------------------------
169
170; CHECK-LABEL: sti64_a1:
171; CHECK-NEXT: .functype sti64_a1 (i32, i64) -> (){{$}}
172; CHECK-NEXT: i64.store 0($0):p2align=0, $1{{$}}
173; CHECK-NEXT: return{{$}}
174define void @sti64_a1(i64 *%p, i64 %v) {
175  store i64 %v, i64* %p, align 1
176  ret void
177}
178
179; CHECK-LABEL: sti64_a2:
180; CHECK-NEXT: .functype sti64_a2 (i32, i64) -> (){{$}}
181; CHECK-NEXT: i64.store 0($0):p2align=1, $1{{$}}
182; CHECK-NEXT: return{{$}}
183define void @sti64_a2(i64 *%p, i64 %v) {
184  store i64 %v, i64* %p, align 2
185  ret void
186}
187
188; CHECK-LABEL: sti64_a4:
189; CHECK-NEXT: .functype sti64_a4 (i32, i64) -> (){{$}}
190; CHECK-NEXT: i64.store 0($0):p2align=2, $1{{$}}
191; CHECK-NEXT: return{{$}}
192define void @sti64_a4(i64 *%p, i64 %v) {
193  store i64 %v, i64* %p, align 4
194  ret void
195}
196
197; 8 is the default alignment for i32 so no attribute is needed.
198
199; CHECK-LABEL: sti64_a8:
200; CHECK-NEXT: .functype sti64_a8 (i32, i64) -> (){{$}}
201; CHECK-NEXT: i64.store 0($0), $1{{$}}
202; CHECK-NEXT: return{{$}}
203define void @sti64_a8(i64 *%p, i64 %v) {
204  store i64 %v, i64* %p, align 8
205  ret void
206}
207
208; The default alignment in LLVM is the same as the defualt alignment in wasm.
209
210; CHECK-LABEL: sti64:
211; CHECK-NEXT: .functype sti64 (i32, i64) -> (){{$}}
212; CHECK-NEXT: i64.store 0($0), $1{{$}}
213; CHECK-NEXT: return{{$}}
214define void @sti64(i64 *%p, i64 %v) {
215  store i64 %v, i64* %p
216  ret void
217}
218
219; CHECK-LABEL: sti64_a16:
220; CHECK-NEXT: .functype sti64_a16 (i32, i64) -> (){{$}}
221; CHECK-NEXT: i64.store 0($0), $1{{$}}
222; CHECK-NEXT: return{{$}}
223define void @sti64_a16(i64 *%p, i64 %v) {
224  store i64 %v, i64* %p, align 16
225  ret void
226}
227
228;===----------------------------------------------------------------------------
229; Truncating stores
230;===----------------------------------------------------------------------------
231
232; CHECK-LABEL: sti8_a1:
233; CHECK-NEXT: .functype sti8_a1 (i32, i64) -> (){{$}}
234; CHECK-NEXT: i64.store8 0($0), $1{{$}}
235; CHECK-NEXT: return{{$}}
236define void @sti8_a1(i8 *%p, i64 %w) {
237  %v = trunc i64 %w to i8
238  store i8 %v, i8* %p, align 1
239  ret void
240}
241
242; CHECK-LABEL: sti8_a2:
243; CHECK-NEXT: .functype sti8_a2 (i32, i64) -> (){{$}}
244; CHECK-NEXT: i64.store8 0($0), $1{{$}}
245; CHECK-NEXT: return{{$}}
246define void @sti8_a2(i8 *%p, i64 %w) {
247  %v = trunc i64 %w to i8
248  store i8 %v, i8* %p, align 2
249  ret void
250}
251
252; CHECK-LABEL: sti16_a1:
253; CHECK-NEXT: .functype sti16_a1 (i32, i64) -> (){{$}}
254; CHECK-NEXT: i64.store16 0($0):p2align=0, $1{{$}}
255; CHECK-NEXT: return{{$}}
256define void @sti16_a1(i16 *%p, i64 %w) {
257  %v = trunc i64 %w to i16
258  store i16 %v, i16* %p, align 1
259  ret void
260}
261
262; CHECK-LABEL: sti16_a2:
263; CHECK-NEXT: .functype sti16_a2 (i32, i64) -> (){{$}}
264; CHECK-NEXT: i64.store16 0($0), $1{{$}}
265; CHECK-NEXT: return{{$}}
266define void @sti16_a2(i16 *%p, i64 %w) {
267  %v = trunc i64 %w to i16
268  store i16 %v, i16* %p, align 2
269  ret void
270}
271
272; CHECK-LABEL: sti16_a4:
273; CHECK-NEXT: .functype sti16_a4 (i32, i64) -> (){{$}}
274; CHECK-NEXT: i64.store16 0($0), $1{{$}}
275; CHECK-NEXT: return{{$}}
276define void @sti16_a4(i16 *%p, i64 %w) {
277  %v = trunc i64 %w to i16
278  store i16 %v, i16* %p, align 4
279  ret void
280}
281
282; CHECK-LABEL: sti32_a1:
283; CHECK-NEXT: .functype sti32_a1 (i32, i64) -> (){{$}}
284; CHECK-NEXT: i64.store32 0($0):p2align=0, $1{{$}}
285; CHECK-NEXT: return{{$}}
286define void @sti32_a1(i32 *%p, i64 %w) {
287  %v = trunc i64 %w to i32
288  store i32 %v, i32* %p, align 1
289  ret void
290}
291
292; CHECK-LABEL: sti32_a2:
293; CHECK-NEXT: .functype sti32_a2 (i32, i64) -> (){{$}}
294; CHECK-NEXT: i64.store32 0($0):p2align=1, $1{{$}}
295; CHECK-NEXT: return{{$}}
296define void @sti32_a2(i32 *%p, i64 %w) {
297  %v = trunc i64 %w to i32
298  store i32 %v, i32* %p, align 2
299  ret void
300}
301
302; CHECK-LABEL: sti32_a4:
303; CHECK-NEXT: .functype sti32_a4 (i32, i64) -> (){{$}}
304; CHECK-NEXT: i64.store32 0($0), $1{{$}}
305; CHECK-NEXT: return{{$}}
306define void @sti32_a4(i32 *%p, i64 %w) {
307  %v = trunc i64 %w to i32
308  store i32 %v, i32* %p, align 4
309  ret void
310}
311
312; CHECK-LABEL: sti32_a8:
313; CHECK-NEXT: .functype sti32_a8 (i32, i64) -> (){{$}}
314; CHECK-NEXT: i64.store32 0($0), $1{{$}}
315; CHECK-NEXT: return{{$}}
316define void @sti32_a8(i32 *%p, i64 %w) {
317  %v = trunc i64 %w to i32
318  store i32 %v, i32* %p, align 8
319  ret void
320}
321
322;===----------------------------------------------------------------------------
323; Atomic loads
324;===----------------------------------------------------------------------------
325
326; Wasm atomics have the alignment field, but it must always have the type's
327; natural alignment.
328
329; CHECK-LABEL: ldi64_atomic_a8:
330; CHECK-NEXT: .functype ldi64_atomic_a8 (i32) -> (i64){{$}}
331; CHECK-NEXT: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
332; CHECK-NEXT: return $pop[[NUM]]{{$}}
333define i64 @ldi64_atomic_a8(i64 *%p) {
334  %v = load atomic i64, i64* %p seq_cst, align 8
335  ret i64 %v
336}
337
338; 16 is greater than the default alignment so it is ignored.
339
340; CHECK-LABEL: ldi64_atomic_a16:
341; CHECK-NEXT: .functype ldi64_atomic_a16 (i32) -> (i64){{$}}
342; CHECK-NEXT: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
343; CHECK-NEXT: return $pop[[NUM]]{{$}}
344define i64 @ldi64_atomic_a16(i64 *%p) {
345  %v = load atomic i64, i64* %p seq_cst, align 16
346  ret i64 %v
347}
348
349;===----------------------------------------------------------------------------
350; Atomic stores
351;===----------------------------------------------------------------------------
352
353; CHECK-LABEL: sti64_atomic_a4:
354; CHECK-NEXT: .functype sti64_atomic_a4 (i32, i64) -> (){{$}}
355; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
356; CHECK-NEXT: return{{$}}
357define void @sti64_atomic_a4(i64 *%p, i64 %v) {
358 store atomic i64 %v, i64* %p seq_cst, align 8
359 ret void
360}
361
362; 16 is greater than the default alignment so it is ignored.
363
364; CHECK-LABEL: sti64_atomic_a8:
365; CHECK-NEXT: .functype sti64_atomic_a8 (i32, i64) -> (){{$}}
366; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
367; CHECK-NEXT: return{{$}}
368define void @sti64_atomic_a8(i64 *%p, i64 %v) {
369 store atomic i64 %v, i64* %p seq_cst, align 16
370 ret void
371}
372