xref: /llvm-project/llvm/test/Analysis/StackSafetyAnalysis/local.ll (revision 318bdd0aeb721c8e9bd67101ac6641e5f9d990f2)
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
3
4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5target triple = "x86_64-unknown-linux-gnu"
6
7@sink = global ptr null, align 8
8
9declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
10declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
11declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
12declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)
13
14declare void @unknown_call(ptr %dest)
15declare void @unknown_call_int(i64 %i)
16declare ptr @retptr(ptr returned)
17
18; Address leaked.
19define 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:
25; CHECK-EMPTY:
26entry:
27  %x = alloca i32, align 4
28  store ptr %x, ptr @sink, align 8
29  ret void
30}
31
32define 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
39; CHECK-EMPTY:
40entry:
41  %x = alloca i32, align 4
42  store i8 0, ptr %x, align 1
43  ret void
44}
45
46define 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
53; CHECK-EMPTY:
54entry:
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
59
60c1.true:
61  br i1 %c2, label %c2.true, label %false
62
63c2.true:
64  %x2 = getelementptr i8, ptr %x, i64 %i
65  store i8 0, ptr %x2, align 1
66  br label %false
67
68false:
69  ret void
70}
71
72define 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
79; CHECK-EMPTY:
80entry:
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
88  ret void
89}
90
91define 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
98; CHECK-EMPTY:
99entry:
100  %x = alloca i32, align 4
101  store i32 0, ptr %x, align 4
102  ret void
103}
104
105define 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
112; CHECK-EMPTY:
113entry:
114  %x = alloca i32, align 4
115  %x2 = getelementptr i8, ptr %x, i64 2
116  store i8 0, ptr %x2, align 1
117  ret void
118}
119
120; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
121define 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:
127; CHECK-EMPTY:
128entry:
129  %x = alloca i32, align 4
130  %x1 = ptrtoint ptr %x to i64
131  %x2 = add i64 %x1, 2
132  %x3 = inttoptr i64 %x2 to ptr
133  store i8 0, ptr %x3, align 1
134  ret void
135}
136
137define 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
145; CHECK-EMPTY:
146entry:
147  %x = alloca i32, align 4
148  %x2 = call ptr @retptr(ptr %x)
149  store i8 0, ptr %x2, align 1
150  ret void
151}
152
153define 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
161; CHECK-EMPTY:
162entry:
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
167  ret void
168}
169
170define 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)
178; CHECK-EMPTY:
179entry:
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)
183  ret void
184}
185
186define 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:
192; CHECK-EMPTY:
193entry:
194  %x = alloca i32, align 4
195  %x2 = getelementptr i8, ptr %x, i64 2
196  store i32 0, ptr %x2, align 1
197  ret void
198}
199
200define 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:
206; CHECK-EMPTY:
207entry:
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
212
213c1.true:
214  br i1 %c2, label %c2.true, label %false
215
216c2.true:
217  %x2 = getelementptr i8, ptr %x, i64 %i
218  store i8 0, ptr %x2, align 1
219  br label %false
220
221false:
222  ret void
223}
224
225define 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:
231; CHECK-EMPTY:
232entry:
233  %x = alloca i32, align 4
234  %c2 = icmp slt i64 %i, 5
235  br i1 %c2, label %c2.true, label %false
236
237c2.true:
238  %x2 = getelementptr i8, ptr %x, i64 %i
239  store i8 0, ptr %x2, align 1
240  br label %false
241
242false:
243  ret void
244}
245
246define 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:
253; CHECK-EMPTY:
254entry:
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
259  ret void
260}
261
262; There is no difference in load vs store handling.
263define 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
270; CHECK-EMPTY:
271entry:
272  %x = alloca i32, align 4
273  %v = load i8, ptr %x, align 1
274  ret void
275}
276
277define 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:
283; CHECK-EMPTY:
284entry:
285  %x = alloca i32, align 4
286  %x2 = getelementptr i8, ptr %x, i64 2
287  %v = load i32, ptr %x2, align 1
288  ret void
289}
290
291; Leak through ret.
292define ptr @Ret() {
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:
298; CHECK-EMPTY:
299entry:
300  %x = alloca i32, align 4
301  %x2 = getelementptr i8, ptr %x, i64 2
302  ret ptr %x2
303}
304
305declare void @Foo(ptr %p)
306
307define 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:
314; CHECK-EMPTY:
315entry:
316  %x = alloca i64, align 4
317  %x2 = getelementptr i16, ptr %x, i64 1
318  call void @Foo(ptr %x2);
319  ret void
320}
321
322; Indirect calls can not be analyzed (yet).
323; FIXME: %p[]: full-set looks invalid
324define 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:
331; CHECK-EMPTY:
332entry:
333  %x = alloca i32, align 4
334  call void %p(ptr %x);
335  ret void
336}
337
338define 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
346; CHECK-EMPTY:
347entry:
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
352  ret void
353}
354
355define 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:
361; CHECK-EMPTY:
362entry:
363  %x = alloca i32, i32 10, align 4
364  %x2 = getelementptr i32, ptr %x, i64 -400000000000
365  store i32 0, ptr %x2, align 1
366  ret void
367}
368
369define 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:
375; CHECK-EMPTY:
376entry:
377  %x = alloca i32, i32 10, align 4
378  %x2 = getelementptr i32, ptr %x, i16 %z
379  store i32 0, ptr %x2, align 1
380  ret void
381}
382
383define 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:
389; CHECK-EMPTY:
390entry:
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
395  ret void
396}
397
398define 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
405; CHECK-EMPTY:
406entry:
407  %x = alloca i32, i32 10, align 4
408  %x2 = getelementptr i8, ptr %x, i64 36
409  store i32 0, ptr %x2, align 1
410  ret void
411}
412
413define 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:
419; CHECK-EMPTY:
420entry:
421  %x = alloca i32, i32 10, align 4
422  %x2 = getelementptr i8, ptr %x, i64 37
423  store i32 0, ptr %x2, align 1
424  ret void
425}
426
427define 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:
433; CHECK-EMPTY:
434entry:
435  %x = alloca i32, i64 %size, align 16
436  ret void
437}
438
439; Dynamic alloca with unknown size.
440define 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:
446; CHECK-EMPTY:
447entry:
448  %x = alloca i32, i64 %size, align 16
449  store i32 0, ptr %x, align 1
450  ret void
451}
452
453; Dynamic alloca with limited size.
454; FIXME: could be proved safe. Implement.
455define 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:
461; CHECK-EMPTY:
462entry:
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
466  ret void
467}
468
469define 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
476; CHECK-EMPTY:
477entry:
478  %x = alloca [10 x i8], align 1
479  %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 10
480  br label %for.body
481
482for.body:
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
490
491for.cond.cleanup:
492  ret i8 %add
493}
494
495; OOB in a loop.
496define 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:
502; CHECK-EMPTY:
503entry:
504  %x = alloca [10 x i8], align 1
505 ; 11 iterations
506  %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 11
507  br label %for.body
508
509for.body:
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
517
518for.cond.cleanup:
519  ret i8 %add
520}
521
522define 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:
528; CHECK-EMPTY:
529entry:
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
533
534if.then:
535  call void @llvm.memset.p0.i32(ptr nonnull align 16 %x1, i8 0, i32 %sz, i1 false)
536  br label %if.end
537
538if.end:
539  ret void
540}
541
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.
544define 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
553; CHECK-EMPTY:
554entry:
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
558  ret void
559}
560
561%zerosize_type = type {}
562
563define 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
573; CHECK-EMPTY:
574entry:
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
579  ret void
580}
581
582define 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:
588; CHECK-EMPTY:
589entry:
590  %a = alloca i32, align 4
591  call void @LeakAddress() ["unknown"(ptr %a)]
592  ret void
593}
594
595define 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:
600  ; CHECK-EMPTY:
601entry:
602  ret void
603}
604
605define 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)
614; CHECK-EMPTY:
615entry:
616  %x = alloca i16, align 4
617  call void @ByVal(ptr byval(i16) %x)
618
619  %y = alloca i64, align 4
620  call void @ByVal(ptr byval(i16) %y)
621
622  ret void
623}
624
625declare void @ByValArray(ptr byval([100000 x i64]) %p)
626
627define 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:
633; CHECK-EMPTY:
634entry:
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)
638  ret void
639}
640
641define 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
648  ; CHECK-EMPTY:
649  %p2 = getelementptr i8, ptr %p, i64 -9223372036854775808
650  %v = load i8, ptr %p2, align 1
651  ret i8 %v
652}
653
654define 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:
661; CHECK-EMPTY:
662entry:
663  %x = alloca i8, align 4
664  %x2 = getelementptr i8, ptr %x, i64 -9223372036854775808
665  %v = call i8 @LoadMinInt64(ptr %x2)
666  ret void
667}
668
669define 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
678; CHECK-EMPTY:
679entry:
680  %x = alloca i8, align 4
681  br label %end
682
683dead:
684  store i8 5, ptr %x
685  store i64 -5, ptr %p
686  br label %end
687
688end:
689  ret void
690}
691
692define 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:
700; CHECK-EMPTY:
701entry:
702  %x = alloca i8, align 4
703  %y = alloca i8, align 4
704  %z = alloca i8, align 4
705
706  store i8 5, ptr %x
707  %n = load i8, ptr %y
708  call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
709
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)
713
714  ret void
715}
716
717define 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)
728; CHECK-EMPTY:
729entry:
730  %x = alloca i8, align 4
731  %y = alloca i8, align 4
732  %z = alloca i8, align 4
733
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)
737
738  store i8 5, ptr %x
739  %n = load i8, ptr %y
740  call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
741
742  ret void
743}
744
745define 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:
753; CHECK-EMPTY:
754entry:
755  %x = alloca i8, align 4
756  %y = alloca i8, align 4
757  %z = alloca i8, align 4
758
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)
762
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)
766
767  store i8 5, ptr %x
768  %n = load i8, ptr %y
769  call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
770
771  ret void
772}
773
774define 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)
782; CHECK-EMPTY:
783entry:
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)
787  ret void
788}
789
790define 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:
797; CHECK-EMPTY:
798entry:
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)
802  ret void
803}
804
805define 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:
812; CHECK-EMPTY:
813entry:
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)
817  ret void
818}
819
820define 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:
827; CHECK-EMPTY:
828entry:
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)
832  ret void
833}
834
835define 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)
842; CHECK-EMPTY:
843entry:
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)
847  ret void
848}
849
850define 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
857; CHECK-EMPTY:
858entry:
859  %a = alloca i32, align 4
860  %n1 = load i64, ptr %a, align 4
861  %n2 = load i32, ptr %a, align 4
862  ret void
863}
864
865define 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
873; CHECK-EMPTY:
874entry:
875  %a = alloca i32, align 4
876  %n2 = load i32, ptr %a, align 4
877  call void %func(ptr %a)
878  ret void
879}
880
881define 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
889; CHECK-EMPTY:
890entry:
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
895  ret void
896}
897
898define 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
906; CHECK-EMPTY:
907entry:
908  %a = alloca i32, align 4
909  br i1 %x, label %tlabel, label %flabel
910flabel:
911  %n = load i32, ptr %a, align 4
912  ret ptr %y
913tlabel:
914  ret ptr %a
915}
916
917define void @MixedAccesses6(ptr %arg) {
918; CHECK-LABEL: @MixedAccesses6
919; CHECK-NEXT: args uses:
920; CHECK-NEXT: arg[]: [0,4)
921; CHECK-NEXT: allocas uses:
922; CHECK: a[4]: [0,4)
923; GLOBAL-NEXT: safe accesses:
924; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
925; CHECK-EMPTY:
926entry:
927  %a = alloca i32, align 4
928  call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
929  ret void
930}
931
932define void @MixedAccesses7(i1 %cond, ptr %arg) {
933; SECV doesn't support select, so we consider this non-stack-safe, even through
934; it is.
935;
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:
942; CHECK-EMPTY:
943entry:
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)
947  ret void
948}
949
950define 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)
959; CHECK-EMPTY:
960entry:
961  %a = alloca i32, align 4
962  call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)
963  ret void
964}
965
966define 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)
973; CHECK-EMPTY:
974entry:
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)
979
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)
983  ret void
984}
985
986define 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)
993; CHECK-EMPTY:
994entry:
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
999
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)
1003  ret void
1004}
1005
1006define 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)
1013; CHECK-EMPTY:
1014entry:
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)
1018  store i32 5, ptr %a
1019
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)
1023  ret void
1024}
1025
1026define 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)
1033; CHECK-EMPTY:
1034entry:
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)
1040  ret void
1041}
1042
1043define 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
1050; CHECK-EMPTY:
1051entry:
1052  cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1
1053  ret void
1054}
1055
1056define 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
1063; CHECK-EMPTY:
1064entry:
1065  atomicrmw add ptr %p, i32 1 monotonic, align 1
1066  ret void
1067}
1068
1069define 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
1076; CHECK-EMPTY:
1077entry:
1078  %x = alloca i32, align 4
1079  cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1
1080  ret void
1081}
1082
1083define 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
1090; CHECK-EMPTY:
1091entry:
1092  %x = alloca i32, align 4
1093  atomicrmw add ptr %x, i32 1 monotonic, align 1
1094  ret void
1095}
1096
1097define 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
1104; CHECK-EMPTY:
1105entry:
1106  store i32 1, ptr %p
1107  ret void
1108}
1109
1110define 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:
1117; CHECK-EMPTY:
1118  %int = ptrtoint ptr %p to i64
1119  call void @unknown_call_int(i64 %int)
1120  ret void
1121}
1122
1123@ifunc = dso_local ifunc i64 (ptr), ptr @ifunc_resolver
1124
1125define 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
1129entry:
1130  tail call i64 @ifunc(ptr noundef %uaddr)
1131  ret void
1132}
1133
1134define dso_local ptr @ifunc_resolver() {
1135entry:
1136  ret ptr null
1137}
1138
1139declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
1140declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
1141