1 ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
3 ; Test loads and stores with custom alignment values.
5 target triple = "wasm32-unknown-unknown"
7 ;===----------------------------------------------------------------------------
9 ;===----------------------------------------------------------------------------
11 ; CHECK-LABEL: ldi64_a1:
12 ; CHECK-NEXT: .functype ldi64_a1 (i32) -> (i64){{$}}
13 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
14 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
15 define i64 @ldi64_a1(ptr %p) {
16 %v = load i64, ptr %p, align 1
20 ; CHECK-LABEL: ldi64_a2:
21 ; CHECK-NEXT: .functype ldi64_a2 (i32) -> (i64){{$}}
22 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
23 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
24 define i64 @ldi64_a2(ptr %p) {
25 %v = load i64, ptr %p, align 2
29 ; CHECK-LABEL: ldi64_a4:
30 ; CHECK-NEXT: .functype ldi64_a4 (i32) -> (i64){{$}}
31 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0):p2align=2{{$}}
32 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
33 define i64 @ldi64_a4(ptr %p) {
34 %v = load i64, ptr %p, align 4
38 ; 8 is the default alignment for i64 so no attribute is needed.
40 ; CHECK-LABEL: ldi64_a8:
41 ; CHECK-NEXT: .functype ldi64_a8 (i32) -> (i64){{$}}
42 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
43 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
44 define i64 @ldi64_a8(ptr %p) {
45 %v = load i64, ptr %p, align 8
49 ; The default alignment in LLVM is the same as the default alignment in wasm.
52 ; CHECK-NEXT: .functype ldi64 (i32) -> (i64){{$}}
53 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
54 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
55 define i64 @ldi64(ptr %p) {
60 ; 16 is greater than the default alignment so it is ignored.
62 ; CHECK-LABEL: ldi64_a16:
63 ; CHECK-NEXT: .functype ldi64_a16 (i32) -> (i64){{$}}
64 ; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
65 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
66 define i64 @ldi64_a16(ptr %p) {
67 %v = load i64, ptr %p, align 16
71 ;===----------------------------------------------------------------------------
73 ;===----------------------------------------------------------------------------
75 ; CHECK-LABEL: ldi8_a1:
76 ; CHECK-NEXT: .functype ldi8_a1 (i32) -> (i64){{$}}
77 ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
78 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
79 define i64 @ldi8_a1(ptr %p) {
80 %v = load i8, ptr %p, align 1
81 %w = zext i8 %v to i64
85 ; CHECK-LABEL: ldi8_a2:
86 ; CHECK-NEXT: .functype ldi8_a2 (i32) -> (i64){{$}}
87 ; CHECK-NEXT: i64.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
88 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
89 define i64 @ldi8_a2(ptr %p) {
90 %v = load i8, ptr %p, align 2
91 %w = zext i8 %v to i64
95 ; CHECK-LABEL: ldi16_a1:
96 ; CHECK-NEXT: .functype ldi16_a1 (i32) -> (i64){{$}}
97 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
98 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
99 define i64 @ldi16_a1(ptr %p) {
100 %v = load i16, ptr %p, align 1
101 %w = zext i16 %v to i64
105 ; CHECK-LABEL: ldi16_a2:
106 ; CHECK-NEXT: .functype ldi16_a2 (i32) -> (i64){{$}}
107 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
108 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
109 define i64 @ldi16_a2(ptr %p) {
110 %v = load i16, ptr %p, align 2
111 %w = zext i16 %v to i64
115 ; CHECK-LABEL: ldi16_a4:
116 ; CHECK-NEXT: .functype ldi16_a4 (i32) -> (i64){{$}}
117 ; CHECK-NEXT: i64.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
118 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
119 define i64 @ldi16_a4(ptr %p) {
120 %v = load i16, ptr %p, align 4
121 %w = zext i16 %v to i64
125 ; CHECK-LABEL: ldi32_a1:
126 ; CHECK-NEXT: .functype ldi32_a1 (i32) -> (i64){{$}}
127 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
128 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
129 define i64 @ldi32_a1(ptr %p) {
130 %v = load i32, ptr %p, align 1
131 %w = zext i32 %v to i64
135 ; CHECK-LABEL: ldi32_a2:
136 ; CHECK-NEXT: .functype ldi32_a2 (i32) -> (i64){{$}}
137 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
138 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
139 define i64 @ldi32_a2(ptr %p) {
140 %v = load i32, ptr %p, align 2
141 %w = zext i32 %v to i64
145 ; CHECK-LABEL: ldi32_a4:
146 ; CHECK-NEXT: .functype ldi32_a4 (i32) -> (i64){{$}}
147 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
148 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
149 define i64 @ldi32_a4(ptr %p) {
150 %v = load i32, ptr %p, align 4
151 %w = zext i32 %v to i64
155 ; CHECK-LABEL: ldi32_a8:
156 ; CHECK-NEXT: .functype ldi32_a8 (i32) -> (i64){{$}}
157 ; CHECK-NEXT: i64.load32_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
158 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
159 define i64 @ldi32_a8(ptr %p) {
160 %v = load i32, ptr %p, align 8
161 %w = zext i32 %v to i64
165 ;===----------------------------------------------------------------------------
167 ;===----------------------------------------------------------------------------
169 ; CHECK-LABEL: sti64_a1:
170 ; CHECK-NEXT: .functype sti64_a1 (i32, i64) -> (){{$}}
171 ; CHECK-NEXT: i64.store 0($0):p2align=0, $1{{$}}
172 ; CHECK-NEXT: return{{$}}
173 define void @sti64_a1(ptr %p, i64 %v) {
174 store i64 %v, ptr %p, align 1
178 ; CHECK-LABEL: sti64_a2:
179 ; CHECK-NEXT: .functype sti64_a2 (i32, i64) -> (){{$}}
180 ; CHECK-NEXT: i64.store 0($0):p2align=1, $1{{$}}
181 ; CHECK-NEXT: return{{$}}
182 define void @sti64_a2(ptr %p, i64 %v) {
183 store i64 %v, ptr %p, align 2
187 ; CHECK-LABEL: sti64_a4:
188 ; CHECK-NEXT: .functype sti64_a4 (i32, i64) -> (){{$}}
189 ; CHECK-NEXT: i64.store 0($0):p2align=2, $1{{$}}
190 ; CHECK-NEXT: return{{$}}
191 define void @sti64_a4(ptr %p, i64 %v) {
192 store i64 %v, ptr %p, align 4
196 ; 8 is the default alignment for i32 so no attribute is needed.
198 ; CHECK-LABEL: sti64_a8:
199 ; CHECK-NEXT: .functype sti64_a8 (i32, i64) -> (){{$}}
200 ; CHECK-NEXT: i64.store 0($0), $1{{$}}
201 ; CHECK-NEXT: return{{$}}
202 define void @sti64_a8(ptr %p, i64 %v) {
203 store i64 %v, ptr %p, align 8
207 ; The default alignment in LLVM is the same as the default alignment in wasm.
209 ; CHECK-LABEL: sti64:
210 ; CHECK-NEXT: .functype sti64 (i32, i64) -> (){{$}}
211 ; CHECK-NEXT: i64.store 0($0), $1{{$}}
212 ; CHECK-NEXT: return{{$}}
213 define void @sti64(ptr %p, i64 %v) {
218 ; CHECK-LABEL: sti64_a16:
219 ; CHECK-NEXT: .functype sti64_a16 (i32, i64) -> (){{$}}
220 ; CHECK-NEXT: i64.store 0($0), $1{{$}}
221 ; CHECK-NEXT: return{{$}}
222 define void @sti64_a16(ptr %p, i64 %v) {
223 store i64 %v, ptr %p, align 16
227 ;===----------------------------------------------------------------------------
229 ;===----------------------------------------------------------------------------
231 ; CHECK-LABEL: sti8_a1:
232 ; CHECK-NEXT: .functype sti8_a1 (i32, i64) -> (){{$}}
233 ; CHECK-NEXT: i64.store8 0($0), $1{{$}}
234 ; CHECK-NEXT: return{{$}}
235 define void @sti8_a1(ptr %p, i64 %w) {
236 %v = trunc i64 %w to i8
237 store i8 %v, ptr %p, align 1
241 ; CHECK-LABEL: sti8_a2:
242 ; CHECK-NEXT: .functype sti8_a2 (i32, i64) -> (){{$}}
243 ; CHECK-NEXT: i64.store8 0($0), $1{{$}}
244 ; CHECK-NEXT: return{{$}}
245 define void @sti8_a2(ptr %p, i64 %w) {
246 %v = trunc i64 %w to i8
247 store i8 %v, ptr %p, align 2
251 ; CHECK-LABEL: sti16_a1:
252 ; CHECK-NEXT: .functype sti16_a1 (i32, i64) -> (){{$}}
253 ; CHECK-NEXT: i64.store16 0($0):p2align=0, $1{{$}}
254 ; CHECK-NEXT: return{{$}}
255 define void @sti16_a1(ptr %p, i64 %w) {
256 %v = trunc i64 %w to i16
257 store i16 %v, ptr %p, align 1
261 ; CHECK-LABEL: sti16_a2:
262 ; CHECK-NEXT: .functype sti16_a2 (i32, i64) -> (){{$}}
263 ; CHECK-NEXT: i64.store16 0($0), $1{{$}}
264 ; CHECK-NEXT: return{{$}}
265 define void @sti16_a2(ptr %p, i64 %w) {
266 %v = trunc i64 %w to i16
267 store i16 %v, ptr %p, align 2
271 ; CHECK-LABEL: sti16_a4:
272 ; CHECK-NEXT: .functype sti16_a4 (i32, i64) -> (){{$}}
273 ; CHECK-NEXT: i64.store16 0($0), $1{{$}}
274 ; CHECK-NEXT: return{{$}}
275 define void @sti16_a4(ptr %p, i64 %w) {
276 %v = trunc i64 %w to i16
277 store i16 %v, ptr %p, align 4
281 ; CHECK-LABEL: sti32_a1:
282 ; CHECK-NEXT: .functype sti32_a1 (i32, i64) -> (){{$}}
283 ; CHECK-NEXT: i64.store32 0($0):p2align=0, $1{{$}}
284 ; CHECK-NEXT: return{{$}}
285 define void @sti32_a1(ptr %p, i64 %w) {
286 %v = trunc i64 %w to i32
287 store i32 %v, ptr %p, align 1
291 ; CHECK-LABEL: sti32_a2:
292 ; CHECK-NEXT: .functype sti32_a2 (i32, i64) -> (){{$}}
293 ; CHECK-NEXT: i64.store32 0($0):p2align=1, $1{{$}}
294 ; CHECK-NEXT: return{{$}}
295 define void @sti32_a2(ptr %p, i64 %w) {
296 %v = trunc i64 %w to i32
297 store i32 %v, ptr %p, align 2
301 ; CHECK-LABEL: sti32_a4:
302 ; CHECK-NEXT: .functype sti32_a4 (i32, i64) -> (){{$}}
303 ; CHECK-NEXT: i64.store32 0($0), $1{{$}}
304 ; CHECK-NEXT: return{{$}}
305 define void @sti32_a4(ptr %p, i64 %w) {
306 %v = trunc i64 %w to i32
307 store i32 %v, ptr %p, align 4
311 ; CHECK-LABEL: sti32_a8:
312 ; CHECK-NEXT: .functype sti32_a8 (i32, i64) -> (){{$}}
313 ; CHECK-NEXT: i64.store32 0($0), $1{{$}}
314 ; CHECK-NEXT: return{{$}}
315 define void @sti32_a8(ptr %p, i64 %w) {
316 %v = trunc i64 %w to i32
317 store i32 %v, ptr %p, align 8
321 ;===----------------------------------------------------------------------------
323 ;===----------------------------------------------------------------------------
325 ; Wasm atomics have the alignment field, but it must always have the type's
328 ; CHECK-LABEL: ldi64_atomic_a8:
329 ; CHECK-NEXT: .functype ldi64_atomic_a8 (i32) -> (i64){{$}}
330 ; CHECK-NEXT: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
331 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
332 define i64 @ldi64_atomic_a8(ptr %p) {
333 %v = load atomic i64, ptr %p seq_cst, align 8
337 ; 16 is greater than the default alignment so it is ignored.
339 ; CHECK-LABEL: ldi64_atomic_a16:
340 ; CHECK-NEXT: .functype ldi64_atomic_a16 (i32) -> (i64){{$}}
341 ; CHECK-NEXT: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
342 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
343 define i64 @ldi64_atomic_a16(ptr %p) {
344 %v = load atomic i64, ptr %p seq_cst, align 16
348 ;===----------------------------------------------------------------------------
350 ;===----------------------------------------------------------------------------
352 ; CHECK-LABEL: sti64_atomic_a4:
353 ; CHECK-NEXT: .functype sti64_atomic_a4 (i32, i64) -> (){{$}}
354 ; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
355 ; CHECK-NEXT: return{{$}}
356 define void @sti64_atomic_a4(ptr %p, i64 %v) {
357 store atomic i64 %v, ptr %p seq_cst, align 8
361 ; 16 is greater than the default alignment so it is ignored.
363 ; CHECK-LABEL: sti64_atomic_a8:
364 ; CHECK-NEXT: .functype sti64_atomic_a8 (i32, i64) -> (){{$}}
365 ; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
366 ; CHECK-NEXT: return{{$}}
367 define void @sti64_atomic_a8(ptr %p, i64 %v) {
368 store atomic i64 %v, ptr %p seq_cst, align 16