1; RUN: llc < %s -asm-verbose=false | 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; CHECK-LABEL: ldi64_a1:
9; CHECK-NEXT: .param i32{{$}}
10; CHECK-NEXT: .result i64{{$}}
11; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
12; CHECK-NEXT: return $pop[[NUM]]{{$}}
13define i64 @ldi64_a1(i64 *%p) {
14  %v = load i64, i64* %p, align 1
15  ret i64 %v
16}
17
18; CHECK-LABEL: ldi64_a2:
19; CHECK-NEXT: .param i32{{$}}
20; CHECK-NEXT: .result i64{{$}}
21; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
22; CHECK-NEXT: return $pop[[NUM]]{{$}}
23define i64 @ldi64_a2(i64 *%p) {
24  %v = load i64, i64* %p, align 2
25  ret i64 %v
26}
27
28; CHECK-LABEL: ldi64_a4:
29; CHECK-NEXT: .param i32{{$}}
30; CHECK-NEXT: .result i64{{$}}
31; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}}
32; CHECK-NEXT: return $pop[[NUM]]{{$}}
33define i64 @ldi64_a4(i64 *%p) {
34  %v = load i64, i64* %p, align 4
35  ret i64 %v
36}
37
38; 8 is the default alignment for i32 so no attribute is needed.
39
40; CHECK-LABEL: ldi64_a8:
41; CHECK-NEXT: .param i32{{$}}
42; CHECK-NEXT: .result 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: .param i32{{$}}
54; CHECK-NEXT: .result i64{{$}}
55; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
56; CHECK-NEXT: return $pop[[NUM]]{{$}}
57define i64 @ldi64(i64 *%p) {
58  %v = load i64, i64* %p
59  ret i64 %v
60}
61
62; CHECK-LABEL: ldi64_a16:
63; CHECK-NEXT: .param i32{{$}}
64; CHECK-NEXT: .result i64{{$}}
65; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=4{{$}}
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; Extending loads.
73
74; CHECK-LABEL: ldi8_a1:
75; CHECK-NEXT: .param i32{{$}}
76; CHECK-NEXT: .result i64{{$}}
77; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
78; CHECK-NEXT: return $pop[[NUM]]{{$}}
79define i64 @ldi8_a1(i8 *%p) {
80  %v = load i8, i8* %p, align 1
81  %w = zext i8 %v to i64
82  ret i64 %w
83}
84
85; CHECK-LABEL: ldi8_a2:
86; CHECK-NEXT: .param i32{{$}}
87; CHECK-NEXT: .result i64{{$}}
88; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
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: .param i32{{$}}
98; CHECK-NEXT: .result i64{{$}}
99; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
100; CHECK-NEXT: return $pop[[NUM]]{{$}}
101define i64 @ldi16_a1(i16 *%p) {
102  %v = load i16, i16* %p, align 1
103  %w = zext i16 %v to i64
104  ret i64 %w
105}
106
107; CHECK-LABEL: ldi16_a2:
108; CHECK-NEXT: .param i32{{$}}
109; CHECK-NEXT: .result i64{{$}}
110; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
111; CHECK-NEXT: return $pop[[NUM]]{{$}}
112define i64 @ldi16_a2(i16 *%p) {
113  %v = load i16, i16* %p, align 2
114  %w = zext i16 %v to i64
115  ret i64 %w
116}
117
118; CHECK-LABEL: ldi16_a4:
119; CHECK-NEXT: .param i32{{$}}
120; CHECK-NEXT: .result i64{{$}}
121; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}}
122; CHECK-NEXT: return $pop[[NUM]]{{$}}
123define i64 @ldi16_a4(i16 *%p) {
124  %v = load i16, i16* %p, align 4
125  %w = zext i16 %v to i64
126  ret i64 %w
127}
128
129; CHECK-LABEL: ldi32_a1:
130; CHECK-NEXT: .param i32{{$}}
131; CHECK-NEXT: .result i64{{$}}
132; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
133; CHECK-NEXT: return $pop[[NUM]]{{$}}
134define i64 @ldi32_a1(i32 *%p) {
135  %v = load i32, i32* %p, align 1
136  %w = zext i32 %v to i64
137  ret i64 %w
138}
139
140; CHECK-LABEL: ldi32_a2:
141; CHECK-NEXT: .param i32{{$}}
142; CHECK-NEXT: .result i64{{$}}
143; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
144; CHECK-NEXT: return $pop[[NUM]]{{$}}
145define i64 @ldi32_a2(i32 *%p) {
146  %v = load i32, i32* %p, align 2
147  %w = zext i32 %v to i64
148  ret i64 %w
149}
150
151; CHECK-LABEL: ldi32_a4:
152; CHECK-NEXT: .param i32{{$}}
153; CHECK-NEXT: .result i64{{$}}
154; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
155; CHECK-NEXT: return $pop[[NUM]]{{$}}
156define i64 @ldi32_a4(i32 *%p) {
157  %v = load i32, i32* %p, align 4
158  %w = zext i32 %v to i64
159  ret i64 %w
160}
161
162; CHECK-LABEL: ldi32_a8:
163; CHECK-NEXT: .param i32{{$}}
164; CHECK-NEXT: .result i64{{$}}
165; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=3{{$}}
166; CHECK-NEXT: return $pop[[NUM]]{{$}}
167define i64 @ldi32_a8(i32 *%p) {
168  %v = load i32, i32* %p, align 8
169  %w = zext i32 %v to i64
170  ret i64 %w
171}
172
173; Stores.
174
175; CHECK-LABEL: sti64_a1:
176; CHECK-NEXT: .param i32, i64{{$}}
177; CHECK-NEXT: i64.store $discard=, 0($0):p2align=0, $1{{$}}
178; CHECK-NEXT: return{{$}}
179define void @sti64_a1(i64 *%p, i64 %v) {
180  store i64 %v, i64* %p, align 1
181  ret void
182}
183
184; CHECK-LABEL: sti64_a2:
185; CHECK-NEXT: .param i32, i64{{$}}
186; CHECK-NEXT: i64.store $discard=, 0($0):p2align=1, $1{{$}}
187; CHECK-NEXT: return{{$}}
188define void @sti64_a2(i64 *%p, i64 %v) {
189  store i64 %v, i64* %p, align 2
190  ret void
191}
192
193; CHECK-LABEL: sti64_a4:
194; CHECK-NEXT: .param i32, i64{{$}}
195; CHECK-NEXT: i64.store $discard=, 0($0):p2align=2, $1{{$}}
196; CHECK-NEXT: return{{$}}
197define void @sti64_a4(i64 *%p, i64 %v) {
198  store i64 %v, i64* %p, align 4
199  ret void
200}
201
202; 8 is the default alignment for i32 so no attribute is needed.
203
204; CHECK-LABEL: sti64_a8:
205; CHECK-NEXT: .param i32, i64{{$}}
206; CHECK-NEXT: i64.store $discard=, 0($0), $1{{$}}
207; CHECK-NEXT: return{{$}}
208define void @sti64_a8(i64 *%p, i64 %v) {
209  store i64 %v, i64* %p, align 8
210  ret void
211}
212
213; The default alignment in LLVM is the same as the defualt alignment in wasm.
214
215; CHECK-LABEL: sti64:
216; CHECK-NEXT: .param i32, i64{{$}}
217; CHECK-NEXT: i64.store $discard=, 0($0), $1{{$}}
218; CHECK-NEXT: return{{$}}
219define void @sti64(i64 *%p, i64 %v) {
220  store i64 %v, i64* %p
221  ret void
222}
223
224; CHECK-LABEL: sti64_a16:
225; CHECK-NEXT: .param i32, i64{{$}}
226; CHECK-NEXT: i64.store $discard=, 0($0):p2align=4, $1{{$}}
227; CHECK-NEXT: return{{$}}
228define void @sti64_a16(i64 *%p, i64 %v) {
229  store i64 %v, i64* %p, align 16
230  ret void
231}
232
233; Truncating stores.
234
235; CHECK-LABEL: sti8_a1:
236; CHECK-NEXT: .param i32, i64{{$}}
237; CHECK-NEXT: i64.store8 $discard=, 0($0), $1{{$}}
238; CHECK-NEXT: return{{$}}
239define void @sti8_a1(i8 *%p, i64 %w) {
240  %v = trunc i64 %w to i8
241  store i8 %v, i8* %p, align 1
242  ret void
243}
244
245; CHECK-LABEL: sti8_a2:
246; CHECK-NEXT: .param i32, i64{{$}}
247; CHECK-NEXT: i64.store8 $discard=, 0($0):p2align=1, $1{{$}}
248; CHECK-NEXT: return{{$}}
249define void @sti8_a2(i8 *%p, i64 %w) {
250  %v = trunc i64 %w to i8
251  store i8 %v, i8* %p, align 2
252  ret void
253}
254
255; CHECK-LABEL: sti16_a1:
256; CHECK-NEXT: .param i32, i64{{$}}
257; CHECK-NEXT: i64.store16 $discard=, 0($0):p2align=0, $1{{$}}
258; CHECK-NEXT: return{{$}}
259define void @sti16_a1(i16 *%p, i64 %w) {
260  %v = trunc i64 %w to i16
261  store i16 %v, i16* %p, align 1
262  ret void
263}
264
265; CHECK-LABEL: sti16_a2:
266; CHECK-NEXT: .param i32, i64{{$}}
267; CHECK-NEXT: i64.store16 $discard=, 0($0), $1{{$}}
268; CHECK-NEXT: return{{$}}
269define void @sti16_a2(i16 *%p, i64 %w) {
270  %v = trunc i64 %w to i16
271  store i16 %v, i16* %p, align 2
272  ret void
273}
274
275; CHECK-LABEL: sti16_a4:
276; CHECK-NEXT: .param i32, i64{{$}}
277; CHECK-NEXT: i64.store16 $discard=, 0($0):p2align=2, $1{{$}}
278; CHECK-NEXT: return{{$}}
279define void @sti16_a4(i16 *%p, i64 %w) {
280  %v = trunc i64 %w to i16
281  store i16 %v, i16* %p, align 4
282  ret void
283}
284
285; CHECK-LABEL: sti32_a1:
286; CHECK-NEXT: .param i32, i64{{$}}
287; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=0, $1{{$}}
288; CHECK-NEXT: return{{$}}
289define void @sti32_a1(i32 *%p, i64 %w) {
290  %v = trunc i64 %w to i32
291  store i32 %v, i32* %p, align 1
292  ret void
293}
294
295; CHECK-LABEL: sti32_a2:
296; CHECK-NEXT: .param i32, i64{{$}}
297; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=1, $1{{$}}
298; CHECK-NEXT: return{{$}}
299define void @sti32_a2(i32 *%p, i64 %w) {
300  %v = trunc i64 %w to i32
301  store i32 %v, i32* %p, align 2
302  ret void
303}
304
305; CHECK-LABEL: sti32_a4:
306; CHECK-NEXT: .param i32, i64{{$}}
307; CHECK-NEXT: i64.store32 $discard=, 0($0), $1{{$}}
308; CHECK-NEXT: return{{$}}
309define void @sti32_a4(i32 *%p, i64 %w) {
310  %v = trunc i64 %w to i32
311  store i32 %v, i32* %p, align 4
312  ret void
313}
314
315; CHECK-LABEL: sti32_a8:
316; CHECK-NEXT: .param i32, i64{{$}}
317; CHECK-NEXT: i64.store32 $discard=, 0($0):p2align=3, $1{{$}}
318; CHECK-NEXT: return{{$}}
319define void @sti32_a8(i32 *%p, i64 %w) {
320  %v = trunc i64 %w to i32
321  store i32 %v, i32* %p, align 8
322  ret void
323}
324