1 ; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
2 ; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5 target triple = "x86_64-unknown-linux-gnu"
7 @sink = global ptr null, align 8
9 declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
10 declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
11 declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
12 declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)
14 declare void @unknown_call(ptr %dest)
15 declare void @unknown_call_int(i64 %i)
16 declare ptr @retptr(ptr returned)
19 define void @LeakAddress() {
20 ; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
21 ; CHECK-NEXT: args uses:
22 ; CHECK-NEXT: allocas uses:
23 ; CHECK-NEXT: x[4]: full-set{{$}}
24 ; GLOBAL-NEXT: safe accesses:
27 %x = alloca i32, align 4
28 store ptr %x, ptr @sink, align 8
32 define void @StoreInBounds() {
33 ; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}
34 ; CHECK-NEXT: args uses:
35 ; CHECK-NEXT: allocas uses:
36 ; CHECK-NEXT: x[4]: [0,1){{$}}
37 ; GLOBAL-NEXT: safe accesses:
38 ; GLOBAL-NEXT: store i8 0, ptr %x, align 1
41 %x = alloca i32, align 4
42 store i8 0, ptr %x, align 1
46 define void @StoreInBoundsCond(i64 %i) {
47 ; CHECK-LABEL: @StoreInBoundsCond dso_preemptable{{$}}
48 ; CHECK-NEXT: args uses:
49 ; CHECK-NEXT: allocas uses:
50 ; CHECK-NEXT: x[4]: full-set{{$}}
51 ; GLOBAL-NEXT: safe accesses:
52 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
55 %x = alloca i32, align 4
56 %c1 = icmp sge i64 %i, 0
57 %c2 = icmp slt i64 %i, 4
58 br i1 %c1, label %c1.true, label %false
61 br i1 %c2, label %c2.true, label %false
64 %x2 = getelementptr i8, ptr %x, i64 %i
65 store i8 0, ptr %x2, align 1
72 define void @StoreInBoundsMinMax(i64 %i) {
73 ; CHECK-LABEL: @StoreInBoundsMinMax dso_preemptable{{$}}
74 ; CHECK-NEXT: args uses:
75 ; CHECK-NEXT: allocas uses:
76 ; CHECK-NEXT: x[4]: [0,4){{$}}
77 ; GLOBAL-NEXT: safe accesses:
78 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
81 %x = alloca i32, align 4
82 %c1 = icmp sge i64 %i, 0
83 %i1 = select i1 %c1, i64 %i, i64 0
84 %c2 = icmp slt i64 %i1, 3
85 %i2 = select i1 %c2, i64 %i1, i64 3
86 %x2 = getelementptr i8, ptr %x, i64 %i2
87 store i8 0, ptr %x2, align 1
91 define void @StoreInBounds2() {
92 ; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}
93 ; CHECK-NEXT: args uses:
94 ; CHECK-NEXT: allocas uses:
95 ; CHECK-NEXT: x[4]: [0,4){{$}}
96 ; GLOBAL-NEXT: safe accesses:
97 ; GLOBAL-NEXT: store i32 0, ptr %x, align 4
100 %x = alloca i32, align 4
101 store i32 0, ptr %x, align 4
105 define void @StoreInBounds3() {
106 ; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}
107 ; CHECK-NEXT: args uses:
108 ; CHECK-NEXT: allocas uses:
109 ; CHECK-NEXT: x[4]: [2,3){{$}}
110 ; GLOBAL-NEXT: safe accesses:
111 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
114 %x = alloca i32, align 4
115 %x2 = getelementptr i8, ptr %x, i64 2
116 store i8 0, ptr %x2, align 1
120 ; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
121 define void @StoreInBounds4() {
122 ; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}
123 ; CHECK-NEXT: args uses:
124 ; CHECK-NEXT: allocas uses:
125 ; CHECK-NEXT: x[4]: full-set{{$}}
126 ; GLOBAL-NEXT: safe accesses:
129 %x = alloca i32, align 4
130 %x1 = ptrtoint ptr %x to i64
132 %x3 = inttoptr i64 %x2 to ptr
133 store i8 0, ptr %x3, align 1
137 define void @StoreInBounds6() {
138 ; CHECK-LABEL: @StoreInBounds6 dso_preemptable{{$}}
139 ; CHECK-NEXT: args uses:
140 ; CHECK-NEXT: allocas uses:
141 ; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [0,1)){{$}}
142 ; LOCAL-NEXT: x[4]: [0,1), @retptr(arg0, [0,1)){{$}}
143 ; GLOBAL-NEXT: safe accesses:
144 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
147 %x = alloca i32, align 4
148 %x2 = call ptr @retptr(ptr %x)
149 store i8 0, ptr %x2, align 1
153 define dso_local void @WriteMinMax(ptr %p) {
154 ; CHECK-LABEL: @WriteMinMax{{$}}
155 ; CHECK-NEXT: args uses:
156 ; CHECK-NEXT: p[]: full-set
157 ; CHECK-NEXT: allocas uses:
158 ; GLOBAL-NEXT: safe accesses:
159 ; GLOBAL-NEXT: store i8 0, ptr %p1, align 1
160 ; GLOBAL-NEXT: store i8 0, ptr %p2, align 1
163 %p1 = getelementptr i8, ptr %p, i64 9223372036854775805
164 store i8 0, ptr %p1, align 1
165 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775805
166 store i8 0, ptr %p2, align 1
170 define dso_local void @WriteMax(ptr %p) {
171 ; CHECK-LABEL: @WriteMax{{$}}
172 ; CHECK-NEXT: args uses:
173 ; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)
174 ; CHECK-NEXT: allocas uses:
175 ; GLOBAL-NEXT: safe accesses:
176 ; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 false)
177 ; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 false)
180 call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 0)
181 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775807
182 call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 0)
186 define void @StoreOutOfBounds() {
187 ; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
188 ; CHECK-NEXT: args uses:
189 ; CHECK-NEXT: allocas uses:
190 ; CHECK-NEXT: x[4]: [2,6){{$}}
191 ; GLOBAL-NEXT: safe accesses:
194 %x = alloca i32, align 4
195 %x2 = getelementptr i8, ptr %x, i64 2
196 store i32 0, ptr %x2, align 1
200 define void @StoreOutOfBoundsCond(i64 %i) {
201 ; CHECK-LABEL: @StoreOutOfBoundsCond dso_preemptable{{$}}
202 ; CHECK-NEXT: args uses:
203 ; CHECK-NEXT: allocas uses:
204 ; CHECK-NEXT: x[4]: full-set{{$}}
205 ; GLOBAL-NEXT: safe accesses:
208 %x = alloca i32, align 4
209 %c1 = icmp sge i64 %i, 0
210 %c2 = icmp slt i64 %i, 5
211 br i1 %c1, label %c1.true, label %false
214 br i1 %c2, label %c2.true, label %false
217 %x2 = getelementptr i8, ptr %x, i64 %i
218 store i8 0, ptr %x2, align 1
225 define void @StoreOutOfBoundsCond2(i64 %i) {
226 ; CHECK-LABEL: @StoreOutOfBoundsCond2 dso_preemptable{{$}}
227 ; CHECK-NEXT: args uses:
228 ; CHECK-NEXT: allocas uses:
229 ; CHECK-NEXT: x[4]: full-set{{$}}
230 ; GLOBAL-NEXT: safe accesses:
233 %x = alloca i32, align 4
234 %c2 = icmp slt i64 %i, 5
235 br i1 %c2, label %c2.true, label %false
238 %x2 = getelementptr i8, ptr %x, i64 %i
239 store i8 0, ptr %x2, align 1
246 define void @StoreOutOfBounds2() {
247 ; CHECK-LABEL: @StoreOutOfBounds2 dso_preemptable{{$}}
248 ; CHECK-NEXT: args uses:
249 ; CHECK-NEXT: allocas uses:
250 ; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [2,3)){{$}}
251 ; LOCAL-NEXT: x[4]: [2,6), @retptr(arg0, [2,3)){{$}}
252 ; GLOBAL-NEXT: safe accesses:
255 %x = alloca i32, align 4
256 %x2 = getelementptr i8, ptr %x, i64 2
257 %x3 = call ptr @retptr(ptr %x2)
258 store i32 0, ptr %x3, align 1
262 ; There is no difference in load vs store handling.
263 define void @LoadInBounds() {
264 ; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}
265 ; CHECK-NEXT: args uses:
266 ; CHECK-NEXT: allocas uses:
267 ; CHECK-NEXT: x[4]: [0,1){{$}}
268 ; GLOBAL-NEXT: safe accesses:
269 ; GLOBAL-NEXT: %v = load i8, ptr %x, align 1
272 %x = alloca i32, align 4
273 %v = load i8, ptr %x, align 1
277 define void @LoadOutOfBounds() {
278 ; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}
279 ; CHECK-NEXT: args uses:
280 ; CHECK-NEXT: allocas uses:
281 ; CHECK-NEXT: x[4]: [2,6){{$}}
282 ; GLOBAL-NEXT: safe accesses:
285 %x = alloca i32, align 4
286 %x2 = getelementptr i8, ptr %x, i64 2
287 %v = load i32, ptr %x2, align 1
293 ; CHECK-LABEL: @Ret dso_preemptable{{$}}
294 ; CHECK-NEXT: args uses:
295 ; CHECK-NEXT: allocas uses:
296 ; CHECK-NEXT: x[4]: full-set{{$}}
297 ; GLOBAL-NEXT: safe accesses:
300 %x = alloca i32, align 4
301 %x2 = getelementptr i8, ptr %x, i64 2
305 declare void @Foo(ptr %p)
307 define void @DirectCall() {
308 ; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
309 ; CHECK-NEXT: args uses:
310 ; CHECK-NEXT: allocas uses:
311 ; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
312 ; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
313 ; GLOBAL-NEXT: safe accesses:
316 %x = alloca i64, align 4
317 %x2 = getelementptr i16, ptr %x, i64 1
318 call void @Foo(ptr %x2);
322 ; Indirect calls can not be analyzed (yet).
323 ; FIXME: %p[]: full-set looks invalid
324 define void @IndirectCall(ptr %p) {
325 ; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}
326 ; CHECK-NEXT: args uses:
327 ; CHECK-NEXT: p[]: full-set{{$}}
328 ; CHECK-NEXT: allocas uses:
329 ; CHECK-NEXT: x[4]: full-set{{$}}
330 ; GLOBAL-NEXT: safe accesses:
333 %x = alloca i32, align 4
334 call void %p(ptr %x);
338 define void @NonConstantOffset(i1 zeroext %z) {
339 ; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}
340 ; CHECK-NEXT: args uses:
341 ; CHECK-NEXT: allocas uses:
342 ; FIXME: SCEV can't look through selects.
343 ; CHECK-NEXT: x[4]: [0,4){{$}}
344 ; GLOBAL-NEXT: safe accesses:
345 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
348 %x = alloca i32, align 4
349 %idx = select i1 %z, i64 1, i64 2
350 %x2 = getelementptr i8, ptr %x, i64 %idx
351 store i8 0, ptr %x2, align 1
355 define void @NegativeOffset() {
356 ; CHECK-LABEL: @NegativeOffset dso_preemptable{{$}}
357 ; CHECK-NEXT: args uses:
358 ; CHECK-NEXT: allocas uses:
359 ; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}
360 ; GLOBAL-NEXT: safe accesses:
363 %x = alloca i32, i32 10, align 4
364 %x2 = getelementptr i32, ptr %x, i64 -400000000000
365 store i32 0, ptr %x2, align 1
369 define void @PossiblyNegativeOffset(i16 %z) {
370 ; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}}
371 ; CHECK-NEXT: args uses:
372 ; CHECK-NEXT: allocas uses:
373 ; CHECK-NEXT: x[40]: [-131072,131072){{$}}
374 ; GLOBAL-NEXT: safe accesses:
377 %x = alloca i32, i32 10, align 4
378 %x2 = getelementptr i32, ptr %x, i16 %z
379 store i32 0, ptr %x2, align 1
383 define void @NonConstantOffsetOOB(i1 zeroext %z) {
384 ; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}
385 ; CHECK-NEXT: args uses:
386 ; CHECK-NEXT: allocas uses:
387 ; CHECK-NEXT: x[4]: [0,6){{$}}
388 ; GLOBAL-NEXT: safe accesses:
391 %x = alloca i32, align 4
392 %idx = select i1 %z, i64 1, i64 4
393 %x2 = getelementptr i8, ptr %x, i64 %idx
394 store i8 0, ptr %x2, align 1
398 define void @ArrayAlloca() {
399 ; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}
400 ; CHECK-NEXT: args uses:
401 ; CHECK-NEXT: allocas uses:
402 ; CHECK-NEXT: x[40]: [36,40){{$}}
403 ; GLOBAL-NEXT: safe accesses:
404 ; GLOBAL-NEXT: store i32 0, ptr %x2, align 1
407 %x = alloca i32, i32 10, align 4
408 %x2 = getelementptr i8, ptr %x, i64 36
409 store i32 0, ptr %x2, align 1
413 define void @ArrayAllocaOOB() {
414 ; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}
415 ; CHECK-NEXT: args uses:
416 ; CHECK-NEXT: allocas uses:
417 ; CHECK-NEXT: x[40]: [37,41){{$}}
418 ; GLOBAL-NEXT: safe accesses:
421 %x = alloca i32, i32 10, align 4
422 %x2 = getelementptr i8, ptr %x, i64 37
423 store i32 0, ptr %x2, align 1
427 define void @DynamicAllocaUnused(i64 %size) {
428 ; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}
429 ; CHECK-NEXT: args uses:
430 ; CHECK-NEXT: allocas uses:
431 ; CHECK-NEXT: x[0]: empty-set{{$}}
432 ; GLOBAL-NEXT: safe accesses:
435 %x = alloca i32, i64 %size, align 16
439 ; Dynamic alloca with unknown size.
440 define void @DynamicAlloca(i64 %size) {
441 ; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}
442 ; CHECK-NEXT: args uses:
443 ; CHECK-NEXT: allocas uses:
444 ; CHECK-NEXT: x[0]: [0,4){{$}}
445 ; GLOBAL-NEXT: safe accesses:
448 %x = alloca i32, i64 %size, align 16
449 store i32 0, ptr %x, align 1
453 ; Dynamic alloca with limited size.
454 ; FIXME: could be proved safe. Implement.
455 define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
456 ; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}
457 ; CHECK-NEXT: args uses:
458 ; CHECK-NEXT: allocas uses:
459 ; CHECK-NEXT: x[0]: [0,4){{$}}
460 ; GLOBAL-NEXT: safe accesses:
463 %size = select i1 %z, i64 3, i64 5
464 %x = alloca i32, i64 %size, align 16
465 store i32 0, ptr %x, align 1
469 define signext i8 @SimpleLoop() {
470 ; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}
471 ; CHECK-NEXT: args uses:
472 ; CHECK-NEXT: allocas uses:
473 ; CHECK-NEXT: x[10]: [0,10){{$}}
474 ; GLOBAL-NEXT: safe accesses:
475 ; GLOBAL-NEXT: %load = load volatile i8, ptr %p.09, align 1
478 %x = alloca [10 x i8], align 1
479 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 10
483 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
484 %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]
485 %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1
486 %load = load volatile i8, ptr %p.09, align 1
487 %add = add i8 %load, %sum.010
488 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit
489 br i1 %exitcond, label %for.cond.cleanup, label %for.body
496 define signext i8 @SimpleLoopOOB() {
497 ; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}
498 ; CHECK-NEXT: args uses:
499 ; CHECK-NEXT: allocas uses:
500 ; CHECK-NEXT: x[10]: [0,11){{$}}
501 ; GLOBAL-NEXT: safe accesses:
504 %x = alloca [10 x i8], align 1
506 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 11
510 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
511 %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]
512 %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1
513 %load = load volatile i8, ptr %p.09, align 1
514 %add = add i8 %load, %sum.010
515 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit
516 br i1 %exitcond, label %for.cond.cleanup, label %for.body
522 define dso_local void @SizeCheck(i32 %sz) {
523 ; CHECK-LABEL: @SizeCheck{{$}}
524 ; CHECK-NEXT: args uses:
525 ; CHECK-NEXT: allocas uses:
526 ; CHECK-NEXT: x1[128]: [0,4294967295){{$}}
527 ; GLOBAL-NEXT: safe accesses:
530 %x1 = alloca [128 x i8], align 16
531 %cmp = icmp slt i32 %sz, 129
532 br i1 %cmp, label %if.then, label %if.end
535 call void @llvm.memset.p0.i32(ptr nonnull align 16 %x1, i8 0, i32 %sz, i1 false)
542 ; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.
543 ; This effectively disables safety analysis for scalable allocations.
544 define void @Scalable(ptr %p, ptr %unused, <vscale x 4 x i32> %v) {
545 ; CHECK-LABEL: @Scalable dso_preemptable{{$}}
546 ; CHECK-NEXT: args uses:
547 ; CHECK-NEXT: p[]: full-set
548 ; CHECK-NEXT: unused[]: empty-set
549 ; CHECK-NEXT: allocas uses:
550 ; CHECK-NEXT: x[0]: [0,1){{$}}
551 ; GLOBAL-NEXT: safe accesses:
552 ; GLOBAL-NEXT: store <vscale x 4 x i32> %v, ptr %p, align 4
555 %x = alloca <vscale x 4 x i32>, align 4
556 store i8 0, ptr %x, align 1
557 store <vscale x 4 x i32> %v, ptr %p, align 4
561 %zerosize_type = type {}
563 define void @ZeroSize(ptr %p) {
564 ; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}
565 ; CHECK-NEXT: args uses:
566 ; CHECK-NEXT: p[]: empty-set
567 ; CHECK-NEXT: allocas uses:
568 ; CHECK-NEXT: x[0]: empty-set
569 ; GLOBAL-NEXT: safe accesses:
570 ; GLOBAL-NEXT: store %zerosize_type undef, ptr %x, align 4
571 ; GLOBAL-NEXT: store %zerosize_type undef, ptr undef, align 4
572 ; GLOBAL-NEXT: load %zerosize_type, ptr %p, align
575 %x = alloca %zerosize_type, align 4
576 store %zerosize_type undef, ptr %x, align 4
577 store %zerosize_type undef, ptr undef, align 4
578 %val = load %zerosize_type, ptr %p, align 4
582 define void @OperandBundle() {
583 ; CHECK-LABEL: @OperandBundle dso_preemptable{{$}}
584 ; CHECK-NEXT: args uses:
585 ; CHECK-NEXT: allocas uses:
586 ; CHECK-NEXT: a[4]: full-set
587 ; GLOBAL-NEXT: safe accesses:
590 %a = alloca i32, align 4
591 call void @LeakAddress() ["unknown"(ptr %a)]
595 define void @ByVal(ptr byval(i16) %p) {
596 ; CHECK-LABEL: @ByVal dso_preemptable{{$}}
597 ; CHECK-NEXT: args uses:
598 ; CHECK-NEXT: allocas uses:
599 ; GLOBAL-NEXT: safe accesses:
605 define void @TestByVal() {
606 ; CHECK-LABEL: @TestByVal dso_preemptable{{$}}
607 ; CHECK-NEXT: args uses:
608 ; CHECK-NEXT: allocas uses:
609 ; CHECK-NEXT: x[2]: [0,2)
610 ; CHECK-NEXT: y[8]: [0,2)
611 ; GLOBAL-NEXT: safe accesses:
612 ; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %x)
613 ; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %y)
616 %x = alloca i16, align 4
617 call void @ByVal(ptr byval(i16) %x)
619 %y = alloca i64, align 4
620 call void @ByVal(ptr byval(i16) %y)
625 declare void @ByValArray(ptr byval([100000 x i64]) %p)
627 define void @TestByValArray() {
628 ; CHECK-LABEL: @TestByValArray dso_preemptable{{$}}
629 ; CHECK-NEXT: args uses:
630 ; CHECK-NEXT: allocas uses:
631 ; CHECK-NEXT: z[800000]: [500000,1300000)
632 ; GLOBAL-NEXT: safe accesses:
635 %z = alloca [100000 x i64], align 4
636 %z2 = getelementptr i8, ptr %z, i64 500000
637 call void @ByValArray(ptr byval([100000 x i64]) %z2)
641 define dso_local i8 @LoadMinInt64(ptr %p) {
642 ; CHECK-LABEL: @LoadMinInt64{{$}}
643 ; CHECK-NEXT: args uses:
644 ; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}
645 ; CHECK-NEXT: allocas uses:
646 ; GLOBAL-NEXT: safe accesses:
647 ; GLOBAL-NEXT: load i8, ptr %p2, align 1
649 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775808
650 %v = load i8, ptr %p2, align 1
654 define void @Overflow() {
655 ; CHECK-LABEL: @Overflow dso_preemptable{{$}}
656 ; CHECK-NEXT: args uses:
657 ; CHECK-NEXT: allocas uses:
658 ; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
659 ; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
660 ; GLOBAL-NEXT: safe accesses:
663 %x = alloca i8, align 4
664 %x2 = getelementptr i8, ptr %x, i64 -9223372036854775808
665 %v = call i8 @LoadMinInt64(ptr %x2)
669 define void @DeadBlock(ptr %p) {
670 ; CHECK-LABEL: @DeadBlock dso_preemptable{{$}}
671 ; CHECK-NEXT: args uses:
672 ; CHECK-NEXT: p[]: empty-set{{$}}
673 ; CHECK-NEXT: allocas uses:
674 ; CHECK-NEXT: x[1]: empty-set{{$}}
675 ; GLOBAL-NEXT: safe accesses:
676 ; GLOBAL-NEXT: store i8 5, ptr %x
677 ; GLOBAL-NEXT: store i64 -5, ptr %p
680 %x = alloca i8, align 4
692 define void @LifeNotStarted() {
693 ; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}
694 ; CHECK-NEXT: args uses:
695 ; CHECK-NEXT: allocas uses:
696 ; CHECK: x[1]: full-set{{$}}
697 ; CHECK: y[1]: full-set{{$}}
698 ; CHECK: z[1]: full-set{{$}}
699 ; GLOBAL-NEXT: safe accesses:
702 %x = alloca i8, align 4
703 %y = alloca i8, align 4
704 %z = alloca i8, align 4
708 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
710 call void @llvm.lifetime.start.p0(i64 1, ptr %x)
711 call void @llvm.lifetime.start.p0(i64 1, ptr %y)
712 call void @llvm.lifetime.start.p0(i64 1, ptr %z)
717 define void @LifeOK() {
718 ; CHECK-LABEL: @LifeOK dso_preemptable{{$}}
719 ; CHECK-NEXT: args uses:
720 ; CHECK-NEXT: allocas uses:
721 ; CHECK: x[1]: [0,1){{$}}
722 ; CHECK: y[1]: [0,1){{$}}
723 ; CHECK: z[1]: [0,1){{$}}
724 ; GLOBAL-NEXT: safe accesses:
725 ; GLOBAL-NEXT: store i8 5, ptr %x
726 ; GLOBAL-NEXT: %n = load i8, ptr %y
727 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
730 %x = alloca i8, align 4
731 %y = alloca i8, align 4
732 %z = alloca i8, align 4
734 call void @llvm.lifetime.start.p0(i64 1, ptr %x)
735 call void @llvm.lifetime.start.p0(i64 1, ptr %y)
736 call void @llvm.lifetime.start.p0(i64 1, ptr %z)
740 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
745 define void @LifeEnded() {
746 ; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}
747 ; CHECK-NEXT: args uses:
748 ; CHECK-NEXT: allocas uses:
749 ; CHECK: x[1]: full-set{{$}}
750 ; CHECK: y[1]: full-set{{$}}
751 ; CHECK: z[1]: full-set{{$}}
752 ; GLOBAL-NEXT: safe accesses:
755 %x = alloca i8, align 4
756 %y = alloca i8, align 4
757 %z = alloca i8, align 4
759 call void @llvm.lifetime.start.p0(i64 1, ptr %x)
760 call void @llvm.lifetime.start.p0(i64 1, ptr %y)
761 call void @llvm.lifetime.start.p0(i64 1, ptr %z)
763 call void @llvm.lifetime.end.p0(i64 1, ptr %x)
764 call void @llvm.lifetime.end.p0(i64 1, ptr %y)
765 call void @llvm.lifetime.end.p0(i64 1, ptr %z)
769 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
774 define void @TwoAllocasOK() {
775 ; CHECK-LABEL: @TwoAllocasOK
776 ; CHECK-NEXT: args uses:
777 ; CHECK-NEXT: allocas uses:
778 ; CHECK: a[4]: [0,1){{$}}
779 ; CHECK: y[1]: [0,1){{$}}
780 ; GLOBAL-NEXT: safe accesses:
781 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)
784 %a = alloca i32, align 4
785 %y = alloca i8, align 4
786 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)
790 define void @TwoAllocasOOBDest() {
791 ; CHECK-LABEL: @TwoAllocasOOBDest
792 ; CHECK-NEXT: args uses:
793 ; CHECK-NEXT: allocas uses:
794 ; CHECK: a[4]: [0,4){{$}}
795 ; CHECK: y[1]: [0,4){{$}}
796 ; GLOBAL-NEXT: safe accesses:
799 %a = alloca i32, align 4
800 %y = alloca i8, align 4
801 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 4, i1 false)
805 define void @TwoAllocasOOBSource() {
806 ; CHECK-LABEL: @TwoAllocasOOBSource
807 ; CHECK-NEXT: args uses:
808 ; CHECK-NEXT: allocas uses:
809 ; CHECK: a[4]: [0,4){{$}}
810 ; CHECK: y[1]: [0,4){{$}}
811 ; GLOBAL-NEXT: safe accesses:
814 %a = alloca i32, align 4
815 %y = alloca i8, align 4
816 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %y, i32 4, i1 false)
820 define void @TwoAllocasOOBBoth() {
821 ; CHECK-LABEL: @TwoAllocasOOBBoth
822 ; CHECK-NEXT: args uses:
823 ; CHECK-NEXT: allocas uses:
824 ; CHECK: a[4]: [0,5){{$}}
825 ; CHECK: y[1]: [0,5){{$}}
826 ; GLOBAL-NEXT: safe accesses:
829 %a = alloca i32, align 4
830 %y = alloca i8, align 4
831 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 5, i1 false)
835 define void @MixedAccesses() {
836 ; CHECK-LABEL: @MixedAccesses
837 ; CHECK-NEXT: args uses:
838 ; CHECK-NEXT: allocas uses:
839 ; CHECK: a[4]: [0,5){{$}}
840 ; GLOBAL-NEXT: safe accesses:
841 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
844 %a = alloca i32, align 4
845 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 5, i1 false)
846 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
850 define void @MixedAccesses2() {
851 ; CHECK-LABEL: @MixedAccesses2
852 ; CHECK-NEXT: args uses:
853 ; CHECK-NEXT: allocas uses:
854 ; CHECK: a[4]: [0,8){{$}}
855 ; GLOBAL-NEXT: safe accesses:
856 ; GLOBAL-NEXT: load i32, ptr %a, align 4
859 %a = alloca i32, align 4
860 %n1 = load i64, ptr %a, align 4
861 %n2 = load i32, ptr %a, align 4
865 define void @MixedAccesses3(ptr %func) {
866 ; CHECK-LABEL: @MixedAccesses3
867 ; CHECK-NEXT: args uses:
868 ; CHECK-NEXT: func[]: full-set
869 ; CHECK-NEXT: allocas uses:
870 ; CHECK: a[4]: full-set{{$}}
871 ; GLOBAL-NEXT: safe accesses:
872 ; GLOBAL-NEXT: load i32, ptr %a, align 4
875 %a = alloca i32, align 4
876 %n2 = load i32, ptr %a, align 4
877 call void %func(ptr %a)
881 define void @MixedAccesses4() {
882 ; CHECK-LABEL: @MixedAccesses4
883 ; CHECK-NEXT: args uses:
884 ; CHECK-NEXT: allocas uses:
885 ; CHECK: a[4]: full-set{{$}}
886 ; CHECK: a1[8]: [0,8){{$}}
887 ; GLOBAL-NEXT: safe accesses:
888 ; GLOBAL-NEXT: load i32, ptr %a, align 4
891 %a = alloca i32, align 4
892 %a1 = alloca ptr, align 4
893 %n2 = load i32, ptr %a, align 4
894 store ptr %a, ptr %a1
898 define ptr @MixedAccesses5(i1 %x, ptr %y) {
899 ; CHECK-LABEL: @MixedAccesses5
900 ; CHECK-NEXT: args uses:
901 ; CHECK: y[]: full-set
902 ; CHECK-NEXT: allocas uses:
903 ; CHECK: a[4]: full-set{{$}}
904 ; GLOBAL-NEXT: safe accesses:
905 ; GLOBAL-NEXT: load i32, ptr %a, align 4
908 %a = alloca i32, align 4
909 br i1 %x, label %tlabel, label %flabel
911 %n = load i32, ptr %a, align 4
917 define void @MixedAccesses6(ptr %arg) {
918 ; CHECK-LABEL: @MixedAccesses6
919 ; CHECK-NEXT: args uses:
920 ; CHECK-NEXT: arg[]: [0,4)
921 ; CHECK-NEXT: allocas uses:
923 ; GLOBAL-NEXT: safe accesses:
924 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
927 %a = alloca i32, align 4
928 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
932 define void @MixedAccesses7(i1 %cond, ptr %arg) {
933 ; SECV doesn't support select, so we consider this non-stack-safe, even through
936 ; CHECK-LABEL: @MixedAccesses7
937 ; CHECK-NEXT: args uses:
938 ; CHECK-NEXT: arg[]: full-set
939 ; CHECK-NEXT: allocas uses:
940 ; CHECK: a[4]: full-set
941 ; GLOBAL-NEXT: safe accesses:
944 %a = alloca i32, align 4
945 %x1 = select i1 %cond, ptr %arg, ptr %a
946 call void @llvm.memcpy.p0.p0.i32(ptr %x1, ptr %arg, i32 4, i1 false)
950 define void @NoStackAccess(ptr %arg1, ptr %arg2) {
951 ; CHECK-LABEL: @NoStackAccess
952 ; CHECK-NEXT: args uses:
953 ; CHECK-NEXT: arg1[]: [0,4)
954 ; CHECK-NEXT: arg2[]: [0,4)
955 ; CHECK-NEXT: allocas uses:
956 ; CHECK: a[4]: empty-set{{$}}
957 ; GLOBAL-NEXT: safe accesses:
958 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)
961 %a = alloca i32, align 4
962 call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)
966 define void @DoubleLifetime() {
967 ; CHECK-LABEL: @DoubleLifetime
968 ; CHECK-NEXT: args uses:
969 ; CHECK-NEXT: allocas uses:
970 ; CHECK: a[4]: full-set{{$}}
971 ; GLOBAL-NEXT: safe accesses:
972 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
975 %a = alloca i32, align 4
976 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
977 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
978 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 true)
980 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
981 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
982 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
986 define void @DoubleLifetime2() {
987 ; CHECK-LABEL: @DoubleLifetime2
988 ; CHECK-NEXT: args uses:
989 ; CHECK-NEXT: allocas uses:
990 ; CHECK: a[4]: full-set{{$}}
991 ; GLOBAL-NEXT: safe accesses:
992 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
995 %a = alloca i32, align 4
996 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
997 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
998 %n = load i32, ptr %a
1000 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1001 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1002 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1006 define void @DoubleLifetime3() {
1007 ; CHECK-LABEL: @DoubleLifetime3
1008 ; CHECK-NEXT: args uses:
1009 ; CHECK-NEXT: allocas uses:
1010 ; CHECK: a[4]: full-set{{$}}
1011 ; GLOBAL-NEXT: safe accesses:
1012 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1015 %a = alloca i32, align 4
1016 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1017 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1020 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1021 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1022 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1026 define void @DoubleLifetime4() {
1027 ; CHECK-LABEL: @DoubleLifetime4
1028 ; CHECK-NEXT: args uses:
1029 ; CHECK-NEXT: allocas uses:
1030 ; CHECK: a[4]: full-set{{$}}
1031 ; GLOBAL-NEXT: safe accesses:
1032 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1035 %a = alloca i32, align 4
1036 call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1037 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1038 call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1039 call void @unknown_call(ptr %a)
1043 define void @Cmpxchg4Arg(ptr %p) {
1044 ; CHECK-LABEL: @Cmpxchg4Arg
1045 ; CHECK-NEXT: args uses:
1046 ; CHECK-NEXT: p[]: [0,4){{$}}
1047 ; CHECK-NEXT: allocas uses:
1048 ; GLOBAL-NEXT: safe accesses:
1049 ; GLOBAL-NEXT: cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1
1052 cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1
1056 define void @AtomicRMW4Arg(ptr %p) {
1057 ; CHECK-LABEL: @AtomicRMW4Arg
1058 ; CHECK-NEXT: args uses:
1059 ; CHECK-NEXT: p[]: [0,4){{$}}
1060 ; CHECK-NEXT: allocas uses:
1061 ; GLOBAL-NEXT: safe accesses:
1062 ; GLOBAL-NEXT: atomicrmw add ptr %p, i32 1 monotonic, align 1
1065 atomicrmw add ptr %p, i32 1 monotonic, align 1
1069 define void @Cmpxchg4Alloca() {
1070 ; CHECK-LABEL: @Cmpxchg4Alloca
1071 ; CHECK-NEXT: args uses:
1072 ; CHECK-NEXT: allocas uses:
1073 ; CHECK-NEXT: x[4]: [0,4){{$}}
1074 ; GLOBAL-NEXT: safe accesses:
1075 ; GLOBAL-NEXT: cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1
1078 %x = alloca i32, align 4
1079 cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1
1083 define void @AtomicRMW4Alloca() {
1084 ; CHECK-LABEL: @AtomicRMW4Alloca
1085 ; CHECK-NEXT: args uses:
1086 ; CHECK-NEXT: allocas uses:
1087 ; CHECK-NEXT: x[4]: [0,4){{$}}
1088 ; GLOBAL-NEXT: safe accesses:
1089 ; GLOBAL-NEXT: atomicrmw add ptr %x, i32 1 monotonic, align 1
1092 %x = alloca i32, align 4
1093 atomicrmw add ptr %x, i32 1 monotonic, align 1
1097 define void @StoreArg(ptr %p) {
1098 ; CHECK-LABEL: @StoreArg
1099 ; CHECK-NEXT: args uses:
1100 ; CHECK-NEXT: p[]: [0,4){{$}}
1101 ; CHECK-NEXT: allocas uses:
1102 ; GLOBAL-NEXT: safe accesses:
1103 ; GLOBAL-NEXT: store i32 1, ptr %p
1110 define void @NonPointer(ptr %p) {
1111 ; CHECK-LABEL: @NonPointer
1112 ; CHECK-NEXT: args uses:
1113 ; LOCAL-NEXT: p[]: empty-set, @unknown_call_int(arg0, full-set)
1114 ; GLOBAL-NEXT: p[]: full-set, @unknown_call_int(arg0, full-set)
1115 ; CHECK-NEXT: allocas uses:
1116 ; GLOBAL-NEXT: safe accesses:
1118 %int = ptrtoint ptr %p to i64
1119 call void @unknown_call_int(i64 %int)
1123 @ifunc = dso_local ifunc i64 (ptr), ptr @ifunc_resolver
1125 define dso_local void @CallIfunc(ptr noundef %uaddr) local_unnamed_addr {
1126 ; CHECK-LABEL: @CallIfunc
1127 ; CHECK-NEXT: args uses:
1128 ; CHECK-NEXT: uaddr[]: full-set
1130 tail call i64 @ifunc(ptr noundef %uaddr)
1134 define dso_local ptr @ifunc_resolver() {
1139 declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
1140 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)