1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s --check-prefixes=CHECK,LOCAL
2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL
4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
5
6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7target triple = "x86_64-unknown-linux-gnu"
8
9@sink = global i8* null, align 8
10
11declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
12declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
13declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
14
15; Address leaked.
16define void @LeakAddress() {
17; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
18; CHECK-NEXT: args uses:
19; CHECK-NEXT: allocas uses:
20; CHECK-NEXT: x[4]: full-set{{$}}
21; CHECK-NOT: ]:
22entry:
23  %x = alloca i32, align 4
24  %x1 = bitcast i32* %x to i8*
25  store i8* %x1, i8** @sink, align 8
26  ret void
27}
28
29define void @StoreInBounds() {
30; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}
31; CHECK-NEXT: args uses:
32; CHECK-NEXT: allocas uses:
33; CHECK-NEXT: x[4]: [0,1){{$}}
34; CHECK-NOT: ]:
35entry:
36  %x = alloca i32, align 4
37  %x1 = bitcast i32* %x to i8*
38  store i8 0, i8* %x1, align 1
39  ret void
40}
41
42define void @StoreInBounds2() {
43; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}
44; CHECK-NEXT: args uses:
45; CHECK-NEXT: allocas uses:
46; CHECK-NEXT: x[4]: [0,4){{$}}
47; CHECK-NOT: ]:
48entry:
49  %x = alloca i32, align 4
50  store i32 0, i32* %x, align 4
51  ret void
52}
53
54define void @StoreInBounds3() {
55; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}
56; CHECK-NEXT: args uses:
57; CHECK-NEXT: allocas uses:
58; CHECK-NEXT: x[4]: [2,3){{$}}
59; CHECK-NOT: ]:
60entry:
61  %x = alloca i32, align 4
62  %x1 = bitcast i32* %x to i8*
63  %x2 = getelementptr i8, i8* %x1, i64 2
64  store i8 0, i8* %x2, align 1
65  ret void
66}
67
68; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
69define void @StoreInBounds4() {
70; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}
71; CHECK-NEXT: args uses:
72; CHECK-NEXT: allocas uses:
73; CHECK-NEXT: x[4]: [2,-1){{$}}
74; CHECK-NOT: ]:
75entry:
76  %x = alloca i32, align 4
77  %x1 = ptrtoint i32* %x to i64
78  %x2 = add i64 %x1, 2
79  %x3 = inttoptr i64 %x2 to i8*
80  store i8 0, i8* %x3, align 1
81  ret void
82}
83
84define void @StoreOutOfBounds() {
85; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
86; CHECK-NEXT: args uses:
87; CHECK-NEXT: allocas uses:
88; CHECK-NEXT: x[4]: [2,6){{$}}
89; CHECK-NOT: ]:
90entry:
91  %x = alloca i32, align 4
92  %x1 = bitcast i32* %x to i8*
93  %x2 = getelementptr i8, i8* %x1, i64 2
94  %x3 = bitcast i8* %x2 to i32*
95  store i32 0, i32* %x3, align 1
96  ret void
97}
98
99; There is no difference in load vs store handling.
100define void @LoadInBounds() {
101; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}
102; CHECK-NEXT: args uses:
103; CHECK-NEXT: allocas uses:
104; CHECK-NEXT: x[4]: [0,1){{$}}
105; CHECK-NOT: ]:
106entry:
107  %x = alloca i32, align 4
108  %x1 = bitcast i32* %x to i8*
109  %v = load i8, i8* %x1, align 1
110  ret void
111}
112
113define void @LoadOutOfBounds() {
114; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}
115; CHECK-NEXT: args uses:
116; CHECK-NEXT: allocas uses:
117; CHECK-NEXT: x[4]: [2,6){{$}}
118; CHECK-NOT: ]:
119entry:
120  %x = alloca i32, align 4
121  %x1 = bitcast i32* %x to i8*
122  %x2 = getelementptr i8, i8* %x1, i64 2
123  %x3 = bitcast i8* %x2 to i32*
124  %v = load i32, i32* %x3, align 1
125  ret void
126}
127
128; Leak through ret.
129define i8* @Ret() {
130; CHECK-LABEL: @Ret dso_preemptable{{$}}
131; CHECK-NEXT: args uses:
132; CHECK-NEXT: allocas uses:
133; CHECK-NEXT: x[4]: full-set{{$}}
134; CHECK-NOT: ]:
135entry:
136  %x = alloca i32, align 4
137  %x1 = bitcast i32* %x to i8*
138  %x2 = getelementptr i8, i8* %x1, i64 2
139  ret i8* %x2
140}
141
142declare void @Foo(i16* %p)
143
144define void @DirectCall() {
145; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
146; CHECK-NEXT: args uses:
147; CHECK-NEXT: allocas uses:
148; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
149; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
150; CHECK-NOT: ]:
151entry:
152  %x = alloca i64, align 4
153  %x1 = bitcast i64* %x to i16*
154  %x2 = getelementptr i16, i16* %x1, i64 1
155  call void @Foo(i16* %x2);
156  ret void
157}
158
159; Indirect calls can not be analyzed (yet).
160; FIXME: %p[]: full-set looks invalid
161define void @IndirectCall(void (i8*)* %p) {
162; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}
163; CHECK-NEXT: args uses:
164; CHECK-NEXT: p[]: full-set{{$}}
165; CHECK-NEXT: allocas uses:
166; CHECK-NEXT: x[4]: full-set{{$}}
167; CHECK-NOT: ]:
168entry:
169  %x = alloca i32, align 4
170  %x1 = bitcast i32* %x to i8*
171  call void %p(i8* %x1);
172  ret void
173}
174
175define void @NonConstantOffset(i1 zeroext %z) {
176; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}
177; CHECK-NEXT: args uses:
178; CHECK-NEXT: z[]: full-set{{$}}
179; CHECK-NEXT: allocas uses:
180; CHECK-NEXT: x[4]: [0,4){{$}}
181; CHECK-NOT: ]:
182entry:
183  %x = alloca i32, align 4
184  %x1 = bitcast i32* %x to i8*
185  %idx = select i1 %z, i64 1, i64 2
186  %x2 = getelementptr i8, i8* %x1, i64 %idx
187  store i8 0, i8* %x2, align 1
188  ret void
189}
190
191define void @NonConstantOffsetOOB(i1 zeroext %z) {
192; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}
193; CHECK-NEXT: args uses:
194; CHECK-NEXT: z[]: full-set{{$}}
195; CHECK-NEXT: allocas uses:
196; CHECK-NEXT: x[4]: [0,6){{$}}
197; CHECK-NOT: ]:
198entry:
199  %x = alloca i32, align 4
200  %x1 = bitcast i32* %x to i8*
201  %idx = select i1 %z, i64 1, i64 4
202  %x2 = getelementptr i8, i8* %x1, i64 %idx
203  store i8 0, i8* %x2, align 1
204  ret void
205}
206
207define void @ArrayAlloca() {
208; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}
209; CHECK-NEXT: args uses:
210; CHECK-NEXT: allocas uses:
211; CHECK-NEXT: x[40]: [36,40){{$}}
212; CHECK-NOT: ]:
213entry:
214  %x = alloca i32, i32 10, align 4
215  %x1 = bitcast i32* %x to i8*
216  %x2 = getelementptr i8, i8* %x1, i64 36
217  %x3 = bitcast i8* %x2 to i32*
218  store i32 0, i32* %x3, align 1
219  ret void
220}
221
222define void @ArrayAllocaOOB() {
223; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}
224; CHECK-NEXT: args uses:
225; CHECK-NEXT: allocas uses:
226; CHECK-NEXT: x[40]: [37,41){{$}}
227; CHECK-NOT: ]:
228entry:
229  %x = alloca i32, i32 10, align 4
230  %x1 = bitcast i32* %x to i8*
231  %x2 = getelementptr i8, i8* %x1, i64 37
232  %x3 = bitcast i8* %x2 to i32*
233  store i32 0, i32* %x3, align 1
234  ret void
235}
236
237define void @DynamicAllocaUnused(i64 %size) {
238; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}
239; CHECK-NEXT: args uses:
240; CHECK-NEXT: size[]: empty-set{{$}}
241; CHECK-NEXT: allocas uses:
242; CHECK-NEXT: x[0]: empty-set{{$}}
243; CHECK-NOT: ]:
244entry:
245  %x = alloca i32, i64 %size, align 16
246  ret void
247}
248
249; Dynamic alloca with unknown size.
250define void @DynamicAlloca(i64 %size) {
251; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}
252; CHECK-NEXT: args uses:
253; CHECK-NEXT: size[]: [0,-12){{$}}
254; CHECK-NEXT: allocas uses:
255; CHECK-NEXT: x[0]: [0,4){{$}}
256; CHECK-NOT: ]:
257entry:
258  %x = alloca i32, i64 %size, align 16
259  store i32 0, i32* %x, align 1
260  ret void
261}
262
263; Dynamic alloca with limited size.
264; FIXME: could be proved safe. Implement.
265define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
266; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}
267; CHECK-NEXT: args uses:
268; CHECK-NEXT: z[]: [0,-12){{$}}
269; CHECK-NEXT: allocas uses:
270; CHECK-NEXT: x[0]: [0,4){{$}}
271; CHECK-NOT: ]:
272entry:
273  %size = select i1 %z, i64 3, i64 5
274  %x = alloca i32, i64 %size, align 16
275  store i32 0, i32* %x, align 1
276  ret void
277}
278
279define signext i8 @SimpleLoop() {
280; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}
281; CHECK-NEXT: args uses:
282; CHECK-NEXT: allocas uses:
283; CHECK-NEXT: x[10]: [0,10){{$}}
284; CHECK-NOT: ]:
285entry:
286  %x = alloca [10 x i8], align 1
287  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
288  %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 10
289  br label %for.body
290
291for.body:
292  %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
293  %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
294  %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
295  %1 = load volatile i8, i8* %p.09, align 1
296  %add = add i8 %1, %sum.010
297  %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
298  br i1 %exitcond, label %for.cond.cleanup, label %for.body
299
300for.cond.cleanup:
301  ret i8 %add
302}
303
304; OOB in a loop.
305define signext i8 @SimpleLoopOOB() {
306; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}
307; CHECK-NEXT: args uses:
308; CHECK-NEXT: allocas uses:
309; CHECK-NEXT: x[10]: [0,11){{$}}
310; CHECK-NOT: ]:
311entry:
312  %x = alloca [10 x i8], align 1
313  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
314 ; 11 iterations
315  %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 11
316  br label %for.body
317
318for.body:
319  %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
320  %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
321  %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
322  %1 = load volatile i8, i8* %p.09, align 1
323  %add = add i8 %1, %sum.010
324  %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
325  br i1 %exitcond, label %for.cond.cleanup, label %for.body
326
327for.cond.cleanup:
328  ret i8 %add
329}
330
331; FIXME: we don't understand that %sz in the memset call is limited to 128 by the preceding check.
332define dso_local void @SizeCheck(i32 %sz) {
333; CHECK-LABEL: @SizeCheck{{$}}
334; CHECK-NEXT: args uses:
335; CHECK-NEXT: sz[]: [0,1){{$}}
336; CHECK-NEXT: allocas uses:
337; CHECK-NEXT: x1[128]: full-set{{$}}
338; CHECK-NOT: ]:
339entry:
340  %x1 = alloca [128 x i8], align 16
341  %x1.sub = getelementptr inbounds [128 x i8], [128 x i8]* %x1, i64 0, i64 0
342  %cmp = icmp slt i32 %sz, 129
343  br i1 %cmp, label %if.then, label %if.end
344
345if.then:
346  call void @llvm.memset.p0i8.i32(i8* nonnull align 16 %x1.sub, i8 0, i32 %sz, i1 false)
347  br label %if.end
348
349if.end:
350  ret void
351}
352
353; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.
354; This effectively disables safety analysis for scalable allocations.
355define void @Scalable(<vscale x 4 x i32>* %p, <vscale x 4 x i32>* %unused, <vscale x 4 x i32> %v) {
356; CHECK-LABEL: @Scalable dso_preemptable{{$}}
357; CHECK-NEXT: args uses:
358; CHECK-NEXT:   p[]: full-set
359; CHECK-NEXT:   unused[]: empty-set
360; CHECK-NEXT:   v[]: full-set
361; CHECK-NEXT: allocas uses:
362; CHECK-NEXT:   x[0]: [0,1){{$}}
363; CHECK-NOT: ]:
364entry:
365  %x = alloca <vscale x 4 x i32>, align 4
366  %x1 = bitcast <vscale x 4 x i32>* %x to i8*
367  store i8 0, i8* %x1, align 1
368  store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %p, align 4
369  ret void
370}
371
372%zerosize_type = type {}
373
374define void @ZeroSize(%zerosize_type *%p)  {
375; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}
376; CHECK-NEXT: args uses:
377; CHECK-NEXT:   p[]: empty-set
378; CHECK-NEXT: allocas uses:
379; CHECK-NEXT:   x[0]: empty-set
380; CHECK-NOT: ]:
381entry:
382  %x = alloca %zerosize_type, align 4
383  store %zerosize_type undef, %zerosize_type* %x, align 4
384  store %zerosize_type undef, %zerosize_type* undef, align 4
385  %val = load %zerosize_type, %zerosize_type* %p, align 4
386  ret void
387}
388