1; RUN: llc -mtriple=aarch64--linux-gnu -mattr=+sve < %s | FileCheck %s
2
3declare dso_local void @val_fn(<vscale x 4 x float>)
4declare dso_local void @ptr_fn(<vscale x 4 x float>*)
5
6; An alloca of a scalable vector shouldn't trigger stack protection.
7
8; CHECK-LABEL: call_value:
9; CHECK-NOT: mov x19, sp
10; CHECK: addvl sp, sp, #-1
11; CHECK-NOT: __stack_chk_guard
12; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl]
13define void @call_value() #0 {
14entry:
15  %x = alloca <vscale x 4 x float>, align 16
16  store <vscale x 4 x float> zeroinitializer, <vscale x 4 x float>* %x, align 16
17  %0 = load <vscale x 4 x float>, <vscale x 4 x float>* %x, align 16
18  call void @val_fn(<vscale x 4 x float> %0)
19  ret void
20}
21
22; CHECK-LABEL: call_value_strong:
23; CHECK-NOT: mov x19, sp
24; CHECK: addvl sp, sp, #-1
25; CHECK-NOT: __stack_chk_guard
26; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl]
27define void @call_value_strong() #1 {
28entry:
29  %x = alloca <vscale x 4 x float>, align 16
30  store <vscale x 4 x float> zeroinitializer, <vscale x 4 x float>* %x, align 16
31  %0 = load <vscale x 4 x float>, <vscale x 4 x float>* %x, align 16
32  call void @val_fn(<vscale x 4 x float> %0)
33  ret void
34}
35
36; Address-taking of a scalable vector should trigger stack protection only with
37; sspstrong, and the scalable vector should be be placed below the stack guard.
38
39; CHECK-LABEL: call_ptr:
40; CHECK-NOT: mov x19, sp
41; CHECK: addvl sp, sp, #-1
42; CHECK-NOT: __stack_chk_guard
43; CHECK: addvl x0, x29, #-1
44; CHECK: bl ptr_fn
45define void @call_ptr() #0 {
46entry:
47  %x = alloca <vscale x 4 x float>, align 16
48  call void @ptr_fn(<vscale x 4 x float>* %x)
49  ret void
50}
51
52; CHECK-LABEL: call_ptr_strong:
53; CHECK: mov x29, sp
54; CHECK: addvl sp, sp, #-2
55; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-1
56; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard]
57; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]]
58; CHECK-DAG: addvl x0, x29, #-2
59; CHECK: bl ptr_fn
60define void @call_ptr_strong() #1 {
61entry:
62  %x = alloca <vscale x 4 x float>, align 16
63  call void @ptr_fn(<vscale x 4 x float>* %x)
64  ret void
65}
66
67; Check that both variables are addressed in the same way
68
69; CHECK-LABEL: call_both:
70; CHECK: mov x29, sp
71; CHECK: addvl sp, sp, #-2
72; CHECK-NOT: __stack_chk_guard
73; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl]
74; CHECK: bl val_fn
75; CHECK: addvl x0, x29, #-2
76; CHECK: bl ptr_fn
77define void @call_both() #0 {
78entry:
79  %x = alloca <vscale x 4 x float>, align 16
80  %y = alloca <vscale x 4 x float>, align 16
81  store <vscale x 4 x float> zeroinitializer, <vscale x 4 x float>* %x, align 16
82  %0 = load <vscale x 4 x float>, <vscale x 4 x float>* %x, align 16
83  call void @val_fn(<vscale x 4 x float> %0)
84  call void @ptr_fn(<vscale x 4 x float>* %y)
85  ret void
86}
87
88; CHECK-LABEL: call_both_strong:
89; CHECK: mov x29, sp
90; CHECK: addvl sp, sp, #-3
91; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-1
92; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard]
93; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]]
94; CHECK-DAG: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-2, mul vl]
95; CHECK: bl val_fn
96; CHECK: addvl x0, x29, #-3
97; CHECK: bl ptr_fn
98define void @call_both_strong() #1 {
99entry:
100  %x = alloca <vscale x 4 x float>, align 16
101  %y = alloca <vscale x 4 x float>, align 16
102  store <vscale x 4 x float> zeroinitializer, <vscale x 4 x float>* %x, align 16
103  %0 = load <vscale x 4 x float>, <vscale x 4 x float>* %x, align 16
104  call void @val_fn(<vscale x 4 x float> %0)
105  call void @ptr_fn(<vscale x 4 x float>* %y)
106  ret void
107}
108
109; Pushed callee-saved regs should be above the stack guard
110
111; CHECK-LABEL: callee_save:
112; CHECK: mov x29, sp
113; CHECK: addvl sp, sp, #-18
114; CHECK: str {{z[0-9]+}}, [sp, #{{[0-9]+}}, mul vl]
115; CHECK-NOT: mov x29, sp
116; CHECK: addvl sp, sp, #-1
117; CHECK-NOT: __stack_chk_guard
118; CHECK: addvl [[REG:x[0-9]+]], x29, #-11
119; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, {{\[}}[[REG]], #-8, mul vl]
120define void @callee_save(<vscale x 4 x float> %x) #0 {
121entry:
122  %x.addr = alloca <vscale x 4 x float>, align 16
123  store <vscale x 4 x float> %x, <vscale x 4 x float>* %x.addr, align 16
124  call void @ptr_fn(<vscale x 4 x float>* %x.addr)
125  ret void
126}
127
128; CHECK-LABEL: callee_save_strong:
129; CHECK: mov x29, sp
130; CHECK: addvl sp, sp, #-18
131; CHECK: str {{z[0-9]+}}, [sp, #{{[0-9]+}}, mul vl]
132; CHECK: addvl sp, sp, #-2
133; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-19
134; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard]
135; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]]
136; CHECK-DAG: addvl [[ADDR2:x[0-9]+]], x29, #-12
137; CHECK-DAG: st1w { z0.s }, p0, {{\[}}[[ADDR2]], #-8, mul vl]
138define void @callee_save_strong(<vscale x 4 x float> %x) #1 {
139entry:
140  %x.addr = alloca <vscale x 4 x float>, align 16
141  store <vscale x 4 x float> %x, <vscale x 4 x float>* %x.addr, align 16
142  call void @ptr_fn(<vscale x 4 x float>* %x.addr)
143  ret void
144}
145
146; Check that local stack allocation works correctly both when we have a stack
147; guard but no vulnerable SVE objects, and when we do have such objects.
148
149; CHECK-LABEL: local_stack_alloc:
150; CHECK: mov x29, sp
151; CHECK: addvl sp, sp, #-2
152; CHECK: sub sp, sp, #16, lsl #12
153; CHECK: sub sp, sp, #16
154
155; Stack guard is placed below the SVE stack area
156; CHECK-DAG: ldr [[STACK_GUARD:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard]
157; CHECK-DAG: addvl [[STACK_GUARD_POS:x[0-9]+]], x29, #-2
158; CHECK-DAG: stur [[STACK_GUARD]], {{\[}}[[STACK_GUARD_POS]], #-8]
159
160; char_arr is below the stack guard
161; CHECK-DAG: sub [[CHAR_ARR_1:x[0-9]+]], x29, #16
162; CHECK-DAG: addvl [[CHAR_ARR_2:x[0-9]+]], [[CHAR_ARR_1]], #-2
163; CHECK-DAG: strb wzr, {{\[}}[[CHAR_ARR_2]]]
164
165; large1 is accessed via a virtual base register
166; CHECK-DAG: add [[LARGE1:x[0-9]+]], sp, #8, lsl #12
167; CHECK-DAG: stp x0, x0, {{\[}}[[LARGE1]]]
168
169; large2 is at the bottom of the stack
170; CHECK-DAG: stp x0, x0, [sp]
171
172; vec1 and vec2 are in the SVE stack immediately below fp
173; CHECK-DAG: addvl x0, x29, #-1
174; CHECK-DAG: bl ptr_fn
175; CHECK-DAG: addvl x0, x29, #-2
176; CHECK-DAG: bl ptr_fn
177define void @local_stack_alloc(i64 %val) #0 {
178entry:
179  %char_arr = alloca [8 x i8], align 4
180  %gep0 = getelementptr [8 x i8], [8 x i8]* %char_arr, i64 0, i64 0
181  store i8 0, i8* %gep0, align 8
182  %large1 = alloca [4096 x i64], align 8
183  %large2 = alloca [4096 x i64], align 8
184  %vec_1 = alloca <vscale x 4 x float>, align 16
185  %vec_2 = alloca <vscale x 4 x float>, align 16
186  %gep1 = getelementptr [4096 x i64], [4096 x i64]* %large1, i64 0, i64 0
187  %gep2 = getelementptr [4096 x i64], [4096 x i64]* %large1, i64 0, i64 1
188  store i64 %val, i64* %gep1, align 8
189  store i64 %val, i64* %gep2, align 8
190  %gep3 = getelementptr [4096 x i64], [4096 x i64]* %large2, i64 0, i64 0
191  %gep4 = getelementptr [4096 x i64], [4096 x i64]* %large2, i64 0, i64 1
192  store i64 %val, i64* %gep3, align 8
193  store i64 %val, i64* %gep4, align 8
194  call void @ptr_fn(<vscale x 4 x float>* %vec_1)
195  call void @ptr_fn(<vscale x 4 x float>* %vec_2)
196  ret void
197}
198
199; CHECK-LABEL: local_stack_alloc_strong:
200; CHECK: mov x29, sp
201; CHECK: addvl sp, sp, #-3
202; CHECK: sub sp, sp, #16, lsl #12
203; CHECK: sub sp, sp, #16
204
205; Stack guard is placed at the top of the SVE stack area
206; CHECK-DAG: ldr [[STACK_GUARD:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard]
207; CHECK-DAG: addvl [[STACK_GUARD_POS:x[0-9]+]], x29, #-1
208; CHECK-DAG: str [[STACK_GUARD]], {{\[}}[[STACK_GUARD_POS]]]
209
210; char_arr is below the SVE stack area
211; CHECK-DAG: addvl [[CHAR_ARR:x[0-9]+]], x29, #-3
212; CHECK-DAG: sturb wzr, {{\[}}[[CHAR_ARR]], #-8]
213
214; large1 is accessed via a virtual base register
215; CHECK-DAG: add [[LARGE1:x[0-9]+]], sp, #8, lsl #12
216; CHECK-DAG: stp x0, x0, {{\[}}[[LARGE1]], #8]
217
218; large2 is at the bottom of the stack
219; CHECK-DAG: stp x0, x0, [sp, #8]
220
221; vec1 and vec2 are in the SVE stack area below the stack guard
222; CHECK-DAG: addvl x0, x29, #-2
223; CHECK-DAG: bl ptr_fn
224; CHECK-DAG: addvl x0, x29, #-3
225; CHECK-DAG: bl ptr_fn
226define void @local_stack_alloc_strong(i64 %val) #1 {
227entry:
228  %char_arr = alloca [8 x i8], align 4
229  %gep0 = getelementptr [8 x i8], [8 x i8]* %char_arr, i64 0, i64 0
230  store i8 0, i8* %gep0, align 8
231  %large1 = alloca [4096 x i64], align 8
232  %large2 = alloca [4096 x i64], align 8
233  %vec_1 = alloca <vscale x 4 x float>, align 16
234  %vec_2 = alloca <vscale x 4 x float>, align 16
235  %gep1 = getelementptr [4096 x i64], [4096 x i64]* %large1, i64 0, i64 0
236  %gep2 = getelementptr [4096 x i64], [4096 x i64]* %large1, i64 0, i64 1
237  store i64 %val, i64* %gep1, align 8
238  store i64 %val, i64* %gep2, align 8
239  %gep3 = getelementptr [4096 x i64], [4096 x i64]* %large2, i64 0, i64 0
240  %gep4 = getelementptr [4096 x i64], [4096 x i64]* %large2, i64 0, i64 1
241  store i64 %val, i64* %gep3, align 8
242  store i64 %val, i64* %gep4, align 8
243  call void @ptr_fn(<vscale x 4 x float>* %vec_1)
244  call void @ptr_fn(<vscale x 4 x float>* %vec_2)
245  ret void
246}
247
248; A GEP addressing into a vector of <vscale x 4 x float> is in-bounds for
249; offsets up to 3, but out-of-bounds (and so triggers stack protection with
250; sspstrong) after that.
251
252; CHECK-LABEL: vector_gep_3:
253; CHECK-NOT: __stack_chk_guard
254define void @vector_gep_3() #0 {
255entry:
256  %vec = alloca <vscale x 4 x float>, align 16
257  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 3
258  store float 0.0, float* %gep, align 4
259  ret void
260}
261
262; CHECK-LABEL: vector_gep_4:
263; CHECK-NOT: __stack_chk_guard
264define void @vector_gep_4() #0 {
265entry:
266  %vec = alloca <vscale x 4 x float>, align 16
267  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 4
268  store float 0.0, float* %gep, align 4
269  ret void
270}
271
272; CHECK-LABEL: vector_gep_twice:
273; CHECK-NOT: __stack_chk_guard
274define void @vector_gep_twice() #0 {
275entry:
276  %vec = alloca <vscale x 4 x float>, align 16
277  %gep1 = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 3
278  store float 0.0, float* %gep1, align 4
279  %gep2 = getelementptr float, float* %gep1, i64 1
280  store float 0.0, float* %gep2, align 4
281  ret void
282}
283
284; CHECK-LABEL: vector_gep_n:
285; CHECK-NOT: __stack_chk_guard
286define void @vector_gep_n(i64 %n) #0 {
287entry:
288  %vec = alloca <vscale x 4 x float>, align 16
289  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 %n
290  store float 0.0, float* %gep, align 4
291  ret void
292}
293
294; CHECK-LABEL: vector_gep_3_strong:
295; CHECK-NOT: __stack_chk_guard
296define void @vector_gep_3_strong() #1 {
297entry:
298  %vec = alloca <vscale x 4 x float>, align 16
299  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 3
300  store float 0.0, float* %gep, align 4
301  ret void
302}
303
304; CHECK-LABEL: vector_gep_4_strong:
305; CHECK: __stack_chk_guard
306define void @vector_gep_4_strong(i64 %val) #1 {
307entry:
308  %vec = alloca <vscale x 4 x float>, align 16
309  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 4
310  store float 0.0, float* %gep, align 4
311  ret void
312}
313
314
315; CHECK-LABEL: vector_gep_twice_strong:
316; CHECK: __stack_chk_guard
317define void @vector_gep_twice_strong() #1 {
318entry:
319  %vec = alloca <vscale x 4 x float>, align 16
320  %gep1 = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 3
321  store float 0.0, float* %gep1, align 4
322  %gep2 = getelementptr float, float* %gep1, i64 1
323  store float 0.0, float* %gep2, align 4
324  ret void
325}
326
327; CHECK-LABEL: vector_gep_n_strong:
328; CHECK: __stack_chk_guard
329define void @vector_gep_n_strong(i64 %n) #1 {
330entry:
331  %vec = alloca <vscale x 4 x float>, align 16
332  %gep = getelementptr <vscale x 4 x float>, <vscale x 4 x float>* %vec, i64 0, i64 %n
333  store float 0.0, float* %gep, align 4
334  ret void
335}
336
337attributes #0 = { ssp "frame-pointer"="non-leaf" }
338attributes #1 = { sspstrong "frame-pointer"="non-leaf" }
339