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