xref: /llvm-project/llvm/test/CodeGen/WebAssembly/userstack.ll (revision ff9af4c43ad71eeba2cabe99609cfaa0fd54c1d0)
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
4
5declare void @ext_func(ptr %ptr)
6declare void @ext_func_i32(ptr %ptr)
7
8; Check that there is an extra local for the stack pointer.
9define 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
27;
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
45 %retval = alloca i32
46 store i32 0, ptr %retval
47 ret void
48}
49
50define 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
65;
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
80 %r1 = alloca i32
81 %r2 = alloca double
82 store i32 0, ptr %r1
83 store double 0.0, ptr %r2
84 ret void
85}
86
87define 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
110;
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]
134 store i32 1, ptr %r
135 %p2 = getelementptr [33 x i32], ptr %r, i32 0, i32 3
136 store i32 1, ptr %p2
137 ret void
138}
139
140define 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
166;
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
193 %r = alloca i64
194 %r2 = alloca i64
195 ; %r is at SP+8
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
200 ; %buf is at SP+16
201 store ptr %buf, ptr %addr
202 ret void
203}
204
205define 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
228;
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]
252 store i32 1, ptr %r
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
255 store i32 1, ptr %p2
256 call void @ext_func(ptr null);
257 ret void
258}
259
260define 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
284;
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)
310 ret void
311}
312
313define 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
337;
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
362 store i32 0, ptr %r
363 ret void
364}
365
366define 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
420;
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
473 %static = alloca i32
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.
489 ret void
490}
491
492declare ptr @llvm.stacksave()
493declare void @llvm.stackrestore(ptr)
494
495define 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
520;
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)
550 ret void
551}
552
553; Use of stacksave requires local SP definition even without dymamic alloca.
554; CHECK-LABEL: llvm_stacksave_noalloca:
555define void @llvm_stacksave_noalloca() noredzone {
556 ; CHECK: global.get $push[[L11:.+]]=, __stack_pointer{{$}}
557 %stack = call ptr @llvm.stacksave()
558
559 ; CHECK-NEXT: call use_i8_star, $pop[[L11:.+]]
560 call void @use_i8_star(ptr %stack)
561
562 ret void
563}
564
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.
568define 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
589;
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
612 ret void
613}
614
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
617define 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
645;
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
673entry:
674 %addr = alloca i32
675 br label %body
676body:
677 %a = phi ptr [%addr, %entry], [%b, %body]
678 store i32 1, ptr %a
679 br i1 %cond, label %body, label %exit
680exit:
681 ret void
682}
683
684declare void @use_i8_star(ptr)
685declare ptr @llvm.frameaddress(i32)
686
687; Test __builtin_frame_address(0).
688define 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
699;
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)
712  ret void
713}
714
715; Test __builtin_frame_address(1).
716define 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
723;
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)
732  ret void
733}
734
735; Test a stack address passed to an inline asm.
736define 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
751;
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
766  %tmp = alloca i8
767  call void asm sideeffect "# %0", "r"(ptr %tmp)
768  ret void
769}
770
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
775define 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
790;
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
811  %5 = and i8 %4, 67
812  ret i8 %5
813}
814
815; TODO: test over-aligned alloca
816