1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s
2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s
4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s
5
6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7target triple = "x86_64-unknown-linux-gnu"
8
9declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile)
10declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
11declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
12declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
13
14define void @MemsetInBounds() {
15; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}}
16; CHECK-NEXT: args uses:
17; CHECK-NEXT: allocas uses:
18; CHECK-NEXT: x[4]: [0,4){{$}}
19; CHECK-EMPTY:
20entry:
21  %x = alloca i32, align 4
22  %x1 = bitcast i32* %x to i8*
23  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false)
24  ret void
25}
26
27; Volatile does not matter for access bounds.
28define void @VolatileMemsetInBounds() {
29; CHECK-LABEL: VolatileMemsetInBounds dso_preemptable{{$}}
30; CHECK-NEXT: args uses:
31; CHECK-NEXT: allocas uses:
32; CHECK-NEXT: x[4]: [0,4){{$}}
33; CHECK-EMPTY:
34entry:
35  %x = alloca i32, align 4
36  %x1 = bitcast i32* %x to i8*
37  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true)
38  ret void
39}
40
41define void @MemsetOutOfBounds() {
42; CHECK-LABEL: MemsetOutOfBounds dso_preemptable{{$}}
43; CHECK-NEXT: args uses:
44; CHECK-NEXT: allocas uses:
45; CHECK-NEXT: x[4]: [0,5){{$}}
46; CHECK-EMPTY:
47entry:
48  %x = alloca i32, align 4
49  %x1 = bitcast i32* %x to i8*
50  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 5, i1 false)
51  ret void
52}
53
54define void @MemsetNonConst(i32 %size) {
55; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}}
56; CHECK-NEXT: args uses:
57; CHECK-NEXT: allocas uses:
58; CHECK-NEXT: x[4]: [0,4294967295){{$}}
59; CHECK-EMPTY:
60entry:
61  %x = alloca i32, align 4
62  %x1 = bitcast i32* %x to i8*
63  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false)
64  ret void
65}
66
67; FIXME: memintrinsics should look at size range when possible
68; Right now we refuse any non-constant size.
69define void @MemsetNonConstInBounds(i1 zeroext %z) {
70; CHECK-LABEL: MemsetNonConstInBounds dso_preemptable{{$}}
71; CHECK-NEXT: args uses:
72; CHECK-NEXT: allocas uses:
73; CHECK-NEXT: x[4]: [0,4294967295){{$}}
74; CHECK-EMPTY:
75entry:
76  %x = alloca i32, align 4
77  %x1 = bitcast i32* %x to i8*
78  %size = select i1 %z, i32 3, i32 4
79  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false)
80  ret void
81}
82
83define void @MemsetNonConstSize() {
84; CHECK-LABEL: MemsetNonConstSize dso_preemptable{{$}}
85; CHECK-NEXT: args uses:
86; CHECK-NEXT: allocas uses:
87; CHECK-NEXT: x[4]: [0,4294967295){{$}}
88; CHECK-NEXT: y[4]: empty-set{{$}}
89; CHECK-EMPTY:
90entry:
91  %x = alloca i32, align 4
92  %y = alloca i32, align 4
93  %x1 = bitcast i32* %x to i8*
94  %xint = ptrtoint i32* %x to i32
95  %yint = ptrtoint i32* %y to i32
96  %d = sub i32 %xint, %yint
97  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %d, i1 false)
98  ret void
99}
100
101define void @MemcpyInBounds() {
102; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}}
103; CHECK-NEXT: args uses:
104; CHECK-NEXT: allocas uses:
105; CHECK-NEXT: x[4]: [0,4){{$}}
106; CHECK-NEXT: y[4]: [0,4){{$}}
107; CHECK-EMPTY:
108entry:
109  %x = alloca i32, align 4
110  %y = alloca i32, align 4
111  %x1 = bitcast i32* %x to i8*
112  %y1 = bitcast i32* %y to i8*
113  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false)
114  ret void
115}
116
117define void @MemcpySrcOutOfBounds() {
118; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}}
119; CHECK-NEXT: args uses:
120; CHECK-NEXT: allocas uses:
121; CHECK-NEXT: x[8]: [0,5){{$}}
122; CHECK-NEXT: y[4]: [0,5){{$}}
123; CHECK-EMPTY:
124entry:
125  %x = alloca i64, align 4
126  %y = alloca i32, align 4
127  %x1 = bitcast i64* %x to i8*
128  %y1 = bitcast i32* %y to i8*
129  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
130  ret void
131}
132
133define void @MemcpyDstOutOfBounds() {
134; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}}
135; CHECK-NEXT: args uses:
136; CHECK-NEXT: allocas uses:
137; CHECK-NEXT: x[4]: [0,5){{$}}
138; CHECK-NEXT: y[8]: [0,5){{$}}
139; CHECK-EMPTY:
140entry:
141  %x = alloca i32, align 4
142  %y = alloca i64, align 4
143  %x1 = bitcast i32* %x to i8*
144  %y1 = bitcast i64* %y to i8*
145  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
146  ret void
147}
148
149define void @MemcpyBothOutOfBounds() {
150; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}}
151; CHECK-NEXT: args uses:
152; CHECK-NEXT: allocas uses:
153; CHECK-NEXT: x[4]: [0,9){{$}}
154; CHECK-NEXT: y[8]: [0,9){{$}}
155; CHECK-EMPTY:
156entry:
157  %x = alloca i32, align 4
158  %y = alloca i64, align 4
159  %x1 = bitcast i32* %x to i8*
160  %y1 = bitcast i64* %y to i8*
161  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 9, i1 false)
162  ret void
163}
164
165define void @MemcpySelfInBounds() {
166; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}}
167; CHECK-NEXT: args uses:
168; CHECK-NEXT: allocas uses:
169; CHECK-NEXT: x[8]: [0,8){{$}}
170; CHECK-EMPTY:
171entry:
172  %x = alloca i64, align 4
173  %x1 = bitcast i64* %x to i8*
174  %x2 = getelementptr i8, i8* %x1, i64 5
175  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false)
176  ret void
177}
178
179define void @MemcpySelfSrcOutOfBounds() {
180; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}}
181; CHECK-NEXT: args uses:
182; CHECK-NEXT: allocas uses:
183; CHECK-NEXT: x[8]: [0,9){{$}}
184; CHECK-EMPTY:
185entry:
186  %x = alloca i64, align 4
187  %x1 = bitcast i64* %x to i8*
188  %x2 = getelementptr i8, i8* %x1, i64 5
189  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 4, i1 false)
190  ret void
191}
192
193define void @MemcpySelfDstOutOfBounds() {
194; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}}
195; CHECK-NEXT: args uses:
196; CHECK-NEXT: allocas uses:
197; CHECK-NEXT: x[8]: [0,9){{$}}
198; CHECK-EMPTY:
199entry:
200  %x = alloca i64, align 4
201  %x1 = bitcast i64* %x to i8*
202  %x2 = getelementptr i8, i8* %x1, i64 5
203  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x2, i8* %x1, i32 4, i1 false)
204  ret void
205}
206
207define void @MemmoveSelfBothOutOfBounds() {
208; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}}
209; CHECK-NEXT: args uses:
210; CHECK-NEXT: allocas uses:
211; CHECK-NEXT: x[8]: [0,14){{$}}
212; CHECK-EMPTY:
213entry:
214  %x = alloca i64, align 4
215  %x1 = bitcast i64* %x to i8*
216  %x2 = getelementptr i8, i8* %x1, i64 5
217  call void @llvm.memmove.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 9, i1 false)
218  ret void
219}
220