1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=32 %s --check-prefix=CHECK-32
3 ; RUN: llc < %s --mtriple=wasm64-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=64 %s --check-prefix=CHECK-64
5 declare void @ext_func(ptr %ptr)
6 declare void @ext_func_i32(ptr %ptr)
8 ; Check that there is an extra local for the stack pointer.
9 define void @alloca32() noredzone {
10 ; CHECK-32-LABEL: alloca32:
11 ; CHECK-32: .functype alloca32 () -> ()
12 ; CHECK-32-NEXT: .local i32
13 ; CHECK-32-NEXT: # %bb.0:
14 ; CHECK-32-NEXT: global.get $push1=, __stack_pointer
15 ; CHECK-32-NEXT: i32.const $push2=, 16
16 ; CHECK-32-NEXT: i32.sub $push6=, $pop1, $pop2
17 ; CHECK-32-NEXT: local.tee $push5=, 0, $pop6
18 ; CHECK-32-NEXT: global.set __stack_pointer, $pop5
19 ; CHECK-32-NEXT: local.get $push7=, 0
20 ; CHECK-32-NEXT: i32.const $push0=, 0
21 ; CHECK-32-NEXT: i32.store 12($pop7), $pop0
22 ; CHECK-32-NEXT: local.get $push8=, 0
23 ; CHECK-32-NEXT: i32.const $push3=, 16
24 ; CHECK-32-NEXT: i32.add $push4=, $pop8, $pop3
25 ; CHECK-32-NEXT: global.set __stack_pointer, $pop4
26 ; CHECK-32-NEXT: return
28 ; CHECK-64-LABEL: alloca32:
29 ; CHECK-64: .functype alloca32 () -> ()
30 ; CHECK-64-NEXT: .local i64
31 ; CHECK-64-NEXT: # %bb.0:
32 ; CHECK-64-NEXT: global.get $push1=, __stack_pointer
33 ; CHECK-64-NEXT: i64.const $push2=, 16
34 ; CHECK-64-NEXT: i64.sub $push6=, $pop1, $pop2
35 ; CHECK-64-NEXT: local.tee $push5=, 0, $pop6
36 ; CHECK-64-NEXT: global.set __stack_pointer, $pop5
37 ; CHECK-64-NEXT: local.get $push7=, 0
38 ; CHECK-64-NEXT: i32.const $push0=, 0
39 ; CHECK-64-NEXT: i32.store 12($pop7), $pop0
40 ; CHECK-64-NEXT: local.get $push8=, 0
41 ; CHECK-64-NEXT: i64.const $push3=, 16
42 ; CHECK-64-NEXT: i64.add $push4=, $pop8, $pop3
43 ; CHECK-64-NEXT: global.set __stack_pointer, $pop4
44 ; CHECK-64-NEXT: return
46 store i32 0, ptr %retval
50 define void @alloca3264() {
51 ; CHECK-32-LABEL: alloca3264:
52 ; CHECK-32: .functype alloca3264 () -> ()
53 ; CHECK-32-NEXT: .local i32
54 ; CHECK-32-NEXT: # %bb.0:
55 ; CHECK-32-NEXT: global.get $push2=, __stack_pointer
56 ; CHECK-32-NEXT: i32.const $push3=, 16
57 ; CHECK-32-NEXT: i32.sub $push5=, $pop2, $pop3
58 ; CHECK-32-NEXT: local.tee $push4=, 0, $pop5
59 ; CHECK-32-NEXT: i64.const $push0=, 0
60 ; CHECK-32-NEXT: i64.store 0($pop4), $pop0
61 ; CHECK-32-NEXT: local.get $push6=, 0
62 ; CHECK-32-NEXT: i32.const $push1=, 0
63 ; CHECK-32-NEXT: i32.store 12($pop6), $pop1
64 ; CHECK-32-NEXT: return
66 ; CHECK-64-LABEL: alloca3264:
67 ; CHECK-64: .functype alloca3264 () -> ()
68 ; CHECK-64-NEXT: .local i64
69 ; CHECK-64-NEXT: # %bb.0:
70 ; CHECK-64-NEXT: global.get $push2=, __stack_pointer
71 ; CHECK-64-NEXT: i64.const $push3=, 16
72 ; CHECK-64-NEXT: i64.sub $push5=, $pop2, $pop3
73 ; CHECK-64-NEXT: local.tee $push4=, 0, $pop5
74 ; CHECK-64-NEXT: i64.const $push0=, 0
75 ; CHECK-64-NEXT: i64.store 0($pop4), $pop0
76 ; CHECK-64-NEXT: local.get $push6=, 0
77 ; CHECK-64-NEXT: i32.const $push1=, 0
78 ; CHECK-64-NEXT: i32.store 12($pop6), $pop1
79 ; CHECK-64-NEXT: return
83 store double 0.0, ptr %r2
87 define void @allocarray() {
88 ; CHECK-32-LABEL: allocarray:
89 ; CHECK-32: .functype allocarray () -> ()
90 ; CHECK-32-NEXT: .local i32
91 ; CHECK-32-NEXT: # %bb.0:
92 ; CHECK-32-NEXT: global.get $push3=, __stack_pointer
93 ; CHECK-32-NEXT: i32.const $push4=, 144
94 ; CHECK-32-NEXT: i32.sub $push9=, $pop3, $pop4
95 ; CHECK-32-NEXT: local.tee $push8=, 0, $pop9
96 ; CHECK-32-NEXT: global.set __stack_pointer, $pop8
97 ; CHECK-32-NEXT: local.get $push10=, 0
98 ; CHECK-32-NEXT: i32.const $push0=, 24
99 ; CHECK-32-NEXT: i32.add $push1=, $pop10, $pop0
100 ; CHECK-32-NEXT: i32.const $push2=, 1
101 ; CHECK-32-NEXT: i32.store 0($pop1), $pop2
102 ; CHECK-32-NEXT: local.get $push11=, 0
103 ; CHECK-32-NEXT: i32.const $push7=, 1
104 ; CHECK-32-NEXT: i32.store 12($pop11), $pop7
105 ; CHECK-32-NEXT: local.get $push12=, 0
106 ; CHECK-32-NEXT: i32.const $push5=, 144
107 ; CHECK-32-NEXT: i32.add $push6=, $pop12, $pop5
108 ; CHECK-32-NEXT: global.set __stack_pointer, $pop6
109 ; CHECK-32-NEXT: return
111 ; CHECK-64-LABEL: allocarray:
112 ; CHECK-64: .functype allocarray () -> ()
113 ; CHECK-64-NEXT: .local i64
114 ; CHECK-64-NEXT: # %bb.0:
115 ; CHECK-64-NEXT: global.get $push3=, __stack_pointer
116 ; CHECK-64-NEXT: i64.const $push4=, 144
117 ; CHECK-64-NEXT: i64.sub $push9=, $pop3, $pop4
118 ; CHECK-64-NEXT: local.tee $push8=, 0, $pop9
119 ; CHECK-64-NEXT: global.set __stack_pointer, $pop8
120 ; CHECK-64-NEXT: local.get $push10=, 0
121 ; CHECK-64-NEXT: i64.const $push0=, 24
122 ; CHECK-64-NEXT: i64.add $push1=, $pop10, $pop0
123 ; CHECK-64-NEXT: i32.const $push2=, 1
124 ; CHECK-64-NEXT: i32.store 0($pop1), $pop2
125 ; CHECK-64-NEXT: local.get $push11=, 0
126 ; CHECK-64-NEXT: i32.const $push7=, 1
127 ; CHECK-64-NEXT: i32.store 12($pop11), $pop7
128 ; CHECK-64-NEXT: local.get $push12=, 0
129 ; CHECK-64-NEXT: i64.const $push5=, 144
130 ; CHECK-64-NEXT: i64.add $push6=, $pop12, $pop5
131 ; CHECK-64-NEXT: global.set __stack_pointer, $pop6
132 ; CHECK-64-NEXT: return
133 %r = alloca [33 x i32]
135 %p2 = getelementptr [33 x i32], ptr %r, i32 0, i32 3
140 define void @non_mem_use(ptr %addr) {
141 ; CHECK-32-LABEL: non_mem_use:
142 ; CHECK-32: .functype non_mem_use (i32) -> ()
143 ; CHECK-32-NEXT: .local i32
144 ; CHECK-32-NEXT: # %bb.0:
145 ; CHECK-32-NEXT: global.get $push0=, __stack_pointer
146 ; CHECK-32-NEXT: i32.const $push1=, 48
147 ; CHECK-32-NEXT: i32.sub $push9=, $pop0, $pop1
148 ; CHECK-32-NEXT: local.tee $push8=, 1, $pop9
149 ; CHECK-32-NEXT: global.set __stack_pointer, $pop8
150 ; CHECK-32-NEXT: local.get $push10=, 1
151 ; CHECK-32-NEXT: i32.const $push6=, 8
152 ; CHECK-32-NEXT: i32.add $push7=, $pop10, $pop6
153 ; CHECK-32-NEXT: call ext_func, $pop7
154 ; CHECK-32-NEXT: local.get $push11=, 1
155 ; CHECK-32-NEXT: call ext_func, $pop11
156 ; CHECK-32-NEXT: local.get $push13=, 0
157 ; CHECK-32-NEXT: local.get $push12=, 1
158 ; CHECK-32-NEXT: i32.const $push4=, 16
159 ; CHECK-32-NEXT: i32.add $push5=, $pop12, $pop4
160 ; CHECK-32-NEXT: i32.store 0($pop13), $pop5
161 ; CHECK-32-NEXT: local.get $push14=, 1
162 ; CHECK-32-NEXT: i32.const $push2=, 48
163 ; CHECK-32-NEXT: i32.add $push3=, $pop14, $pop2
164 ; CHECK-32-NEXT: global.set __stack_pointer, $pop3
165 ; CHECK-32-NEXT: return
167 ; CHECK-64-LABEL: non_mem_use:
168 ; CHECK-64: .functype non_mem_use (i64) -> ()
169 ; CHECK-64-NEXT: .local i64
170 ; CHECK-64-NEXT: # %bb.0:
171 ; CHECK-64-NEXT: global.get $push0=, __stack_pointer
172 ; CHECK-64-NEXT: i64.const $push1=, 48
173 ; CHECK-64-NEXT: i64.sub $push9=, $pop0, $pop1
174 ; CHECK-64-NEXT: local.tee $push8=, 1, $pop9
175 ; CHECK-64-NEXT: global.set __stack_pointer, $pop8
176 ; CHECK-64-NEXT: local.get $push10=, 1
177 ; CHECK-64-NEXT: i64.const $push6=, 8
178 ; CHECK-64-NEXT: i64.add $push7=, $pop10, $pop6
179 ; CHECK-64-NEXT: call ext_func, $pop7
180 ; CHECK-64-NEXT: local.get $push11=, 1
181 ; CHECK-64-NEXT: call ext_func, $pop11
182 ; CHECK-64-NEXT: local.get $push13=, 0
183 ; CHECK-64-NEXT: local.get $push12=, 1
184 ; CHECK-64-NEXT: i64.const $push4=, 16
185 ; CHECK-64-NEXT: i64.add $push5=, $pop12, $pop4
186 ; CHECK-64-NEXT: i64.store 0($pop13), $pop5
187 ; CHECK-64-NEXT: local.get $push14=, 1
188 ; CHECK-64-NEXT: i64.const $push2=, 48
189 ; CHECK-64-NEXT: i64.add $push3=, $pop14, $pop2
190 ; CHECK-64-NEXT: global.set __stack_pointer, $pop3
191 ; CHECK-64-NEXT: return
192 %buf = alloca [27 x i8], align 16
196 call void @ext_func(ptr %r)
197 ; %r2 is at SP+0, no add needed
198 call void @ext_func(ptr %r2)
199 ; Use as a value, but in a store
201 store ptr %buf, ptr %addr
205 define void @allocarray_inbounds() {
206 ; CHECK-32-LABEL: allocarray_inbounds:
207 ; CHECK-32: .functype allocarray_inbounds () -> ()
208 ; CHECK-32-NEXT: .local i32
209 ; CHECK-32-NEXT: # %bb.0:
210 ; CHECK-32-NEXT: global.get $push2=, __stack_pointer
211 ; CHECK-32-NEXT: i32.const $push3=, 32
212 ; CHECK-32-NEXT: i32.sub $push8=, $pop2, $pop3
213 ; CHECK-32-NEXT: local.tee $push7=, 0, $pop8
214 ; CHECK-32-NEXT: global.set __stack_pointer, $pop7
215 ; CHECK-32-NEXT: local.get $push9=, 0
216 ; CHECK-32-NEXT: i32.const $push0=, 1
217 ; CHECK-32-NEXT: i32.store 24($pop9), $pop0
218 ; CHECK-32-NEXT: local.get $push10=, 0
219 ; CHECK-32-NEXT: i32.const $push6=, 1
220 ; CHECK-32-NEXT: i32.store 12($pop10), $pop6
221 ; CHECK-32-NEXT: i32.const $push1=, 0
222 ; CHECK-32-NEXT: call ext_func, $pop1
223 ; CHECK-32-NEXT: local.get $push11=, 0
224 ; CHECK-32-NEXT: i32.const $push4=, 32
225 ; CHECK-32-NEXT: i32.add $push5=, $pop11, $pop4
226 ; CHECK-32-NEXT: global.set __stack_pointer, $pop5
227 ; CHECK-32-NEXT: return
229 ; CHECK-64-LABEL: allocarray_inbounds:
230 ; CHECK-64: .functype allocarray_inbounds () -> ()
231 ; CHECK-64-NEXT: .local i64
232 ; CHECK-64-NEXT: # %bb.0:
233 ; CHECK-64-NEXT: global.get $push2=, __stack_pointer
234 ; CHECK-64-NEXT: i64.const $push3=, 32
235 ; CHECK-64-NEXT: i64.sub $push8=, $pop2, $pop3
236 ; CHECK-64-NEXT: local.tee $push7=, 0, $pop8
237 ; CHECK-64-NEXT: global.set __stack_pointer, $pop7
238 ; CHECK-64-NEXT: local.get $push9=, 0
239 ; CHECK-64-NEXT: i32.const $push0=, 1
240 ; CHECK-64-NEXT: i32.store 24($pop9), $pop0
241 ; CHECK-64-NEXT: local.get $push10=, 0
242 ; CHECK-64-NEXT: i32.const $push6=, 1
243 ; CHECK-64-NEXT: i32.store 12($pop10), $pop6
244 ; CHECK-64-NEXT: i64.const $push1=, 0
245 ; CHECK-64-NEXT: call ext_func, $pop1
246 ; CHECK-64-NEXT: local.get $push11=, 0
247 ; CHECK-64-NEXT: i64.const $push4=, 32
248 ; CHECK-64-NEXT: i64.add $push5=, $pop11, $pop4
249 ; CHECK-64-NEXT: global.set __stack_pointer, $pop5
250 ; CHECK-64-NEXT: return
251 %r = alloca [5 x i32]
253 ; This store should have both the GEP and the FI folded into it.
254 %p2 = getelementptr inbounds [5 x i32], ptr %r, i32 0, i32 3
256 call void @ext_func(ptr null);
260 define void @dynamic_alloca(i32 %alloc) {
261 ; Target independent codegen bumps the stack pointer.
262 ; Check that SP is written back to memory after decrement
263 ; CHECK-32-LABEL: dynamic_alloca:
264 ; CHECK-32: .functype dynamic_alloca (i32) -> ()
265 ; CHECK-32-NEXT: .local i32
266 ; CHECK-32-NEXT: # %bb.0:
267 ; CHECK-32-NEXT: global.get $push10=, __stack_pointer
268 ; CHECK-32-NEXT: local.tee $push9=, 1, $pop10
269 ; CHECK-32-NEXT: local.get $push11=, 0
270 ; CHECK-32-NEXT: i32.const $push0=, 2
271 ; CHECK-32-NEXT: i32.shl $push1=, $pop11, $pop0
272 ; CHECK-32-NEXT: i32.const $push2=, 15
273 ; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2
274 ; CHECK-32-NEXT: i32.const $push4=, -16
275 ; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4
276 ; CHECK-32-NEXT: i32.sub $push8=, $pop9, $pop5
277 ; CHECK-32-NEXT: local.tee $push7=, 0, $pop8
278 ; CHECK-32-NEXT: global.set __stack_pointer, $pop7
279 ; CHECK-32-NEXT: local.get $push12=, 0
280 ; CHECK-32-NEXT: call ext_func_i32, $pop12
281 ; CHECK-32-NEXT: local.get $push6=, 1
282 ; CHECK-32-NEXT: global.set __stack_pointer, $pop6
283 ; CHECK-32-NEXT: return
285 ; CHECK-64-LABEL: dynamic_alloca:
286 ; CHECK-64: .functype dynamic_alloca (i32) -> ()
287 ; CHECK-64-NEXT: .local i64, i64
288 ; CHECK-64-NEXT: # %bb.0:
289 ; CHECK-64-NEXT: global.get $push11=, __stack_pointer
290 ; CHECK-64-NEXT: local.tee $push10=, 1, $pop11
291 ; CHECK-64-NEXT: local.get $push12=, 0
292 ; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop12
293 ; CHECK-64-NEXT: i64.const $push1=, 2
294 ; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1
295 ; CHECK-64-NEXT: i64.const $push3=, 15
296 ; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3
297 ; CHECK-64-NEXT: i64.const $push5=, 34359738352
298 ; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5
299 ; CHECK-64-NEXT: i64.sub $push9=, $pop10, $pop6
300 ; CHECK-64-NEXT: local.tee $push8=, 2, $pop9
301 ; CHECK-64-NEXT: global.set __stack_pointer, $pop8
302 ; CHECK-64-NEXT: local.get $push13=, 2
303 ; CHECK-64-NEXT: call ext_func_i32, $pop13
304 ; CHECK-64-NEXT: local.get $push7=, 1
305 ; CHECK-64-NEXT: global.set __stack_pointer, $pop7
306 ; CHECK-64-NEXT: return
307 %r = alloca i32, i32 %alloc
308 ; Target-independent codegen also calculates the store addr
309 call void @ext_func_i32(ptr %r)
313 define void @dynamic_alloca_redzone(i32 %alloc) {
314 ; Target independent codegen bumps the stack pointer
315 ; CHECK-32-LABEL: dynamic_alloca_redzone:
316 ; CHECK-32: .functype dynamic_alloca_redzone (i32) -> ()
317 ; CHECK-32-NEXT: .local i32
318 ; CHECK-32-NEXT: # %bb.0:
319 ; CHECK-32-NEXT: global.get $push8=, __stack_pointer
320 ; CHECK-32-NEXT: local.tee $push9=, 1, $pop8
321 ; CHECK-32-NEXT: drop $pop9
322 ; CHECK-32-NEXT: local.get $push11=, 1
323 ; CHECK-32-NEXT: local.get $push10=, 0
324 ; CHECK-32-NEXT: i32.const $push0=, 2
325 ; CHECK-32-NEXT: i32.shl $push1=, $pop10, $pop0
326 ; CHECK-32-NEXT: i32.const $push2=, 15
327 ; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2
328 ; CHECK-32-NEXT: i32.const $push4=, -16
329 ; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4
330 ; CHECK-32-NEXT: i32.sub $push7=, $pop11, $pop5
331 ; CHECK-32-NEXT: local.tee $push12=, 0, $pop7
332 ; CHECK-32-NEXT: drop $pop12
333 ; CHECK-32-NEXT: local.get $push13=, 0
334 ; CHECK-32-NEXT: i32.const $push6=, 0
335 ; CHECK-32-NEXT: i32.store 0($pop13), $pop6
336 ; CHECK-32-NEXT: return
338 ; CHECK-64-LABEL: dynamic_alloca_redzone:
339 ; CHECK-64: .functype dynamic_alloca_redzone (i32) -> ()
340 ; CHECK-64-NEXT: .local i64
341 ; CHECK-64-NEXT: # %bb.0:
342 ; CHECK-64-NEXT: global.get $push9=, __stack_pointer
343 ; CHECK-64-NEXT: local.tee $push10=, 1, $pop9
344 ; CHECK-64-NEXT: drop $pop10
345 ; CHECK-64-NEXT: local.get $push12=, 1
346 ; CHECK-64-NEXT: local.get $push11=, 0
347 ; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop11
348 ; CHECK-64-NEXT: i64.const $push1=, 2
349 ; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1
350 ; CHECK-64-NEXT: i64.const $push3=, 15
351 ; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3
352 ; CHECK-64-NEXT: i64.const $push5=, 34359738352
353 ; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5
354 ; CHECK-64-NEXT: i64.sub $push8=, $pop12, $pop6
355 ; CHECK-64-NEXT: local.tee $push13=, 1, $pop8
356 ; CHECK-64-NEXT: drop $pop13
357 ; CHECK-64-NEXT: local.get $push14=, 1
358 ; CHECK-64-NEXT: i32.const $push7=, 0
359 ; CHECK-64-NEXT: i32.store 0($pop14), $pop7
360 ; CHECK-64-NEXT: return
361 %r = alloca i32, i32 %alloc
366 define void @dynamic_static_alloca(i32 %alloc) noredzone {
367 ; Decrement SP in the prolog by the static amount and writeback to memory.
368 ; Alloc and write to a static alloca
369 ; CHECK-32-LABEL: dynamic_static_alloca:
370 ; CHECK-32: .functype dynamic_static_alloca (i32) -> ()
371 ; CHECK-32-NEXT: .local i32, i32, i32
372 ; CHECK-32-NEXT: # %bb.0:
373 ; CHECK-32-NEXT: global.get $push11=, __stack_pointer
374 ; CHECK-32-NEXT: i32.const $push12=, 16
375 ; CHECK-32-NEXT: i32.sub $push25=, $pop11, $pop12
376 ; CHECK-32-NEXT: local.tee $push24=, 1, $pop25
377 ; CHECK-32-NEXT: global.set __stack_pointer, $pop24
378 ; CHECK-32-NEXT: local.get $push23=, 1
379 ; CHECK-32-NEXT: local.tee $push22=, 2, $pop23
380 ; CHECK-32-NEXT: i32.const $push0=, 101
381 ; CHECK-32-NEXT: i32.store 12($pop22), $pop0
382 ; CHECK-32-NEXT: local.get $push27=, 1
383 ; CHECK-32-NEXT: local.get $push26=, 0
384 ; CHECK-32-NEXT: i32.const $push1=, 2
385 ; CHECK-32-NEXT: i32.shl $push2=, $pop26, $pop1
386 ; CHECK-32-NEXT: i32.const $push3=, 15
387 ; CHECK-32-NEXT: i32.add $push4=, $pop2, $pop3
388 ; CHECK-32-NEXT: i32.const $push5=, -16
389 ; CHECK-32-NEXT: i32.and $push21=, $pop4, $pop5
390 ; CHECK-32-NEXT: local.tee $push20=, 0, $pop21
391 ; CHECK-32-NEXT: i32.sub $push19=, $pop27, $pop20
392 ; CHECK-32-NEXT: local.tee $push18=, 1, $pop19
393 ; CHECK-32-NEXT: local.tee $push17=, 3, $pop18
394 ; CHECK-32-NEXT: global.set __stack_pointer, $pop17
395 ; CHECK-32-NEXT: local.get $push28=, 2
396 ; CHECK-32-NEXT: i32.const $push6=, 102
397 ; CHECK-32-NEXT: i32.store 12($pop28), $pop6
398 ; CHECK-32-NEXT: local.get $push29=, 1
399 ; CHECK-32-NEXT: i32.const $push7=, 103
400 ; CHECK-32-NEXT: i32.store 0($pop29), $pop7
401 ; CHECK-32-NEXT: local.get $push31=, 3
402 ; CHECK-32-NEXT: local.get $push30=, 0
403 ; CHECK-32-NEXT: i32.sub $push16=, $pop31, $pop30
404 ; CHECK-32-NEXT: local.tee $push15=, 0, $pop16
405 ; CHECK-32-NEXT: global.set __stack_pointer, $pop15
406 ; CHECK-32-NEXT: local.get $push32=, 2
407 ; CHECK-32-NEXT: i32.const $push8=, 104
408 ; CHECK-32-NEXT: i32.store 12($pop32), $pop8
409 ; CHECK-32-NEXT: local.get $push33=, 1
410 ; CHECK-32-NEXT: i32.const $push9=, 105
411 ; CHECK-32-NEXT: i32.store 0($pop33), $pop9
412 ; CHECK-32-NEXT: local.get $push34=, 0
413 ; CHECK-32-NEXT: i32.const $push10=, 106
414 ; CHECK-32-NEXT: i32.store 0($pop34), $pop10
415 ; CHECK-32-NEXT: local.get $push35=, 2
416 ; CHECK-32-NEXT: i32.const $push13=, 16
417 ; CHECK-32-NEXT: i32.add $push14=, $pop35, $pop13
418 ; CHECK-32-NEXT: global.set __stack_pointer, $pop14
419 ; CHECK-32-NEXT: return
421 ; CHECK-64-LABEL: dynamic_static_alloca:
422 ; CHECK-64: .functype dynamic_static_alloca (i32) -> ()
423 ; CHECK-64-NEXT: .local i64, i64, i64, i64
424 ; CHECK-64-NEXT: # %bb.0:
425 ; CHECK-64-NEXT: global.get $push12=, __stack_pointer
426 ; CHECK-64-NEXT: i64.const $push13=, 16
427 ; CHECK-64-NEXT: i64.sub $push26=, $pop12, $pop13
428 ; CHECK-64-NEXT: local.tee $push25=, 1, $pop26
429 ; CHECK-64-NEXT: global.set __stack_pointer, $pop25
430 ; CHECK-64-NEXT: local.get $push24=, 1
431 ; CHECK-64-NEXT: local.tee $push23=, 2, $pop24
432 ; CHECK-64-NEXT: i32.const $push0=, 101
433 ; CHECK-64-NEXT: i32.store 12($pop23), $pop0
434 ; CHECK-64-NEXT: local.get $push28=, 1
435 ; CHECK-64-NEXT: local.get $push27=, 0
436 ; CHECK-64-NEXT: i64.extend_i32_u $push1=, $pop27
437 ; CHECK-64-NEXT: i64.const $push2=, 2
438 ; CHECK-64-NEXT: i64.shl $push3=, $pop1, $pop2
439 ; CHECK-64-NEXT: i64.const $push4=, 15
440 ; CHECK-64-NEXT: i64.add $push5=, $pop3, $pop4
441 ; CHECK-64-NEXT: i64.const $push6=, 34359738352
442 ; CHECK-64-NEXT: i64.and $push22=, $pop5, $pop6
443 ; CHECK-64-NEXT: local.tee $push21=, 3, $pop22
444 ; CHECK-64-NEXT: i64.sub $push20=, $pop28, $pop21
445 ; CHECK-64-NEXT: local.tee $push19=, 1, $pop20
446 ; CHECK-64-NEXT: local.tee $push18=, 4, $pop19
447 ; CHECK-64-NEXT: global.set __stack_pointer, $pop18
448 ; CHECK-64-NEXT: local.get $push29=, 2
449 ; CHECK-64-NEXT: i32.const $push7=, 102
450 ; CHECK-64-NEXT: i32.store 12($pop29), $pop7
451 ; CHECK-64-NEXT: local.get $push30=, 1
452 ; CHECK-64-NEXT: i32.const $push8=, 103
453 ; CHECK-64-NEXT: i32.store 0($pop30), $pop8
454 ; CHECK-64-NEXT: local.get $push32=, 4
455 ; CHECK-64-NEXT: local.get $push31=, 3
456 ; CHECK-64-NEXT: i64.sub $push17=, $pop32, $pop31
457 ; CHECK-64-NEXT: local.tee $push16=, 3, $pop17
458 ; CHECK-64-NEXT: global.set __stack_pointer, $pop16
459 ; CHECK-64-NEXT: local.get $push33=, 2
460 ; CHECK-64-NEXT: i32.const $push9=, 104
461 ; CHECK-64-NEXT: i32.store 12($pop33), $pop9
462 ; CHECK-64-NEXT: local.get $push34=, 1
463 ; CHECK-64-NEXT: i32.const $push10=, 105
464 ; CHECK-64-NEXT: i32.store 0($pop34), $pop10
465 ; CHECK-64-NEXT: local.get $push35=, 3
466 ; CHECK-64-NEXT: i32.const $push11=, 106
467 ; CHECK-64-NEXT: i32.store 0($pop35), $pop11
468 ; CHECK-64-NEXT: local.get $push36=, 2
469 ; CHECK-64-NEXT: i64.const $push14=, 16
470 ; CHECK-64-NEXT: i64.add $push15=, $pop36, $pop14
471 ; CHECK-64-NEXT: global.set __stack_pointer, $pop15
472 ; CHECK-64-NEXT: return
474 store volatile i32 101, ptr %static
475 ; Decrement SP in the body by the dynamic amount.
476 %dynamic = alloca i32, i32 %alloc
477 ; Ensure we don't modify the frame pointer after assigning it.
478 ; Ensure the static address doesn't change after modifying the stack pointer.
479 store volatile i32 102, ptr %static
480 store volatile i32 103, ptr %dynamic
481 ; Decrement SP in the body by the dynamic amount.
482 %dynamic.2 = alloca i32, i32 %alloc
483 ; Ensure neither the static nor dynamic address changes after the second
484 ; modification of the stack pointer.
485 store volatile i32 104, ptr %static
486 store volatile i32 105, ptr %dynamic
487 store volatile i32 106, ptr %dynamic.2
488 ; Writeback to memory.
492 declare ptr @llvm.stacksave()
493 declare void @llvm.stackrestore(ptr)
495 define void @llvm_stack_builtins(i32 %alloc) noredzone {
496 ; CHECK-32-LABEL: llvm_stack_builtins:
497 ; CHECK-32: .functype llvm_stack_builtins (i32) -> ()
498 ; CHECK-32-NEXT: .local i32, i32, i32
499 ; CHECK-32-NEXT: # %bb.0:
500 ; CHECK-32-NEXT: global.get $push7=, __stack_pointer
501 ; CHECK-32-NEXT: local.tee $push8=, 1, $pop7
502 ; CHECK-32-NEXT: local.set 2, $pop8
503 ; CHECK-32-NEXT: local.get $push9=, 1
504 ; CHECK-32-NEXT: local.set 3, $pop9
505 ; CHECK-32-NEXT: local.get $push11=, 1
506 ; CHECK-32-NEXT: local.get $push10=, 0
507 ; CHECK-32-NEXT: i32.const $push0=, 2
508 ; CHECK-32-NEXT: i32.shl $push1=, $pop10, $pop0
509 ; CHECK-32-NEXT: i32.const $push2=, 15
510 ; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2
511 ; CHECK-32-NEXT: i32.const $push4=, -16
512 ; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4
513 ; CHECK-32-NEXT: i32.sub $push6=, $pop11, $pop5
514 ; CHECK-32-NEXT: global.set __stack_pointer, $pop6
515 ; CHECK-32-NEXT: local.get $push12=, 3
516 ; CHECK-32-NEXT: drop $pop12
517 ; CHECK-32-NEXT: local.get $push13=, 2
518 ; CHECK-32-NEXT: global.set __stack_pointer, $pop13
519 ; CHECK-32-NEXT: return
521 ; CHECK-64-LABEL: llvm_stack_builtins:
522 ; CHECK-64: .functype llvm_stack_builtins (i32) -> ()
523 ; CHECK-64-NEXT: .local i64, i64, i64
524 ; CHECK-64-NEXT: # %bb.0:
525 ; CHECK-64-NEXT: global.get $push8=, __stack_pointer
526 ; CHECK-64-NEXT: local.tee $push9=, 1, $pop8
527 ; CHECK-64-NEXT: local.set 2, $pop9
528 ; CHECK-64-NEXT: local.get $push10=, 1
529 ; CHECK-64-NEXT: local.set 3, $pop10
530 ; CHECK-64-NEXT: local.get $push12=, 1
531 ; CHECK-64-NEXT: local.get $push11=, 0
532 ; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop11
533 ; CHECK-64-NEXT: i64.const $push1=, 2
534 ; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1
535 ; CHECK-64-NEXT: i64.const $push3=, 15
536 ; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3
537 ; CHECK-64-NEXT: i64.const $push5=, 34359738352
538 ; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5
539 ; CHECK-64-NEXT: i64.sub $push7=, $pop12, $pop6
540 ; CHECK-64-NEXT: global.set __stack_pointer, $pop7
541 ; CHECK-64-NEXT: local.get $push13=, 3
542 ; CHECK-64-NEXT: drop $pop13
543 ; CHECK-64-NEXT: local.get $push14=, 2
544 ; CHECK-64-NEXT: global.set __stack_pointer, $pop14
545 ; CHECK-64-NEXT: return
546 %stack = call ptr @llvm.stacksave()
547 ; Ensure we don't reassign the stacksave local
548 %dynamic = alloca i32, i32 %alloc
549 call void @llvm.stackrestore(ptr %stack)
553 ; Use of stacksave requires local SP definition even without dymamic alloca.
554 ; CHECK-LABEL: llvm_stacksave_noalloca:
555 define void @llvm_stacksave_noalloca() noredzone {
556 ; CHECK: global.get $push[[L11:.+]]=, __stack_pointer{{$}}
557 %stack = call ptr @llvm.stacksave()
559 ; CHECK-NEXT: call use_i8_star, $pop[[L11:.+]]
560 call void @use_i8_star(ptr %stack)
565 ; Not actually using the alloca'd variables exposed an issue with register
566 ; stackification, where copying the stack pointer into the frame pointer was
567 ; moved after the stack pointer was updated for the dynamic alloca.
568 define void @dynamic_alloca_nouse(i32 %alloc) noredzone {
569 ; CHECK-32-LABEL: dynamic_alloca_nouse:
570 ; CHECK-32: .functype dynamic_alloca_nouse (i32) -> ()
571 ; CHECK-32-NEXT: .local i32, i32
572 ; CHECK-32-NEXT: # %bb.0:
573 ; CHECK-32-NEXT: global.get $push7=, __stack_pointer
574 ; CHECK-32-NEXT: local.tee $push8=, 1, $pop7
575 ; CHECK-32-NEXT: local.set 2, $pop8
576 ; CHECK-32-NEXT: local.get $push10=, 1
577 ; CHECK-32-NEXT: local.get $push9=, 0
578 ; CHECK-32-NEXT: i32.const $push0=, 2
579 ; CHECK-32-NEXT: i32.shl $push1=, $pop9, $pop0
580 ; CHECK-32-NEXT: i32.const $push2=, 15
581 ; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2
582 ; CHECK-32-NEXT: i32.const $push4=, -16
583 ; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4
584 ; CHECK-32-NEXT: i32.sub $push6=, $pop10, $pop5
585 ; CHECK-32-NEXT: global.set __stack_pointer, $pop6
586 ; CHECK-32-NEXT: local.get $push11=, 2
587 ; CHECK-32-NEXT: global.set __stack_pointer, $pop11
588 ; CHECK-32-NEXT: return
590 ; CHECK-64-LABEL: dynamic_alloca_nouse:
591 ; CHECK-64: .functype dynamic_alloca_nouse (i32) -> ()
592 ; CHECK-64-NEXT: .local i64, i64
593 ; CHECK-64-NEXT: # %bb.0:
594 ; CHECK-64-NEXT: global.get $push8=, __stack_pointer
595 ; CHECK-64-NEXT: local.tee $push9=, 1, $pop8
596 ; CHECK-64-NEXT: local.set 2, $pop9
597 ; CHECK-64-NEXT: local.get $push11=, 1
598 ; CHECK-64-NEXT: local.get $push10=, 0
599 ; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop10
600 ; CHECK-64-NEXT: i64.const $push1=, 2
601 ; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1
602 ; CHECK-64-NEXT: i64.const $push3=, 15
603 ; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3
604 ; CHECK-64-NEXT: i64.const $push5=, 34359738352
605 ; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5
606 ; CHECK-64-NEXT: i64.sub $push7=, $pop11, $pop6
607 ; CHECK-64-NEXT: global.set __stack_pointer, $pop7
608 ; CHECK-64-NEXT: local.get $push12=, 2
609 ; CHECK-64-NEXT: global.set __stack_pointer, $pop12
610 ; CHECK-64-NEXT: return
611 %dynamic = alloca i32, i32 %alloc
615 ; The use of the alloca in a phi causes a CopyToReg DAG node to be generated,
616 ; which has to have special handling because CopyToReg can't have a FI operand
617 define void @copytoreg_fi(i1 %cond, ptr %b) {
618 ; CHECK-32-LABEL: copytoreg_fi:
619 ; CHECK-32: .functype copytoreg_fi (i32, i32) -> ()
620 ; CHECK-32-NEXT: .local i32
621 ; CHECK-32-NEXT: # %bb.0: # %entry
622 ; CHECK-32-NEXT: global.get $push0=, __stack_pointer
623 ; CHECK-32-NEXT: i32.const $push1=, 16
624 ; CHECK-32-NEXT: i32.sub $push3=, $pop0, $pop1
625 ; CHECK-32-NEXT: i32.const $push2=, 12
626 ; CHECK-32-NEXT: i32.add $push6=, $pop3, $pop2
627 ; CHECK-32-NEXT: local.set 2, $pop6
628 ; CHECK-32-NEXT: local.get $push8=, 0
629 ; CHECK-32-NEXT: i32.const $push4=, 1
630 ; CHECK-32-NEXT: i32.and $push7=, $pop8, $pop4
631 ; CHECK-32-NEXT: local.set 0, $pop7
632 ; CHECK-32-NEXT: # %body
633 ; CHECK-32-NEXT: # =>This Inner Loop Header: Depth=1
634 ; CHECK-32-NEXT: loop # label0:
635 ; CHECK-32-NEXT: local.get $push9=, 2
636 ; CHECK-32-NEXT: i32.const $push5=, 1
637 ; CHECK-32-NEXT: i32.store 0($pop9), $pop5
638 ; CHECK-32-NEXT: local.get $push10=, 1
639 ; CHECK-32-NEXT: local.set 2, $pop10
640 ; CHECK-32-NEXT: local.get $push11=, 0
641 ; CHECK-32-NEXT: br_if 0, $pop11 # 0: up to label0
642 ; CHECK-32-NEXT: # %bb.2: # %exit
643 ; CHECK-32-NEXT: end_loop
644 ; CHECK-32-NEXT: return
646 ; CHECK-64-LABEL: copytoreg_fi:
647 ; CHECK-64: .functype copytoreg_fi (i32, i64) -> ()
648 ; CHECK-64-NEXT: .local i64
649 ; CHECK-64-NEXT: # %bb.0: # %entry
650 ; CHECK-64-NEXT: global.get $push0=, __stack_pointer
651 ; CHECK-64-NEXT: i64.const $push1=, 16
652 ; CHECK-64-NEXT: i64.sub $push3=, $pop0, $pop1
653 ; CHECK-64-NEXT: i64.const $push2=, 12
654 ; CHECK-64-NEXT: i64.add $push6=, $pop3, $pop2
655 ; CHECK-64-NEXT: local.set 2, $pop6
656 ; CHECK-64-NEXT: local.get $push8=, 0
657 ; CHECK-64-NEXT: i32.const $push4=, 1
658 ; CHECK-64-NEXT: i32.and $push7=, $pop8, $pop4
659 ; CHECK-64-NEXT: local.set 0, $pop7
660 ; CHECK-64-NEXT: # %body
661 ; CHECK-64-NEXT: # =>This Inner Loop Header: Depth=1
662 ; CHECK-64-NEXT: loop # label0:
663 ; CHECK-64-NEXT: local.get $push9=, 2
664 ; CHECK-64-NEXT: i32.const $push5=, 1
665 ; CHECK-64-NEXT: i32.store 0($pop9), $pop5
666 ; CHECK-64-NEXT: local.get $push10=, 1
667 ; CHECK-64-NEXT: local.set 2, $pop10
668 ; CHECK-64-NEXT: local.get $push11=, 0
669 ; CHECK-64-NEXT: br_if 0, $pop11 # 0: up to label0
670 ; CHECK-64-NEXT: # %bb.2: # %exit
671 ; CHECK-64-NEXT: end_loop
672 ; CHECK-64-NEXT: return
677 %a = phi ptr [%addr, %entry], [%b, %body]
679 br i1 %cond, label %body, label %exit
684 declare void @use_i8_star(ptr)
685 declare ptr @llvm.frameaddress(i32)
687 ; Test __builtin_frame_address(0).
688 define void @frameaddress_0() {
689 ; CHECK-32-LABEL: frameaddress_0:
690 ; CHECK-32: .functype frameaddress_0 () -> ()
691 ; CHECK-32-NEXT: .local i32
692 ; CHECK-32-NEXT: # %bb.0:
693 ; CHECK-32-NEXT: global.get $push1=, __stack_pointer
694 ; CHECK-32-NEXT: local.tee $push0=, 0, $pop1
695 ; CHECK-32-NEXT: call use_i8_star, $pop0
696 ; CHECK-32-NEXT: local.get $push2=, 0
697 ; CHECK-32-NEXT: global.set __stack_pointer, $pop2
698 ; CHECK-32-NEXT: return
700 ; CHECK-64-LABEL: frameaddress_0:
701 ; CHECK-64: .functype frameaddress_0 () -> ()
702 ; CHECK-64-NEXT: .local i64
703 ; CHECK-64-NEXT: # %bb.0:
704 ; CHECK-64-NEXT: global.get $push1=, __stack_pointer
705 ; CHECK-64-NEXT: local.tee $push0=, 0, $pop1
706 ; CHECK-64-NEXT: call use_i8_star, $pop0
707 ; CHECK-64-NEXT: local.get $push2=, 0
708 ; CHECK-64-NEXT: global.set __stack_pointer, $pop2
709 ; CHECK-64-NEXT: return
710 %t = call ptr @llvm.frameaddress(i32 0)
711 call void @use_i8_star(ptr %t)
715 ; Test __builtin_frame_address(1).
716 define void @frameaddress_1() {
717 ; CHECK-32-LABEL: frameaddress_1:
718 ; CHECK-32: .functype frameaddress_1 () -> ()
719 ; CHECK-32-NEXT: # %bb.0:
720 ; CHECK-32-NEXT: i32.const $push0=, 0
721 ; CHECK-32-NEXT: call use_i8_star, $pop0
722 ; CHECK-32-NEXT: return
724 ; CHECK-64-LABEL: frameaddress_1:
725 ; CHECK-64: .functype frameaddress_1 () -> ()
726 ; CHECK-64-NEXT: # %bb.0:
727 ; CHECK-64-NEXT: i64.const $push0=, 0
728 ; CHECK-64-NEXT: call use_i8_star, $pop0
729 ; CHECK-64-NEXT: return
730 %t = call ptr @llvm.frameaddress(i32 1)
731 call void @use_i8_star(ptr %t)
735 ; Test a stack address passed to an inline asm.
736 define void @inline_asm() {
737 ; CHECK-32-LABEL: inline_asm:
738 ; CHECK-32: .functype inline_asm () -> ()
739 ; CHECK-32-NEXT: .local i32
740 ; CHECK-32-NEXT: # %bb.0:
741 ; CHECK-32-NEXT: global.get $push0=, __stack_pointer
742 ; CHECK-32-NEXT: i32.const $push1=, 16
743 ; CHECK-32-NEXT: i32.sub $push3=, $pop0, $pop1
744 ; CHECK-32-NEXT: i32.const $push2=, 15
745 ; CHECK-32-NEXT: i32.add $push4=, $pop3, $pop2
746 ; CHECK-32-NEXT: local.set 0, $pop4
747 ; CHECK-32-NEXT: #APP
748 ; CHECK-32-NEXT: # %0
749 ; CHECK-32-NEXT: #NO_APP
750 ; CHECK-32-NEXT: return
752 ; CHECK-64-LABEL: inline_asm:
753 ; CHECK-64: .functype inline_asm () -> ()
754 ; CHECK-64-NEXT: .local i64
755 ; CHECK-64-NEXT: # %bb.0:
756 ; CHECK-64-NEXT: global.get $push0=, __stack_pointer
757 ; CHECK-64-NEXT: i64.const $push1=, 16
758 ; CHECK-64-NEXT: i64.sub $push3=, $pop0, $pop1
759 ; CHECK-64-NEXT: i64.const $push2=, 15
760 ; CHECK-64-NEXT: i64.add $push4=, $pop3, $pop2
761 ; CHECK-64-NEXT: local.set 0, $pop4
762 ; CHECK-64-NEXT: #APP
763 ; CHECK-64-NEXT: # %0
764 ; CHECK-64-NEXT: #NO_APP
765 ; CHECK-64-NEXT: return
767 call void asm sideeffect "# %0", "r"(ptr %tmp)
771 ; We optimize the format of "frame offset + operand" by folding it, but this is
772 ; only possible when that operand is an immediate. In this example it is a
773 ; global address, so we should not fold it.
774 @str = local_unnamed_addr global [3 x i8] c"abc", align 16
775 define i8 @frame_offset_with_global_address() {
776 ; CHECK-32-LABEL: frame_offset_with_global_address:
777 ; CHECK-32: .functype frame_offset_with_global_address () -> (i32)
778 ; CHECK-32-NEXT: # %bb.0:
779 ; CHECK-32-NEXT: i32.const $push0=, str
780 ; CHECK-32-NEXT: global.get $push5=, __stack_pointer
781 ; CHECK-32-NEXT: i32.const $push6=, 16
782 ; CHECK-32-NEXT: i32.sub $push9=, $pop5, $pop6
783 ; CHECK-32-NEXT: i32.const $push7=, 12
784 ; CHECK-32-NEXT: i32.add $push8=, $pop9, $pop7
785 ; CHECK-32-NEXT: i32.add $push1=, $pop0, $pop8
786 ; CHECK-32-NEXT: i32.load8_u $push2=, 0($pop1)
787 ; CHECK-32-NEXT: i32.const $push3=, 67
788 ; CHECK-32-NEXT: i32.and $push4=, $pop2, $pop3
789 ; CHECK-32-NEXT: return $pop4
791 ; CHECK-64-LABEL: frame_offset_with_global_address:
792 ; CHECK-64: .functype frame_offset_with_global_address () -> (i32)
793 ; CHECK-64-NEXT: # %bb.0:
794 ; CHECK-64-NEXT: i64.const $push1=, str
795 ; CHECK-64-NEXT: global.get $push6=, __stack_pointer
796 ; CHECK-64-NEXT: i64.const $push7=, 16
797 ; CHECK-64-NEXT: i64.sub $push10=, $pop6, $pop7
798 ; CHECK-64-NEXT: i64.const $push8=, 12
799 ; CHECK-64-NEXT: i64.add $push9=, $pop10, $pop8
800 ; CHECK-64-NEXT: i64.extend32_s $push0=, $pop9
801 ; CHECK-64-NEXT: i64.add $push2=, $pop1, $pop0
802 ; CHECK-64-NEXT: i32.load8_u $push3=, 0($pop2)
803 ; CHECK-64-NEXT: i32.const $push4=, 67
804 ; CHECK-64-NEXT: i32.and $push5=, $pop3, $pop4
805 ; CHECK-64-NEXT: return $pop5
806 %1 = alloca i8, align 4
807 %2 = ptrtoint ptr %1 to i32
808 ;; Here @str is a global address and not an immediate, so cannot be folded
809 %3 = getelementptr [3 x i8], ptr @str, i32 0, i32 %2
810 %4 = load i8, ptr %3, align 8
815 ; TODO: test over-aligned alloca