1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -S -inferattrs -basic-aa -dse | FileCheck %s
3 ; RUN: opt < %s -S -aa-pipeline=basic-aa -passes=inferattrs,dse | FileCheck %s
5 target triple = "x86_64-unknown-linux-gnu"
7 declare i8* @strcpy(i8* %dest, i8* %src) nounwind
8 define void @test1(i8* %src) {
10 ; CHECK-NEXT: ret void
13 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
14 %call = call i8* @strcpy(i8* %dest, i8* %src)
18 define void @strcpy_reads_after(i8* noalias %dest, i8* %src) {
19 ; CHECK-LABEL: @strcpy_reads_after(
20 ; CHECK-NEXT: [[SRC_2:%.*]] = getelementptr inbounds i8, i8* [[SRC:%.*]], i64 1
21 ; CHECK-NEXT: store i8 99, i8* [[SRC_2]], align 1
22 ; CHECK-NEXT: [[SRC_1:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i64 1
23 ; CHECK-NEXT: [[CALL:%.*]] = call i8* @strcpy(i8* [[DEST:%.*]], i8* [[SRC_1]])
24 ; CHECK-NEXT: store i8 2, i8* [[SRC]], align 1
25 ; CHECK-NEXT: store i8 2, i8* [[SRC_2]], align 1
26 ; CHECK-NEXT: ret void
28 %src.2 = getelementptr inbounds i8, i8* %src, i64 1
30 store i8 99, i8* %src.2
31 %src.1 = getelementptr inbounds i8, i8* %src, i64 1
32 %call = call i8* @strcpy(i8* %dest, i8* %src.1)
34 store i8 2, i8* %src.2
38 declare i8* @strncpy(i8* %dest, i8* %src, i64 %n) nounwind
39 define void @test2(i8* %src) {
40 ; CHECK-LABEL: @test2(
41 ; CHECK-NEXT: ret void
44 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
45 %call = call i8* @strncpy(i8* %dest, i8* %src, i64 12)
49 declare i8* @strcat(i8* %dest, i8* %src) nounwind
50 define void @test3(i8* %src) {
51 ; CHECK-LABEL: @test3(
52 ; CHECK-NEXT: ret void
55 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
56 %call = call i8* @strcat(i8* %dest, i8* %src)
60 define void @test_strcat_with_lifetime(i8* %src) {
61 ; CHECK-LABEL: @test_strcat_with_lifetime(
62 ; CHECK-NEXT: [[B:%.*]] = alloca [16 x i8], align 1
63 ; CHECK-NEXT: [[B_CAST:%.*]] = bitcast [16 x i8]* [[B]] to i8*
64 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull [[B_CAST]])
65 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull [[B_CAST]])
66 ; CHECK-NEXT: ret void
69 %B.cast = bitcast [16 x i8]* %B to i8*
70 call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %B.cast)
71 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
72 %call = call i8* @strcat(i8* %dest, i8* %src)
73 call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %B.cast)
77 define void @test_strcat_with_lifetime_nonlocal(i8* %dest, i8* %src) {
78 ; CHECK-LABEL: @test_strcat_with_lifetime_nonlocal(
79 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull [[DEST:%.*]])
80 ; CHECK-NEXT: [[CALL:%.*]] = call i8* @strcat(i8* [[DEST]], i8* [[SRC:%.*]])
81 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull [[DEST]])
82 ; CHECK-NEXT: ret void
84 call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %dest)
85 %call = call i8* @strcat(i8* %dest, i8* %src)
86 call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %dest)
90 declare i8* @strncat(i8* %dest, i8* %src, i64 %n) nounwind
91 define void @test4(i8* %src) {
92 ; CHECK-LABEL: @test4(
93 ; CHECK-NEXT: ret void
96 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
97 %call = call i8* @strncat(i8* %dest, i8* %src, i64 12)
101 define void @test5(i8* nocapture %src) {
102 ; CHECK-LABEL: @test5(
103 ; CHECK-NEXT: ret void
105 %dest = alloca [100 x i8], align 16
106 %arraydecay = getelementptr inbounds [100 x i8], [100 x i8]* %dest, i64 0, i64 0
107 %call = call i8* @strcpy(i8* %arraydecay, i8* %src)
108 %arrayidx = getelementptr inbounds i8, i8* %call, i64 10
109 store i8 97, i8* %arrayidx, align 1
113 declare void @user(i8* %p)
114 define void @test6(i8* %src) {
115 ; CHECK-LABEL: @test6(
116 ; CHECK-NEXT: [[B:%.*]] = alloca [16 x i8], align 1
117 ; CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds [16 x i8], [16 x i8]* [[B]], i64 0, i64 0
118 ; CHECK-NEXT: [[CALL:%.*]] = call i8* @strcpy(i8* [[DEST]], i8* [[SRC:%.*]])
119 ; CHECK-NEXT: call void @user(i8* [[DEST]])
120 ; CHECK-NEXT: ret void
122 %B = alloca [16 x i8]
123 %dest = getelementptr inbounds [16 x i8], [16 x i8]* %B, i64 0, i64 0
124 %call = call i8* @strcpy(i8* %dest, i8* %src)
125 call void @user(i8* %dest)
129 declare i32 @memcmp(i8*, i8*, i64)
131 define i32 @test_memcmp_const_size(i8* noalias %foo) {
132 ; CHECK-LABEL: @test_memcmp_const_size(
134 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
135 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
136 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
137 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
138 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
139 ; CHECK-NEXT: [[RES:%.*]] = call i32 @memcmp(i8* nonnull dereferenceable(2) [[FOO:%.*]], i8* nonnull dereferenceable(2) [[STACK_PTR]], i64 2)
140 ; CHECK-NEXT: ret i32 [[RES]]
143 %stack = alloca [10 x i8]
144 %stack.ptr = bitcast [10 x i8]* %stack to i8*
145 store i8 49, i8* %stack.ptr, align 1
146 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
147 store i8 50, i8* %gep.1, align 1
148 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
149 store i8 51, i8* %gep.2, align 1
150 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
151 store i8 52, i8* %gep.3, align 1
152 %res = call i32 @memcmp(i8* nonnull dereferenceable(2) %foo, i8* nonnull dereferenceable(2) %stack.ptr, i64 2)
156 define i32 @test_memcmp_variable_size(i8* noalias %foo, i64 %n) {
157 ; CHECK-LABEL: @test_memcmp_variable_size(
159 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
160 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
161 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
162 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
163 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
164 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 2
165 ; CHECK-NEXT: store i8 51, i8* [[GEP_2]], align 1
166 ; CHECK-NEXT: [[GEP_3:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 3
167 ; CHECK-NEXT: store i8 52, i8* [[GEP_3]], align 1
168 ; CHECK-NEXT: [[RES:%.*]] = call i32 @memcmp(i8* nonnull [[FOO:%.*]], i8* nonnull [[STACK_PTR]], i64 [[N:%.*]])
169 ; CHECK-NEXT: ret i32 [[RES]]
172 %stack = alloca [10 x i8]
173 %stack.ptr = bitcast [10 x i8]* %stack to i8*
174 store i8 49, i8* %stack.ptr, align 1
175 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
176 store i8 50, i8* %gep.1, align 1
177 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
178 store i8 51, i8* %gep.2, align 1
179 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
180 store i8 52, i8* %gep.3, align 1
181 %res = call i32 @memcmp(i8* nonnull %foo, i8* nonnull %stack.ptr, i64 %n)
185 declare i32 @bcmp(i8*, i8*, i64)
187 define i1 @test_bcmp_const_size(i8* noalias %foo) {
188 ; CHECK-LABEL: @test_bcmp_const_size(
190 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
191 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
192 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
193 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
194 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
195 ; CHECK-NEXT: [[CALL:%.*]] = call i32 @bcmp(i8* nonnull dereferenceable(2) [[FOO:%.*]], i8* nonnull dereferenceable(2) [[STACK_PTR]], i64 2)
196 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CALL]], 0
197 ; CHECK-NEXT: ret i1 [[RES]]
200 %stack = alloca [10 x i8]
201 %stack.ptr = bitcast [10 x i8]* %stack to i8*
202 store i8 49, i8* %stack.ptr, align 1
203 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
204 store i8 50, i8* %gep.1, align 1
205 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
206 store i8 51, i8* %gep.2, align 1
207 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
208 store i8 52, i8* %gep.3, align 1
209 %call = call i32 @bcmp(i8* nonnull dereferenceable(2) %foo, i8* nonnull dereferenceable(2) %stack.ptr, i64 2)
210 %res = icmp eq i32 %call, 0
214 define i1 @test_bcmp_variable_size(i8* noalias %foo, i64 %n) {
215 ; CHECK-LABEL: @test_bcmp_variable_size(
217 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
218 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
219 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
220 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
221 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
222 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 2
223 ; CHECK-NEXT: store i8 51, i8* [[GEP_2]], align 1
224 ; CHECK-NEXT: [[GEP_3:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 3
225 ; CHECK-NEXT: store i8 52, i8* [[GEP_3]], align 1
226 ; CHECK-NEXT: [[CALL:%.*]] = call i32 @bcmp(i8* nonnull [[FOO:%.*]], i8* nonnull [[STACK_PTR]], i64 [[N:%.*]])
227 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CALL]], 0
228 ; CHECK-NEXT: ret i1 [[RES]]
231 %stack = alloca [10 x i8]
232 %stack.ptr = bitcast [10 x i8]* %stack to i8*
233 store i8 49, i8* %stack.ptr, align 1
234 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
235 store i8 50, i8* %gep.1, align 1
236 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
237 store i8 51, i8* %gep.2, align 1
238 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
239 store i8 52, i8* %gep.3, align 1
240 %call = call i32 @bcmp(i8* nonnull %foo, i8* nonnull %stack.ptr, i64 %n)
241 %res = icmp eq i32 %call, 0
245 declare i8* @memchr(i8*, i32, i64)
247 define i8* @test_memchr_const_size() {
248 ; CHECK-LABEL: @test_memchr_const_size(
250 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
251 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
252 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
253 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
254 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
255 ; CHECK-NEXT: [[CALL:%.*]] = call i8* @memchr(i8* [[STACK_PTR]], i32 42, i64 2)
256 ; CHECK-NEXT: ret i8* [[CALL]]
259 %stack = alloca [10 x i8]
260 %stack.ptr = bitcast [10 x i8]* %stack to i8*
261 store i8 49, i8* %stack.ptr, align 1
262 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
263 store i8 50, i8* %gep.1, align 1
264 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
265 store i8 51, i8* %gep.2, align 1
266 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
267 store i8 52, i8* %gep.3, align 1
268 %call = call i8* @memchr(i8* %stack.ptr, i32 42, i64 2)
272 define i8* @test_memchr_variable_size(i64 %n) {
273 ; CHECK-LABEL: @test_memchr_variable_size(
275 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
276 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
277 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
278 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
279 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
280 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 2
281 ; CHECK-NEXT: store i8 51, i8* [[GEP_2]], align 1
282 ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 4
283 ; CHECK-NEXT: store i8 52, i8* [[GEP]], align 1
284 ; CHECK-NEXT: [[CALL:%.*]] = call i8* @memchr(i8* [[STACK_PTR]], i32 42, i64 [[N:%.*]])
285 ; CHECK-NEXT: ret i8* [[CALL]]
288 %stack = alloca [10 x i8]
289 %stack.ptr = bitcast [10 x i8]* %stack to i8*
290 store i8 49, i8* %stack.ptr, align 1
291 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
292 store i8 50, i8* %gep.1, align 1
293 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
294 store i8 51, i8* %gep.2, align 1
295 %gep = getelementptr i8, i8* %stack.ptr, i64 4
296 store i8 52, i8* %gep, align 1
297 %call = call i8* @memchr(i8* %stack.ptr, i32 42, i64 %n)
301 declare i8* @memccpy(i8*, i8*, i32, i64)
303 define i8* @test_memccpy_const_size(i8* %foo) {
304 ; CHECK-LABEL: @test_memccpy_const_size(
306 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
307 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
308 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
309 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
310 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
311 ; CHECK-NEXT: [[RES:%.*]] = call i8* @memccpy(i8* [[FOO:%.*]], i8* [[STACK_PTR]], i32 42, i64 2)
312 ; CHECK-NEXT: ret i8* [[RES]]
315 %stack = alloca [10 x i8]
316 %stack.ptr = bitcast [10 x i8]* %stack to i8*
317 store i8 49, i8* %stack.ptr, align 1
318 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
319 store i8 50, i8* %gep.1, align 1
320 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
321 store i8 51, i8* %gep.2, align 1
322 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
323 store i8 52, i8* %gep.3, align 1
324 %res = call i8* @memccpy(i8* %foo, i8* %stack.ptr, i32 42, i64 2)
328 define i8* @test_memccpy_variable_size(i8* %foo, i64 %n) {
329 ; CHECK-LABEL: @test_memccpy_variable_size(
331 ; CHECK-NEXT: [[STACK:%.*]] = alloca [10 x i8], align 1
332 ; CHECK-NEXT: [[STACK_PTR:%.*]] = bitcast [10 x i8]* [[STACK]] to i8*
333 ; CHECK-NEXT: store i8 49, i8* [[STACK_PTR]], align 1
334 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 1
335 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
336 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 2
337 ; CHECK-NEXT: store i8 51, i8* [[GEP_2]], align 1
338 ; CHECK-NEXT: [[GEP_3:%.*]] = getelementptr i8, i8* [[STACK_PTR]], i64 3
339 ; CHECK-NEXT: store i8 52, i8* [[GEP_3]], align 1
340 ; CHECK-NEXT: [[RES:%.*]] = call i8* @memccpy(i8* [[FOO:%.*]], i8* [[STACK_PTR]], i32 42, i64 [[N:%.*]])
341 ; CHECK-NEXT: ret i8* [[RES]]
344 %stack = alloca [10 x i8]
345 %stack.ptr = bitcast [10 x i8]* %stack to i8*
346 store i8 49, i8* %stack.ptr, align 1
347 %gep.1 = getelementptr i8, i8* %stack.ptr, i64 1
348 store i8 50, i8* %gep.1, align 1
349 %gep.2 = getelementptr i8, i8* %stack.ptr, i64 2
350 store i8 51, i8* %gep.2, align 1
351 %gep.3 = getelementptr i8, i8* %stack.ptr, i64 3
352 store i8 52, i8* %gep.3, align 1
353 %res = call i8* @memccpy(i8* %foo, i8* %stack.ptr, i32 42, i64 %n)
357 ; Make sure memccpy does not kill any stores, because it is not known how many
359 define i8* @test_memccpy_const_size_does_not_kill_stores(i8* noalias %dest, i8* noalias %foo) {
360 ; CHECK-LABEL: @test_memccpy_const_size_does_not_kill_stores(
362 ; CHECK-NEXT: store i8 49, i8* [[DEST:%.*]], align 1
363 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i8, i8* [[DEST]], i64 1
364 ; CHECK-NEXT: store i8 50, i8* [[GEP_1]], align 1
365 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr i8, i8* [[DEST]], i64 2
366 ; CHECK-NEXT: store i8 51, i8* [[GEP_2]], align 1
367 ; CHECK-NEXT: [[GEP_3:%.*]] = getelementptr i8, i8* [[DEST]], i64 3
368 ; CHECK-NEXT: store i8 52, i8* [[GEP_3]], align 1
369 ; CHECK-NEXT: [[RES:%.*]] = call i8* @memccpy(i8* [[DEST]], i8* [[FOO:%.*]], i32 42, i64 2)
370 ; CHECK-NEXT: ret i8* [[RES]]
373 store i8 49, i8* %dest, align 1
374 %gep.1 = getelementptr i8, i8* %dest, i64 1
375 store i8 50, i8* %gep.1, align 1
376 %gep.2 = getelementptr i8, i8* %dest, i64 2
377 store i8 51, i8* %gep.2, align 1
378 %gep.3 = getelementptr i8, i8* %dest, i64 3
379 store i8 52, i8* %gep.3, align 1
380 %res = call i8* @memccpy(i8* %dest, i8* %foo, i32 42, i64 2)
384 define void @dse_strcpy(i8* nocapture readonly %src) {
385 ; CHECK-LABEL: @dse_strcpy(
386 ; CHECK-NEXT: [[A:%.*]] = alloca [256 x i8], align 16
387 ; CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds [256 x i8], [256 x i8]* [[A]], i64 0, i64 0
388 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull [[BUF]])
389 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull [[BUF]])
390 ; CHECK-NEXT: ret void
392 %a = alloca [256 x i8], align 16
393 %buf = getelementptr inbounds [256 x i8], [256 x i8]* %a, i64 0, i64 0
394 call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %buf)
395 call i8* @strcpy(i8* nonnull %buf, i8* nonnull dereferenceable(1) %src)
396 call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %buf)
400 define void @dse_strncpy(i8* nocapture readonly %src) {
401 ; CHECK-LABEL: @dse_strncpy(
402 ; CHECK-NEXT: [[A:%.*]] = alloca [256 x i8], align 16
403 ; CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds [256 x i8], [256 x i8]* [[A]], i64 0, i64 0
404 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull [[BUF]])
405 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull [[BUF]])
406 ; CHECK-NEXT: ret void
408 %a = alloca [256 x i8], align 16
409 %buf = getelementptr inbounds [256 x i8], [256 x i8]* %a, i64 0, i64 0
410 call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %buf)
411 call i8* @strncpy(i8* nonnull %buf, i8* nonnull dereferenceable(1) %src, i64 6)
412 call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %buf)
416 define void @dse_strcat(i8* nocapture readonly %src) {
417 ; CHECK-LABEL: @dse_strcat(
418 ; CHECK-NEXT: [[A:%.*]] = alloca [256 x i8], align 16
419 ; CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds [256 x i8], [256 x i8]* [[A]], i64 0, i64 0
420 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull [[BUF]])
421 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull [[BUF]])
422 ; CHECK-NEXT: ret void
424 %a = alloca [256 x i8], align 16
425 %buf = getelementptr inbounds [256 x i8], [256 x i8]* %a, i64 0, i64 0
426 call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %buf)
427 call i8* @strcat(i8* nonnull %buf, i8* nonnull dereferenceable(1) %src)
428 call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %buf)
432 define void @dse_strncat(i8* nocapture readonly %src) {
433 ; CHECK-LABEL: @dse_strncat(
434 ; CHECK-NEXT: [[A:%.*]] = alloca [256 x i8], align 16
435 ; CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds [256 x i8], [256 x i8]* [[A]], i64 0, i64 0
436 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull [[BUF]])
437 ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull [[BUF]])
438 ; CHECK-NEXT: ret void
440 %a = alloca [256 x i8], align 16
441 %buf = getelementptr inbounds [256 x i8], [256 x i8]* %a, i64 0, i64 0
442 call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %buf)
443 call i8* @strncat(i8* nonnull %buf, i8* nonnull dereferenceable(1) %src, i64 6)
444 call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %buf)
448 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
449 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
451 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) nounwind
453 ; Test that strncpy/memset overwriting each other is optimized out
455 ; strncpy -> memset, full overwrite
456 define void @dse_strncpy_test1(i8* noalias %out, i8* noalias %in) {
457 ; CHECK-LABEL: @dse_strncpy_test1(
458 ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[OUT:%.*]], i8 42, i64 100, i1 false)
459 ; CHECK-NEXT: ret void
461 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100)
462 tail call void @llvm.memset.p0i8.i64(i8* %out, i8 42, i64 100, i1 false)
466 declare i8* @__memset_chk(i8* writeonly, i32, i64, i64) argmemonly
468 ; strncpy -> __memset_chk, full overwrite
469 define void @dse_strncpy_memset_chk_test1(i8* noalias %out, i8* noalias %in, i64 %n) {
470 ; CHECK-LABEL: @dse_strncpy_memset_chk_test1(
471 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT:%.*]], i8* [[IN:%.*]], i64 100)
472 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
473 ; CHECK-NEXT: ret void
475 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100)
476 %call.2 = tail call i8* @__memset_chk(i8* %out, i32 42, i64 100, i64 %n)
480 declare void @use(i8*)
482 define void @dse_memset_chk_cannot_eliminates_store(i8* %out, i64 %n) {
483 ; CHECK-LABEL: @dse_memset_chk_cannot_eliminates_store(
484 ; CHECK-NEXT: store i8 10, i8* [[OUT:%.*]], align 1
485 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
486 ; CHECK-NEXT: ret void
488 store i8 10, i8* %out
489 %call.2 = tail call i8* @__memset_chk(i8* %out, i32 42, i64 100, i64 %n)
493 define void @dse_memset_chk_eliminates_store_local_object_escapes_after(i64 %n) {
494 ; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_after(
495 ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
496 ; CHECK-NEXT: [[OUT:%.*]] = bitcast [200 x i8]* [[A]] to i8*
497 ; CHECK-NEXT: store i8 10, i8* [[OUT]], align 1
498 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, i8* [[OUT]], i64 100
499 ; CHECK-NEXT: store i8 10, i8* [[OUT_100]], align 1
500 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
501 ; CHECK-NEXT: call void @use(i8* [[OUT]])
502 ; CHECK-NEXT: ret void
504 %a = alloca [200 x i8]
505 %out = bitcast [200 x i8]* %a to i8*
506 store i8 10, i8* %out
507 %out.100 = getelementptr i8, i8* %out, i64 100
508 store i8 10, i8* %out.100
509 %call.2 = tail call i8* @__memset_chk(i8* %out, i32 42, i64 100, i64 %n)
510 call void @use(i8* %out)
514 define void @dse_memset_chk_eliminates_store_local_object_escapes_before(i64 %n) {
515 ; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_before(
516 ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
517 ; CHECK-NEXT: [[OUT:%.*]] = bitcast [200 x i8]* [[A]] to i8*
518 ; CHECK-NEXT: call void @use(i8* [[OUT]])
519 ; CHECK-NEXT: store i8 10, i8* [[OUT]], align 1
520 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, i8* [[OUT]], i64 100
521 ; CHECK-NEXT: store i8 0, i8* [[OUT_100]], align 1
522 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
523 ; CHECK-NEXT: call void @use(i8* [[OUT]])
524 ; CHECK-NEXT: ret void
526 %a = alloca [200 x i8]
527 %out = bitcast [200 x i8]* %a to i8*
528 call void @use(i8* %out)
529 store i8 10, i8* %out
530 %out.100 = getelementptr i8, i8* %out, i64 100
531 store i8 0, i8* %out.100
532 %call.2 = tail call i8* @__memset_chk(i8* %out, i32 42, i64 100, i64 %n)
533 call void @use(i8* %out)
537 ; strncpy -> memset, partial overwrite
538 define void @dse_strncpy_test2(i8* noalias %out, i8* noalias %in) {
539 ; CHECK-LABEL: @dse_strncpy_test2(
540 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT:%.*]], i8* [[IN:%.*]], i64 100)
541 ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[OUT]], i8 42, i64 99, i1 false)
542 ; CHECK-NEXT: ret void
544 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100)
545 tail call void @llvm.memset.p0i8.i64(i8* %out, i8 42, i64 99, i1 false)
549 ; strncpy -> memset_chk, partial overwrite
550 define void @dse_strncpy_memset_chk_test2(i8* noalias %out, i8* noalias %in, i64 %n) {
551 ; CHECK-LABEL: @dse_strncpy_memset_chk_test2(
552 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT:%.*]], i8* [[IN:%.*]], i64 100)
553 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 99, i64 [[N:%.*]])
554 ; CHECK-NEXT: ret void
556 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100)
557 %call.2 = tail call i8* @__memset_chk(i8* %out, i32 42, i64 99, i64 %n)
561 ; strncpy -> memset, different destination
562 define void @dse_strncpy_test3(i8* noalias %out1, i8* noalias %out2, i8* noalias %in) {
563 ; CHECK-LABEL: @dse_strncpy_test3(
564 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT1:%.*]], i8* [[IN:%.*]], i64 100)
565 ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[OUT2:%.*]], i8 42, i64 100, i1 false)
566 ; CHECK-NEXT: ret void
568 %call = tail call i8* @strncpy(i8* %out1, i8* %in, i64 100)
569 tail call void @llvm.memset.p0i8.i64(i8* %out2, i8 42, i64 100, i1 false)
573 ; strncpy -> memset_chk, different destination
574 define void @dse_strncpy_chk_test3(i8* noalias %out1, i8* noalias %out2, i8* noalias %in, i64 %n) {
575 ; CHECK-LABEL: @dse_strncpy_chk_test3(
576 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT1:%.*]], i8* [[IN:%.*]], i64 100)
577 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT2:%.*]], i32 42, i64 100, i64 [[N:%.*]])
578 ; CHECK-NEXT: ret void
580 %call = tail call i8* @strncpy(i8* %out1, i8* %in, i64 100)
581 %call.2 = tail call i8* @__memset_chk(i8* %out2, i32 42, i64 100, i64 %n)
585 ; memset -> strncpy, full overwrite
586 define void @dse_strncpy_test4(i8* noalias %out, i8* noalias %in) {
587 ; CHECK-LABEL: @dse_strncpy_test4(
588 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT:%.*]], i8* [[IN:%.*]], i64 100)
589 ; CHECK-NEXT: ret void
591 tail call void @llvm.memset.p0i8.i64(i8* %out, i8 42, i64 100, i1 false)
592 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100)
596 ; memset -> strncpy, partial overwrite
597 define void @dse_strncpy_test5(i8* noalias %out, i8* noalias %in) {
598 ; CHECK-LABEL: @dse_strncpy_test5(
599 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, i8* [[OUT:%.*]], i64 99
600 ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 42, i64 1, i1 false)
601 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT]], i8* [[IN:%.*]], i64 99)
602 ; CHECK-NEXT: ret void
604 tail call void @llvm.memset.p0i8.i64(i8* %out, i8 42, i64 100, i1 false)
605 %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 99)
609 ; memset -> strncpy, different destination
610 define void @dse_strncpy_test6(i8* noalias %out1, i8* noalias %out2, i8* noalias %in) {
611 ; CHECK-LABEL: @dse_strncpy_test6(
612 ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[OUT1:%.*]], i8 42, i64 100, i1 false)
613 ; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT2:%.*]], i8* [[IN:%.*]], i64 100)
614 ; CHECK-NEXT: ret void
616 tail call void @llvm.memset.p0i8.i64(i8* %out1, i8 42, i64 100, i1 false)
617 %call = tail call i8* @strncpy(i8* %out2, i8* %in, i64 100)