xref: /llvm-project/llvm/test/CodeGen/WebAssembly/i32-load-store-alignment.ll (revision 73856247eef35f5336e485dc009842a5b991c421)
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 triple = "wasm32-unknown-unknown"
6
7;===----------------------------------------------------------------------------
8; Loads
9;===----------------------------------------------------------------------------
10
11; CHECK-LABEL: ldi32_a1:
12; CHECK-NEXT: .functype ldi32_a1 (i32) -> (i32){{$}}
13; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
14; CHECK-NEXT: return $pop[[NUM]]{{$}}
15define i32 @ldi32_a1(ptr %p) {
16  %v = load i32, ptr %p, align 1
17  ret i32 %v
18}
19
20; CHECK-LABEL: ldi32_a2:
21; CHECK-NEXT: .functype ldi32_a2 (i32) -> (i32){{$}}
22; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0):p2align=1{{$}}
23; CHECK-NEXT: return $pop[[NUM]]{{$}}
24define i32 @ldi32_a2(ptr %p) {
25  %v = load i32, ptr %p, align 2
26  ret i32 %v
27}
28
29; 4 is the default alignment for i32 so no attribute is needed.
30
31; CHECK-LABEL: ldi32_a4:
32; CHECK-NEXT: .functype ldi32_a4 (i32) -> (i32){{$}}
33; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
34; CHECK-NEXT: return $pop[[NUM]]{{$}}
35define i32 @ldi32_a4(ptr %p) {
36  %v = load i32, ptr %p, align 4
37  ret i32 %v
38}
39
40; The default alignment in LLVM is the same as the default alignment in wasm.
41
42; CHECK-LABEL: ldi32:
43; CHECK-NEXT: .functype ldi32 (i32) -> (i32){{$}}
44; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
45; CHECK-NEXT: return $pop[[NUM]]{{$}}
46define i32 @ldi32(ptr %p) {
47  %v = load i32, ptr %p
48  ret i32 %v
49}
50
51; 8 is greater than the default alignment so it is ignored.
52
53; CHECK-LABEL: ldi32_a8:
54; CHECK-NEXT: .functype ldi32_a8 (i32) -> (i32){{$}}
55; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
56; CHECK-NEXT: return $pop[[NUM]]{{$}}
57define i32 @ldi32_a8(ptr %p) {
58  %v = load i32, ptr %p, align 8
59  ret i32 %v
60}
61
62;===----------------------------------------------------------------------------
63; Extending loads
64;===----------------------------------------------------------------------------
65
66; CHECK-LABEL: ldi8_a1:
67; CHECK-NEXT: .functype ldi8_a1 (i32) -> (i32){{$}}
68; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
69; CHECK-NEXT: return $pop[[NUM]]{{$}}
70define i8 @ldi8_a1(ptr %p) {
71  %v = load i8, ptr %p, align 1
72  ret i8 %v
73}
74
75; CHECK-LABEL: ldi8_a2:
76; CHECK-NEXT: .functype ldi8_a2 (i32) -> (i32){{$}}
77; CHECK-NEXT: i32.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
78; CHECK-NEXT: return $pop[[NUM]]{{$}}
79define i8 @ldi8_a2(ptr %p) {
80  %v = load i8, ptr %p, align 2
81  ret i8 %v
82}
83
84; CHECK-LABEL: ldi16_a1:
85; CHECK-NEXT: .functype ldi16_a1 (i32) -> (i32){{$}}
86; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0):p2align=0{{$}}
87; CHECK-NEXT: return $pop[[NUM]]{{$}}
88define i16 @ldi16_a1(ptr %p) {
89  %v = load i16, ptr %p, align 1
90  ret i16 %v
91}
92
93; CHECK-LABEL: ldi16_a2:
94; CHECK-NEXT: .functype ldi16_a2 (i32) -> (i32){{$}}
95; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
96; CHECK-NEXT: return $pop[[NUM]]{{$}}
97define i16 @ldi16_a2(ptr %p) {
98  %v = load i16, ptr %p, align 2
99  ret i16 %v
100}
101
102; CHECK-LABEL: ldi16_a4:
103; CHECK-NEXT: .functype ldi16_a4 (i32) -> (i32){{$}}
104; CHECK-NEXT: i32.load16_u $push[[NUM:[0-9]+]]=, 0($0){{$}}
105; CHECK-NEXT: return $pop[[NUM]]{{$}}
106define i16 @ldi16_a4(ptr %p) {
107  %v = load i16, ptr %p, align 4
108  ret i16 %v
109}
110
111;===----------------------------------------------------------------------------
112; Stores
113;===----------------------------------------------------------------------------
114
115; CHECK-LABEL: sti32_a1:
116; CHECK-NEXT: .functype sti32_a1 (i32, i32) -> (){{$}}
117; CHECK-NEXT: i32.store 0($0):p2align=0, $1{{$}}
118; CHECK-NEXT: return{{$}}
119define void @sti32_a1(ptr %p, i32 %v) {
120  store i32 %v, ptr %p, align 1
121  ret void
122}
123
124; CHECK-LABEL: sti32_a2:
125; CHECK-NEXT: .functype sti32_a2 (i32, i32) -> (){{$}}
126; CHECK-NEXT: i32.store 0($0):p2align=1, $1{{$}}
127; CHECK-NEXT: return{{$}}
128define void @sti32_a2(ptr %p, i32 %v) {
129  store i32 %v, ptr %p, align 2
130  ret void
131}
132
133; 4 is the default alignment for i32 so no attribute is needed.
134
135; CHECK-LABEL: sti32_a4:
136; CHECK-NEXT: .functype sti32_a4 (i32, i32) -> (){{$}}
137; CHECK-NEXT: i32.store 0($0), $1{{$}}
138; CHECK-NEXT: return{{$}}
139define void @sti32_a4(ptr %p, i32 %v) {
140  store i32 %v, ptr %p, align 4
141  ret void
142}
143
144; The default alignment in LLVM is the same as the default alignment in wasm.
145
146; CHECK-LABEL: sti32:
147; CHECK-NEXT: .functype sti32 (i32, i32) -> (){{$}}
148; CHECK-NEXT: i32.store 0($0), $1{{$}}
149; CHECK-NEXT: return{{$}}
150define void @sti32(ptr %p, i32 %v) {
151  store i32 %v, ptr %p
152  ret void
153}
154
155; CHECK-LABEL: sti32_a8:
156; CHECK-NEXT: .functype sti32_a8 (i32, i32) -> (){{$}}
157; CHECK-NEXT: i32.store 0($0), $1{{$}}
158; CHECK-NEXT: return{{$}}
159define void @sti32_a8(ptr %p, i32 %v) {
160  store i32 %v, ptr %p, align 8
161  ret void
162}
163
164;===----------------------------------------------------------------------------
165; Truncating stores
166;===----------------------------------------------------------------------------
167
168; CHECK-LABEL: sti8_a1:
169; CHECK-NEXT: .functype sti8_a1 (i32, i32) -> (){{$}}
170; CHECK-NEXT: i32.store8 0($0), $1{{$}}
171; CHECK-NEXT: return{{$}}
172define void @sti8_a1(ptr %p, i8 %v) {
173  store i8 %v, ptr %p, align 1
174  ret void
175}
176
177; CHECK-LABEL: sti8_a2:
178; CHECK-NEXT: .functype sti8_a2 (i32, i32) -> (){{$}}
179; CHECK-NEXT: i32.store8 0($0), $1{{$}}
180; CHECK-NEXT: return{{$}}
181define void @sti8_a2(ptr %p, i8 %v) {
182  store i8 %v, ptr %p, align 2
183  ret void
184}
185
186; CHECK-LABEL: sti16_a1:
187; CHECK-NEXT: .functype sti16_a1 (i32, i32) -> (){{$}}
188; CHECK-NEXT: i32.store16 0($0):p2align=0, $1{{$}}
189; CHECK-NEXT: return{{$}}
190define void @sti16_a1(ptr %p, i16 %v) {
191  store i16 %v, ptr %p, align 1
192  ret void
193}
194
195; CHECK-LABEL: sti16_a2:
196; CHECK-NEXT: .functype sti16_a2 (i32, i32) -> (){{$}}
197; CHECK-NEXT: i32.store16 0($0), $1{{$}}
198; CHECK-NEXT: return{{$}}
199define void @sti16_a2(ptr %p, i16 %v) {
200  store i16 %v, ptr %p, align 2
201  ret void
202}
203
204; CHECK-LABEL: sti16_a4:
205; CHECK-NEXT: .functype sti16_a4 (i32, i32) -> (){{$}}
206; CHECK-NEXT: i32.store16 0($0), $1{{$}}
207; CHECK-NEXT: return{{$}}
208define void @sti16_a4(ptr %p, i16 %v) {
209  store i16 %v, ptr %p, align 4
210  ret void
211}
212
213;===----------------------------------------------------------------------------
214; Atomic loads
215;===----------------------------------------------------------------------------
216
217; Wasm atomics have the alignment field, but it must always have the type's
218; natural alignment.
219
220; CHECK-LABEL: ldi32_atomic_a4:
221; CHECK-NEXT: .functype ldi32_atomic_a4 (i32) -> (i32){{$}}
222; CHECK-NEXT: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
223; CHECK-NEXT: return $pop[[NUM]]{{$}}
224define i32 @ldi32_atomic_a4(ptr %p) {
225  %v = load atomic i32, ptr %p seq_cst, align 4
226  ret i32 %v
227}
228
229; 8 is greater than the default alignment so it is ignored.
230
231; CHECK-LABEL: ldi32_atomic_a8:
232; CHECK-NEXT: .functype ldi32_atomic_a8 (i32) -> (i32){{$}}
233; CHECK-NEXT: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
234; CHECK-NEXT: return $pop[[NUM]]{{$}}
235define i32 @ldi32_atomic_a8(ptr %p) {
236  %v = load atomic i32, ptr %p seq_cst, align 8
237  ret i32 %v
238}
239
240;===----------------------------------------------------------------------------
241; Atomic stores
242;===----------------------------------------------------------------------------
243
244; CHECK-LABEL: sti32_atomic_a4:
245; CHECK-NEXT: .functype sti32_atomic_a4 (i32, i32) -> (){{$}}
246; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
247; CHECK-NEXT: return{{$}}
248define void @sti32_atomic_a4(ptr %p, i32 %v) {
249 store atomic i32 %v, ptr %p seq_cst, align 4
250 ret void
251}
252
253; 8 is greater than the default alignment so it is ignored.
254
255; CHECK-LABEL: sti32_atomic_a8:
256; CHECK-NEXT: .functype sti32_atomic_a8 (i32, i32) -> (){{$}}
257; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
258; CHECK-NEXT: return{{$}}
259define void @sti32_atomic_a8(ptr %p, i32 %v) {
260 store atomic i32 %v, ptr %p seq_cst, align 8
261 ret void
262}
263