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(ptr) 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, ptr %x, align 16 17 %0 = load <vscale x 4 x float>, ptr %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, ptr %x, align 16 31 %0 = load <vscale x 4 x float>, ptr %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(ptr %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(ptr %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, ptr %x, align 16 82 %0 = load <vscale x 4 x float>, ptr %x, align 16 83 call void @val_fn(<vscale x 4 x float> %0) 84 call void @ptr_fn(ptr %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, ptr %x, align 16 103 %0 = load <vscale x 4 x float>, ptr %x, align 16 104 call void @val_fn(<vscale x 4 x float> %0) 105 call void @ptr_fn(ptr %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, ptr %x.addr, align 16 124 call void @ptr_fn(ptr %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, ptr %x.addr, align 16 142 call void @ptr_fn(ptr %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: sub sp, sp, #16, lsl #12 152; CHECK: sub sp, sp, #16 153; CHECK: addvl sp, sp, #-2 154 155; Stack guard is placed below the SVE stack area (and above all fixed-width objects) 156; CHECK-DAG: add [[STACK_GUARD_SPILL_PART_LOC:x[0-9]+]], sp, #8, lsl #12 157; CHECK-DAG: add [[STACK_GUARD_SPILL_PART_LOC]], [[STACK_GUARD_SPILL_PART_LOC]], #16 158; CHECK-DAG: ldr [[STACK_GUARD:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard] 159; CHECK-DAG: str [[STACK_GUARD]], [[[STACK_GUARD_SPILL_PART_LOC]], #32760] 160 161; char_arr is below the stack guard 162; CHECK-DAG: add [[CHAR_ARR_LOC:x[0-9]+]], sp, #16, lsl #12 163; CHECK-DAG: strb wzr, [[[CHAR_ARR_LOC]]] 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], ptr %char_arr, i64 0, i64 0 181 store i8 0, ptr %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], ptr %large1, i64 0, i64 0 187 %gep2 = getelementptr [4096 x i64], ptr %large1, i64 0, i64 1 188 store i64 %val, ptr %gep1, align 8 189 store i64 %val, ptr %gep2, align 8 190 %gep3 = getelementptr [4096 x i64], ptr %large2, i64 0, i64 0 191 %gep4 = getelementptr [4096 x i64], ptr %large2, i64 0, i64 1 192 store i64 %val, ptr %gep3, align 8 193 store i64 %val, ptr %gep4, align 8 194 call void @ptr_fn(ptr %vec_1) 195 call void @ptr_fn(ptr %vec_2) 196 ret void 197} 198 199; CHECK-LABEL: local_stack_alloc_strong: 200; CHECK: mov x29, sp 201; CHECK: sub sp, sp, #16, lsl #12 202; CHECK: sub sp, sp, #16 203; CHECK: addvl sp, sp, #-3 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: add [[CHAR_ARR:x[0-9]+]], sp, #15, lsl #12 // =61440 212; CHECK-DAG: add [[CHAR_ARR]], [[CHAR_ARR]], #9 213; CHECK-DAG: strb wzr, [[[CHAR_ARR]], #4095] 214 215; large1 is accessed via a virtual base register 216; CHECK-DAG: add [[LARGE1:x[0-9]+]], sp, #8, lsl #12 217; CHECK-DAG: stp x0, x0, [[[LARGE1]], #8] 218 219; large2 is at the bottom of the stack 220; CHECK-DAG: stp x0, x0, [sp, #8] 221 222; vec1 and vec2 are in the SVE stack area below the stack guard 223; CHECK-DAG: addvl x0, x29, #-2 224; CHECK-DAG: bl ptr_fn 225; CHECK-DAG: addvl x0, x29, #-3 226; CHECK-DAG: bl ptr_fn 227define void @local_stack_alloc_strong(i64 %val) #1 { 228entry: 229 %char_arr = alloca [8 x i8], align 4 230 %gep0 = getelementptr [8 x i8], ptr %char_arr, i64 0, i64 0 231 store i8 0, ptr %gep0, align 8 232 %large1 = alloca [4096 x i64], align 8 233 %large2 = alloca [4096 x i64], align 8 234 %vec_1 = alloca <vscale x 4 x float>, align 16 235 %vec_2 = alloca <vscale x 4 x float>, align 16 236 %gep1 = getelementptr [4096 x i64], ptr %large1, i64 0, i64 0 237 %gep2 = getelementptr [4096 x i64], ptr %large1, i64 0, i64 1 238 store i64 %val, ptr %gep1, align 8 239 store i64 %val, ptr %gep2, align 8 240 %gep3 = getelementptr [4096 x i64], ptr %large2, i64 0, i64 0 241 %gep4 = getelementptr [4096 x i64], ptr %large2, i64 0, i64 1 242 store i64 %val, ptr %gep3, align 8 243 store i64 %val, ptr %gep4, align 8 244 call void @ptr_fn(ptr %vec_1) 245 call void @ptr_fn(ptr %vec_2) 246 ret void 247} 248 249; A GEP addressing into a vector of <vscale x 4 x float> is in-bounds for 250; offsets up to 3, but out-of-bounds (and so triggers stack protection with 251; sspstrong) after that. 252 253; CHECK-LABEL: vector_gep_3: 254; CHECK-NOT: __stack_chk_guard 255define void @vector_gep_3() #0 { 256entry: 257 %vec = alloca <vscale x 4 x float>, align 16 258 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 3 259 store float 0.0, ptr %gep, align 4 260 ret void 261} 262 263; CHECK-LABEL: vector_gep_4: 264; CHECK-NOT: __stack_chk_guard 265define void @vector_gep_4() #0 { 266entry: 267 %vec = alloca <vscale x 4 x float>, align 16 268 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 4 269 store float 0.0, ptr %gep, align 4 270 ret void 271} 272 273; CHECK-LABEL: vector_gep_twice: 274; CHECK-NOT: __stack_chk_guard 275define void @vector_gep_twice() #0 { 276entry: 277 %vec = alloca <vscale x 4 x float>, align 16 278 %gep1 = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 3 279 store float 0.0, ptr %gep1, align 4 280 %gep2 = getelementptr float, ptr %gep1, i64 1 281 store float 0.0, ptr %gep2, align 4 282 ret void 283} 284 285; CHECK-LABEL: vector_gep_n: 286; CHECK-NOT: __stack_chk_guard 287define void @vector_gep_n(i64 %n) #0 { 288entry: 289 %vec = alloca <vscale x 4 x float>, align 16 290 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 %n 291 store float 0.0, ptr %gep, align 4 292 ret void 293} 294 295; CHECK-LABEL: vector_gep_3_strong: 296; CHECK-NOT: __stack_chk_guard 297define void @vector_gep_3_strong() #1 { 298entry: 299 %vec = alloca <vscale x 4 x float>, align 16 300 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 3 301 store float 0.0, ptr %gep, align 4 302 ret void 303} 304 305; CHECK-LABEL: vector_gep_4_strong: 306; CHECK: __stack_chk_guard 307define void @vector_gep_4_strong(i64 %val) #1 { 308entry: 309 %vec = alloca <vscale x 4 x float>, align 16 310 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 4 311 store float 0.0, ptr %gep, align 4 312 ret void 313} 314 315 316; CHECK-LABEL: vector_gep_twice_strong: 317; CHECK: __stack_chk_guard 318define void @vector_gep_twice_strong() #1 { 319entry: 320 %vec = alloca <vscale x 4 x float>, align 16 321 %gep1 = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 3 322 store float 0.0, ptr %gep1, align 4 323 %gep2 = getelementptr float, ptr %gep1, i64 1 324 store float 0.0, ptr %gep2, align 4 325 ret void 326} 327 328; CHECK-LABEL: vector_gep_n_strong: 329; CHECK: __stack_chk_guard 330define void @vector_gep_n_strong(i64 %n) #1 { 331entry: 332 %vec = alloca <vscale x 4 x float>, align 16 333 %gep = getelementptr <vscale x 4 x float>, ptr %vec, i64 0, i64 %n 334 store float 0.0, ptr %gep, align 4 335 ret void 336} 337 338attributes #0 = { ssp "frame-pointer"="non-leaf" } 339attributes #1 = { sspstrong "frame-pointer"="non-leaf" } 340 341!llvm.module.flags = !{!0} 342!0 = !{i32 7, !"direct-access-external-data", i32 1} 343