1; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
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
7declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile)
8declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
9declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
10declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
11
12define void @MemsetInBounds() {
13; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}}
14; CHECK-NEXT: args uses:
15; CHECK-NEXT: allocas uses:
16; CHECK-NEXT: x[4]: [0,4){{$}}
17; GLOBAL-NEXT: safe accesses:
18; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false)
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; GLOBAL-NEXT: safe accesses:
34; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true)
35; CHECK-EMPTY:
36entry:
37  %x = alloca i32, align 4
38  %x1 = bitcast i32* %x to i8*
39  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true)
40  ret void
41}
42
43define void @MemsetOutOfBounds() {
44; CHECK-LABEL: MemsetOutOfBounds dso_preemptable{{$}}
45; CHECK-NEXT: args uses:
46; CHECK-NEXT: allocas uses:
47; CHECK-NEXT: x[4]: [0,5){{$}}
48; GLOBAL-NEXT: safe accesses:
49; CHECK-EMPTY:
50entry:
51  %x = alloca i32, align 4
52  %x1 = bitcast i32* %x to i8*
53  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 5, i1 false)
54  ret void
55}
56
57define void @MemsetNonConst(i32 %size) {
58; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}}
59; CHECK-NEXT: args uses:
60; CHECK-NEXT: allocas uses:
61; CHECK-NEXT: x[4]: [0,4294967295){{$}}
62; GLOBAL-NEXT: safe accesses:
63; CHECK-EMPTY:
64entry:
65  %x = alloca i32, align 4
66  %x1 = bitcast i32* %x to i8*
67  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false)
68  ret void
69}
70
71; FIXME: memintrinsics should look at size range when possible
72; Right now we refuse any non-constant size.
73define void @MemsetNonConstInBounds(i1 zeroext %z) {
74; CHECK-LABEL: MemsetNonConstInBounds dso_preemptable{{$}}
75; CHECK-NEXT: args uses:
76; CHECK-NEXT: allocas uses:
77; CHECK-NEXT: x[4]: [0,7){{$}}
78; GLOBAL-NEXT: safe accesses:
79; CHECK-EMPTY:
80entry:
81  %x = alloca i32, align 4
82  %x1 = bitcast i32* %x to i8*
83  %size = select i1 %z, i32 3, i32 4
84  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false)
85  ret void
86}
87
88define void @MemsetNonConstSize() {
89; CHECK-LABEL: MemsetNonConstSize dso_preemptable{{$}}
90; CHECK-NEXT: args uses:
91; CHECK-NEXT: allocas uses:
92; CHECK-NEXT: x[4]: [0,4294967295){{$}}
93; CHECK-NEXT: y[4]: empty-set{{$}}
94; GLOBAL-NEXT: safe accesses:
95; CHECK-EMPTY:
96entry:
97  %x = alloca i32, align 4
98  %y = alloca i32, align 4
99  %x1 = bitcast i32* %x to i8*
100  %xint = ptrtoint i32* %x to i32
101  %yint = ptrtoint i32* %y to i32
102  %d = sub i32 %xint, %yint
103  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %d, i1 false)
104  ret void
105}
106
107define void @MemcpyInBounds() {
108; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}}
109; CHECK-NEXT: args uses:
110; CHECK-NEXT: allocas uses:
111; CHECK-NEXT: x[4]: [0,4){{$}}
112; CHECK-NEXT: y[4]: [0,4){{$}}
113; GLOBAL-NEXT: safe accesses:
114; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false)
115; CHECK-EMPTY:
116entry:
117  %x = alloca i32, align 4
118  %y = alloca i32, align 4
119  %x1 = bitcast i32* %x to i8*
120  %y1 = bitcast i32* %y to i8*
121  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false)
122  ret void
123}
124
125define void @MemcpySrcOutOfBounds() {
126; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}}
127; CHECK-NEXT: args uses:
128; CHECK-NEXT: allocas uses:
129; CHECK-NEXT: x[8]: [0,5){{$}}
130; CHECK-NEXT: y[4]: [0,5){{$}}
131; GLOBAL-NEXT: safe accesses
132; CHECK-EMPTY:
133entry:
134  %x = alloca i64, align 4
135  %y = alloca i32, align 4
136  %x1 = bitcast i64* %x to i8*
137  %y1 = bitcast i32* %y to i8*
138  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
139  ret void
140}
141
142define void @MemcpyDstOutOfBounds() {
143; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}}
144; CHECK-NEXT: args uses:
145; CHECK-NEXT: allocas uses:
146; CHECK-NEXT: x[4]: [0,5){{$}}
147; CHECK-NEXT: y[8]: [0,5){{$}}
148; GLOBAL-NEXT: safe accesses
149; CHECK-EMPTY:
150entry:
151  %x = alloca i32, align 4
152  %y = alloca i64, align 4
153  %x1 = bitcast i32* %x to i8*
154  %y1 = bitcast i64* %y to i8*
155  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
156  ret void
157}
158
159define void @MemcpyBothOutOfBounds() {
160; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}}
161; CHECK-NEXT: args uses:
162; CHECK-NEXT: allocas uses:
163; CHECK-NEXT: x[4]: [0,9){{$}}
164; CHECK-NEXT: y[8]: [0,9){{$}}
165; GLOBAL-NEXT: safe accesses
166; CHECK-EMPTY:
167entry:
168  %x = alloca i32, align 4
169  %y = alloca i64, align 4
170  %x1 = bitcast i32* %x to i8*
171  %y1 = bitcast i64* %y to i8*
172  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 9, i1 false)
173  ret void
174}
175
176define void @MemcpySelfInBounds() {
177; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}}
178; CHECK-NEXT: args uses:
179; CHECK-NEXT: allocas uses:
180; CHECK-NEXT: x[8]: [0,8){{$}}
181; GLOBAL-NEXT: safe accesses
182; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false)
183; CHECK-EMPTY:
184entry:
185  %x = alloca i64, align 4
186  %x1 = bitcast i64* %x to i8*
187  %x2 = getelementptr i8, i8* %x1, i64 5
188  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false)
189  ret void
190}
191
192define void @MemcpySelfSrcOutOfBounds() {
193; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}}
194; CHECK-NEXT: args uses:
195; CHECK-NEXT: allocas uses:
196; CHECK-NEXT: x[8]: [0,9){{$}}
197; GLOBAL-NEXT: safe accesses:
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* %x1, i8* %x2, i32 4, i1 false)
204  ret void
205}
206
207define void @MemcpySelfDstOutOfBounds() {
208; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}}
209; CHECK-NEXT: args uses:
210; CHECK-NEXT: allocas uses:
211; CHECK-NEXT: x[8]: [0,9){{$}}
212; GLOBAL-NEXT: safe accesses:
213; CHECK-EMPTY:
214entry:
215  %x = alloca i64, align 4
216  %x1 = bitcast i64* %x to i8*
217  %x2 = getelementptr i8, i8* %x1, i64 5
218  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x2, i8* %x1, i32 4, i1 false)
219  ret void
220}
221
222define void @MemmoveSelfBothOutOfBounds() {
223; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}}
224; CHECK-NEXT: args uses:
225; CHECK-NEXT: allocas uses:
226; CHECK-NEXT: x[8]: [0,14){{$}}
227; GLOBAL-NEXT: safe accesses:
228; CHECK-EMPTY:
229entry:
230  %x = alloca i64, align 4
231  %x1 = bitcast i64* %x to i8*
232  %x2 = getelementptr i8, i8* %x1, i64 5
233  call void @llvm.memmove.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 9, i1 false)
234  ret void
235}
236
237define void @MemsetInBoundsCast() {
238; CHECK-LABEL: MemsetInBoundsCast dso_preemptable{{$}}
239; CHECK-NEXT: args uses:
240; CHECK-NEXT: allocas uses:
241; CHECK-NEXT: x[4]: [0,4){{$}}
242; CHECK-NEXT: y[1]: empty-set{{$}}
243; GLOBAL-NEXT: safe accesses:
244; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 %yint, i32 4, i1 false)
245; CHECK-EMPTY:
246entry:
247  %x = alloca i32, align 4
248  %y = alloca i8, align 1
249  %x1 = bitcast i32* %x to i8*
250  %yint = ptrtoint i8* %y to i8
251  call void @llvm.memset.p0i8.i32(i8* %x1, i8 %yint, i32 4, i1 false)
252  ret void
253}
254
255define void @MemcpyInBoundsCast2(i8 %zint8) {
256; CHECK-LABEL: MemcpyInBoundsCast2 dso_preemptable{{$}}
257; CHECK-NEXT: args uses:
258; CHECK-NEXT: allocas uses:
259; CHECK-NEXT: x[256]: [0,255){{$}}
260; CHECK-NEXT: y[256]: [0,255){{$}}
261; CHECK-NEXT: z[1]: empty-set{{$}}
262; GLOBAL-NEXT: safe accesses:
263; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 %zint32, i1 false)
264; CHECK-EMPTY:
265entry:
266  %x = alloca [256 x i8], align 4
267  %y = alloca [256 x i8], align 4
268  %z = alloca i8, align 1
269  %x1 = bitcast [256 x i8]* %x to i8*
270  %y1 = bitcast [256 x i8]* %y to i8*
271  %zint32 = zext i8 %zint8 to i32
272  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 %zint32, i1 false)
273  ret void
274}
275