xref: /llvm-project/llvm/test/Transforms/DeadStoreElimination/libcalls.ll (revision aec03ad99119aa2c3a96faeb261b0ed583e0824b)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -S -aa-pipeline=basic-aa -passes=inferattrs,dse | FileCheck %s
3
4target triple = "x86_64-unknown-linux-gnu"
5
6declare ptr @strcpy(ptr %dest, ptr %src) nounwind
7define void @test1(ptr %src) {
8; CHECK-LABEL: @test1(
9; CHECK-NEXT:    ret void
10;
11  %B = alloca [16 x i8]
12  %call = call ptr @strcpy(ptr %B, ptr %src)
13  ret void
14}
15
16define void @strcpy_reads_after(ptr noalias %dest, ptr %src) {
17; CHECK-LABEL: @strcpy_reads_after(
18; CHECK-NEXT:    [[SRC_2:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i64 1
19; CHECK-NEXT:    store i8 99, ptr [[SRC_2]], align 1
20; CHECK-NEXT:    [[SRC_1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1
21; CHECK-NEXT:    [[CALL:%.*]] = call ptr @strcpy(ptr [[DEST:%.*]], ptr [[SRC_1]])
22; CHECK-NEXT:    store i8 2, ptr [[SRC]], align 1
23; CHECK-NEXT:    store i8 2, ptr [[SRC_2]], align 1
24; CHECK-NEXT:    ret void
25;
26  %src.2 = getelementptr inbounds i8, ptr %src, i64 1
27  store i8 1, ptr %src
28  store i8 99, ptr %src.2
29  %src.1 = getelementptr inbounds i8, ptr %src, i64 1
30  %call = call ptr @strcpy(ptr %dest, ptr %src.1)
31  store i8 2, ptr %src
32  store i8 2, ptr %src.2
33  ret void
34}
35
36declare ptr @strncpy(ptr %dest, ptr %src, i64 %n) nounwind
37define void @test2(ptr %src) {
38; CHECK-LABEL: @test2(
39; CHECK-NEXT:    ret void
40;
41  %B = alloca [16 x i8]
42  %call = call ptr @strncpy(ptr %B, ptr %src, i64 12)
43  ret void
44}
45
46declare ptr @strcat(ptr %B, ptr %src) nounwind
47define void @test3(ptr %src) {
48; CHECK-LABEL: @test3(
49; CHECK-NEXT:    ret void
50;
51  %B = alloca [16 x i8]
52  %call = call ptr @strcat(ptr %B, ptr %src)
53  ret void
54}
55
56define void @test_strcat_with_lifetime(ptr %src) {
57; CHECK-LABEL: @test_strcat_with_lifetime(
58; CHECK-NEXT:    [[B:%.*]] = alloca [16 x i8], align 1
59; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[B]])
60; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[B]])
61; CHECK-NEXT:    ret void
62;
63  %B = alloca [16 x i8]
64  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %B)
65  %call = call ptr @strcat(ptr %B, ptr %src)
66  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %B)
67  ret void
68}
69
70define void @test_strcat_with_lifetime_nonlocal(ptr %dest, ptr %src) {
71; CHECK-LABEL: @test_strcat_with_lifetime_nonlocal(
72; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[DEST:%.*]])
73; CHECK-NEXT:    [[CALL:%.*]] = call ptr @strcat(ptr [[DEST]], ptr [[SRC:%.*]])
74; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[DEST]])
75; CHECK-NEXT:    ret void
76;
77  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %dest)
78  %call = call ptr @strcat(ptr %dest, ptr %src)
79  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %dest)
80  ret void
81}
82
83declare ptr @strncat(ptr %dest, ptr %src, i64 %n) nounwind
84define void @test4(ptr %src) {
85; CHECK-LABEL: @test4(
86; CHECK-NEXT:    ret void
87;
88  %B = alloca [16 x i8]
89  %call = call ptr @strncat(ptr %B, ptr %src, i64 12)
90  ret void
91}
92
93define void @test5(ptr nocapture %src) {
94; CHECK-LABEL: @test5(
95; CHECK-NEXT:    ret void
96;
97  %dest = alloca [100 x i8], align 16
98  %call = call ptr @strcpy(ptr %dest, ptr %src)
99  %arrayidx = getelementptr inbounds i8, ptr %call, i64 10
100  store i8 97, ptr %arrayidx, align 1
101  ret void
102}
103
104declare void @user(ptr %p)
105define void @test6(ptr %src) {
106; CHECK-LABEL: @test6(
107; CHECK-NEXT:    [[B:%.*]] = alloca [16 x i8], align 1
108; CHECK-NEXT:    [[CALL:%.*]] = call ptr @strcpy(ptr [[B]], ptr [[SRC:%.*]])
109; CHECK-NEXT:    call void @user(ptr [[B]])
110; CHECK-NEXT:    ret void
111;
112  %B = alloca [16 x i8]
113  %call = call ptr @strcpy(ptr %B, ptr %src)
114  call void @user(ptr %B)
115  ret void
116}
117
118declare i32 @memcmp(ptr, ptr, i64)
119
120define i32 @test_memcmp_const_size(ptr noalias %foo) {
121; CHECK-LABEL: @test_memcmp_const_size(
122; CHECK-NEXT:  entry:
123; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
124; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
125; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
126; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
127; CHECK-NEXT:    [[RES:%.*]] = call i32 @memcmp(ptr nonnull dereferenceable(2) [[FOO:%.*]], ptr nonnull dereferenceable(2) [[STACK]], i64 2)
128; CHECK-NEXT:    ret i32 [[RES]]
129;
130entry:
131  %stack = alloca [10 x i8]
132  store i8 49, ptr %stack, align 1
133  %gep.1 = getelementptr i8, ptr %stack, i64 1
134  store i8 50, ptr %gep.1, align 1
135  %gep.2 = getelementptr i8, ptr %stack, i64 2
136  store i8 51, ptr %gep.2, align 1
137  %gep.3 = getelementptr i8, ptr %stack, i64 3
138  store i8 52, ptr %gep.3, align 1
139  %res = call i32 @memcmp(ptr nonnull dereferenceable(2) %foo, ptr nonnull dereferenceable(2) %stack, i64 2)
140  ret i32 %res
141}
142
143define i32 @test_memcmp_variable_size(ptr noalias %foo, i64 %n) {
144; CHECK-LABEL: @test_memcmp_variable_size(
145; CHECK-NEXT:  entry:
146; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
147; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
148; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
149; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
150; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr i8, ptr [[STACK]], i64 2
151; CHECK-NEXT:    store i8 51, ptr [[GEP_2]], align 1
152; CHECK-NEXT:    [[GEP_3:%.*]] = getelementptr i8, ptr [[STACK]], i64 3
153; CHECK-NEXT:    store i8 52, ptr [[GEP_3]], align 1
154; CHECK-NEXT:    [[RES:%.*]] = call i32 @memcmp(ptr nonnull [[FOO:%.*]], ptr nonnull [[STACK]], i64 [[N:%.*]])
155; CHECK-NEXT:    ret i32 [[RES]]
156;
157entry:
158  %stack = alloca [10 x i8]
159  store i8 49, ptr %stack, align 1
160  %gep.1 = getelementptr i8, ptr %stack, i64 1
161  store i8 50, ptr %gep.1, align 1
162  %gep.2 = getelementptr i8, ptr %stack, i64 2
163  store i8 51, ptr %gep.2, align 1
164  %gep.3 = getelementptr i8, ptr %stack, i64 3
165  store i8 52, ptr %gep.3, align 1
166  %res = call i32 @memcmp(ptr nonnull %foo, ptr nonnull %stack, i64 %n)
167  ret i32 %res
168}
169
170declare i32 @bcmp(ptr, ptr, i64)
171
172define i1 @test_bcmp_const_size(ptr noalias %foo) {
173; CHECK-LABEL: @test_bcmp_const_size(
174; CHECK-NEXT:  entry:
175; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
176; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
177; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
178; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
179; CHECK-NEXT:    [[CALL:%.*]] = call i32 @bcmp(ptr nonnull dereferenceable(2) [[FOO:%.*]], ptr nonnull dereferenceable(2) [[STACK]], i64 2)
180; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[CALL]], 0
181; CHECK-NEXT:    ret i1 [[RES]]
182;
183entry:
184  %stack = alloca [10 x i8]
185  store i8 49, ptr %stack, align 1
186  %gep.1 = getelementptr i8, ptr %stack, i64 1
187  store i8 50, ptr %gep.1, align 1
188  %gep.2 = getelementptr i8, ptr %stack, i64 2
189  store i8 51, ptr %gep.2, align 1
190  %gep.3 = getelementptr i8, ptr %stack, i64 3
191  store i8 52, ptr %gep.3, align 1
192  %call = call i32 @bcmp(ptr nonnull dereferenceable(2) %foo, ptr nonnull dereferenceable(2) %stack, i64 2)
193  %res = icmp eq i32 %call, 0
194  ret i1 %res
195}
196
197define i1 @test_bcmp_variable_size(ptr noalias %foo, i64 %n) {
198; CHECK-LABEL: @test_bcmp_variable_size(
199; CHECK-NEXT:  entry:
200; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
201; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
202; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
203; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
204; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr i8, ptr [[STACK]], i64 2
205; CHECK-NEXT:    store i8 51, ptr [[GEP_2]], align 1
206; CHECK-NEXT:    [[GEP_3:%.*]] = getelementptr i8, ptr [[STACK]], i64 3
207; CHECK-NEXT:    store i8 52, ptr [[GEP_3]], align 1
208; CHECK-NEXT:    [[CALL:%.*]] = call i32 @bcmp(ptr nonnull [[FOO:%.*]], ptr nonnull [[STACK]], i64 [[N:%.*]])
209; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[CALL]], 0
210; CHECK-NEXT:    ret i1 [[RES]]
211;
212entry:
213  %stack = alloca [10 x i8]
214  store i8 49, ptr %stack, align 1
215  %gep.1 = getelementptr i8, ptr %stack, i64 1
216  store i8 50, ptr %gep.1, align 1
217  %gep.2 = getelementptr i8, ptr %stack, i64 2
218  store i8 51, ptr %gep.2, align 1
219  %gep.3 = getelementptr i8, ptr %stack, i64 3
220  store i8 52, ptr %gep.3, align 1
221  %call = call i32 @bcmp(ptr nonnull %foo, ptr nonnull %stack, i64 %n)
222  %res = icmp eq i32 %call, 0
223  ret i1 %res
224}
225
226declare ptr @memchr(ptr, i32, i64)
227
228define ptr @test_memchr_const_size() {
229; CHECK-LABEL: @test_memchr_const_size(
230; CHECK-NEXT:  entry:
231; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
232; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
233; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
234; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
235; CHECK-NEXT:    [[CALL:%.*]] = call ptr @memchr(ptr [[STACK]], i32 42, i64 2)
236; CHECK-NEXT:    ret ptr [[CALL]]
237;
238entry:
239  %stack = alloca [10 x i8]
240  store i8 49, ptr %stack, align 1
241  %gep.1 = getelementptr i8, ptr %stack, i64 1
242  store i8 50, ptr %gep.1, align 1
243  %gep.2 = getelementptr i8, ptr %stack, i64 2
244  store i8 51, ptr %gep.2, align 1
245  %gep.3 = getelementptr i8, ptr %stack, i64 3
246  store i8 52, ptr %gep.3, align 1
247  %call = call ptr @memchr(ptr %stack, i32 42, i64 2)
248  ret ptr %call
249}
250
251define ptr @test_memchr_variable_size(i64 %n) {
252; CHECK-LABEL: @test_memchr_variable_size(
253; CHECK-NEXT:  entry:
254; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
255; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
256; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
257; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
258; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr i8, ptr [[STACK]], i64 2
259; CHECK-NEXT:    store i8 51, ptr [[GEP_2]], align 1
260; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[STACK]], i64 4
261; CHECK-NEXT:    store i8 52, ptr [[GEP]], align 1
262; CHECK-NEXT:    [[CALL:%.*]] = call ptr @memchr(ptr [[STACK]], i32 42, i64 [[N:%.*]])
263; CHECK-NEXT:    ret ptr [[CALL]]
264;
265entry:
266  %stack = alloca [10 x i8]
267  store i8 49, ptr %stack, align 1
268  %gep.1 = getelementptr i8, ptr %stack, i64 1
269  store i8 50, ptr %gep.1, align 1
270  %gep.2 = getelementptr i8, ptr %stack, i64 2
271  store i8 51, ptr %gep.2, align 1
272  %gep = getelementptr i8, ptr %stack, i64 4
273  store i8 52, ptr %gep, align 1
274  %call = call ptr @memchr(ptr %stack, i32 42, i64 %n)
275  ret ptr %call
276}
277
278declare ptr @memccpy(ptr, ptr, i32, i64)
279
280define ptr @test_memccpy_const_size(ptr %foo) {
281; CHECK-LABEL: @test_memccpy_const_size(
282; CHECK-NEXT:  entry:
283; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
284; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
285; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
286; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
287; CHECK-NEXT:    [[RES:%.*]] = call ptr @memccpy(ptr [[FOO:%.*]], ptr [[STACK]], i32 42, i64 2)
288; CHECK-NEXT:    ret ptr [[RES]]
289;
290entry:
291  %stack = alloca [10 x i8]
292  store i8 49, ptr %stack, align 1
293  %gep.1 = getelementptr i8, ptr %stack, i64 1
294  store i8 50, ptr %gep.1, align 1
295  %gep.2 = getelementptr i8, ptr %stack, i64 2
296  store i8 51, ptr %gep.2, align 1
297  %gep.3 = getelementptr i8, ptr %stack, i64 3
298  store i8 52, ptr %gep.3, align 1
299  %res = call ptr @memccpy(ptr %foo, ptr %stack, i32 42, i64 2)
300  ret ptr %res
301}
302
303define ptr @test_memccpy_variable_size(ptr %foo, i64 %n) {
304; CHECK-LABEL: @test_memccpy_variable_size(
305; CHECK-NEXT:  entry:
306; CHECK-NEXT:    [[STACK:%.*]] = alloca [10 x i8], align 1
307; CHECK-NEXT:    store i8 49, ptr [[STACK]], align 1
308; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[STACK]], i64 1
309; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
310; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr i8, ptr [[STACK]], i64 2
311; CHECK-NEXT:    store i8 51, ptr [[GEP_2]], align 1
312; CHECK-NEXT:    [[GEP_3:%.*]] = getelementptr i8, ptr [[STACK]], i64 3
313; CHECK-NEXT:    store i8 52, ptr [[GEP_3]], align 1
314; CHECK-NEXT:    [[RES:%.*]] = call ptr @memccpy(ptr [[FOO:%.*]], ptr [[STACK]], i32 42, i64 [[N:%.*]])
315; CHECK-NEXT:    ret ptr [[RES]]
316;
317entry:
318  %stack = alloca [10 x i8]
319  store i8 49, ptr %stack, align 1
320  %gep.1 = getelementptr i8, ptr %stack, i64 1
321  store i8 50, ptr %gep.1, align 1
322  %gep.2 = getelementptr i8, ptr %stack, i64 2
323  store i8 51, ptr %gep.2, align 1
324  %gep.3 = getelementptr i8, ptr %stack, i64 3
325  store i8 52, ptr %gep.3, align 1
326  %res = call ptr @memccpy(ptr %foo, ptr %stack, i32 42, i64 %n)
327  ret ptr %res
328}
329
330; Make sure memccpy does not kill any stores, because it is not known how many
331; bytes are written.
332define ptr @test_memccpy_const_size_does_not_kill_stores(ptr noalias %dest, ptr noalias %foo) {
333; CHECK-LABEL: @test_memccpy_const_size_does_not_kill_stores(
334; CHECK-NEXT:  entry:
335; CHECK-NEXT:    store i8 49, ptr [[DEST:%.*]], align 1
336; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr i8, ptr [[DEST]], i64 1
337; CHECK-NEXT:    store i8 50, ptr [[GEP_1]], align 1
338; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr i8, ptr [[DEST]], i64 2
339; CHECK-NEXT:    store i8 51, ptr [[GEP_2]], align 1
340; CHECK-NEXT:    [[GEP_3:%.*]] = getelementptr i8, ptr [[DEST]], i64 3
341; CHECK-NEXT:    store i8 52, ptr [[GEP_3]], align 1
342; CHECK-NEXT:    [[RES:%.*]] = call ptr @memccpy(ptr [[DEST]], ptr [[FOO:%.*]], i32 42, i64 2)
343; CHECK-NEXT:    ret ptr [[RES]]
344;
345entry:
346  store i8 49, ptr %dest, align 1
347  %gep.1 = getelementptr i8, ptr %dest, i64 1
348  store i8 50, ptr %gep.1, align 1
349  %gep.2 = getelementptr i8, ptr %dest, i64 2
350  store i8 51, ptr %gep.2, align 1
351  %gep.3 = getelementptr i8, ptr %dest, i64 3
352  store i8 52, ptr %gep.3, align 1
353  %res = call ptr @memccpy(ptr %dest, ptr %foo, i32 42, i64 2)
354  ret ptr %res
355}
356
357define void @dse_strcpy(ptr nocapture readonly %src) {
358; CHECK-LABEL: @dse_strcpy(
359; CHECK-NEXT:    [[A:%.*]] = alloca [256 x i8], align 16
360; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 256, ptr nonnull [[A]])
361; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 256, ptr nonnull [[A]])
362; CHECK-NEXT:    ret void
363;
364  %a = alloca [256 x i8], align 16
365  call void @llvm.lifetime.start.p0(i64 256, ptr nonnull %a)
366  call ptr @strcpy(ptr nonnull %a, ptr nonnull dereferenceable(1) %src)
367  call void @llvm.lifetime.end.p0(i64 256, ptr nonnull %a)
368  ret void
369}
370
371define void @dse_strncpy(ptr nocapture readonly %src) {
372; CHECK-LABEL: @dse_strncpy(
373; CHECK-NEXT:    [[A:%.*]] = alloca [256 x i8], align 16
374; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 256, ptr nonnull [[A]])
375; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 256, ptr nonnull [[A]])
376; CHECK-NEXT:    ret void
377;
378  %a = alloca [256 x i8], align 16
379  call void @llvm.lifetime.start.p0(i64 256, ptr nonnull %a)
380  call ptr @strncpy(ptr nonnull %a, ptr nonnull dereferenceable(1) %src, i64 6)
381  call void @llvm.lifetime.end.p0(i64 256, ptr nonnull %a)
382  ret void
383}
384
385define void @dse_strcat(ptr nocapture readonly %src) {
386; CHECK-LABEL: @dse_strcat(
387; CHECK-NEXT:    [[A:%.*]] = alloca [256 x i8], align 16
388; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 256, ptr nonnull [[A]])
389; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 256, ptr nonnull [[A]])
390; CHECK-NEXT:    ret void
391;
392  %a = alloca [256 x i8], align 16
393  call void @llvm.lifetime.start.p0(i64 256, ptr nonnull %a)
394  call ptr @strcat(ptr nonnull %a, ptr nonnull dereferenceable(1) %src)
395  call void @llvm.lifetime.end.p0(i64 256, ptr nonnull %a)
396  ret void
397}
398
399define void @dse_strncat(ptr nocapture readonly %src) {
400; CHECK-LABEL: @dse_strncat(
401; CHECK-NEXT:    [[A:%.*]] = alloca [256 x i8], align 16
402; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 256, ptr nonnull [[A]])
403; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 256, ptr nonnull [[A]])
404; CHECK-NEXT:    ret void
405;
406  %a = alloca [256 x i8], align 16
407  call void @llvm.lifetime.start.p0(i64 256, ptr nonnull %a)
408  call ptr @strncat(ptr nonnull %a, ptr nonnull dereferenceable(1) %src, i64 6)
409  call void @llvm.lifetime.end.p0(i64 256, ptr nonnull %a)
410  ret void
411}
412
413declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
414declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
415
416declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
417
418; Test that strncpy/memset overwriting each other is optimized out
419
420; strncpy -> memset, full overwrite
421define void @dse_strncpy_test1(ptr noalias %out, ptr noalias %in) {
422; CHECK-LABEL: @dse_strncpy_test1(
423; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr [[OUT:%.*]], i8 42, i64 100, i1 false)
424; CHECK-NEXT:    ret void
425;
426  %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
427  tail call void @llvm.memset.p0.i64(ptr %out, i8 42, i64 100, i1 false)
428  ret void
429}
430
431; strncpy -> memset, partial overwrite
432define void @dse_strncpy_test2(ptr noalias %out, ptr noalias %in) {
433; CHECK-LABEL: @dse_strncpy_test2(
434; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT:%.*]], ptr [[IN:%.*]], i64 100)
435; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr [[OUT]], i8 42, i64 99, i1 false)
436; CHECK-NEXT:    ret void
437;
438  %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
439  tail call void @llvm.memset.p0.i64(ptr %out, i8 42, i64 99, i1 false)
440  ret void
441}
442
443; strncpy -> memset, different destination
444define void @dse_strncpy_test3(ptr noalias %out1, ptr noalias %out2, ptr noalias %in) {
445; CHECK-LABEL: @dse_strncpy_test3(
446; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT1:%.*]], ptr [[IN:%.*]], i64 100)
447; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr [[OUT2:%.*]], i8 42, i64 100, i1 false)
448; CHECK-NEXT:    ret void
449;
450  %call = tail call ptr @strncpy(ptr %out1, ptr %in, i64 100)
451  tail call void @llvm.memset.p0.i64(ptr %out2, i8 42, i64 100, i1 false)
452  ret void
453}
454
455; memset -> strncpy, full overwrite
456define void @dse_strncpy_test4(ptr noalias %out, ptr noalias %in) {
457; CHECK-LABEL: @dse_strncpy_test4(
458; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT:%.*]], ptr [[IN:%.*]], i64 100)
459; CHECK-NEXT:    ret void
460;
461  tail call void @llvm.memset.p0.i64(ptr %out, i8 42, i64 100, i1 false)
462  %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
463  ret void
464}
465
466; memset -> strncpy, partial overwrite
467define void @dse_strncpy_test5(ptr noalias %out, ptr noalias %in) {
468; CHECK-LABEL: @dse_strncpy_test5(
469; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[OUT:%.*]], i64 99
470; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr align 1 [[TMP1]], i8 42, i64 1, i1 false)
471; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT]], ptr [[IN:%.*]], i64 99)
472; CHECK-NEXT:    ret void
473;
474  tail call void @llvm.memset.p0.i64(ptr %out, i8 42, i64 100, i1 false)
475  %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 99)
476  ret void
477}
478
479; memset -> strncpy, different destination
480define void @dse_strncpy_test6(ptr noalias %out1, ptr noalias %out2, ptr noalias %in) {
481; CHECK-LABEL: @dse_strncpy_test6(
482; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr [[OUT1:%.*]], i8 42, i64 100, i1 false)
483; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT2:%.*]], ptr [[IN:%.*]], i64 100)
484; CHECK-NEXT:    ret void
485;
486  tail call void @llvm.memset.p0.i64(ptr %out1, i8 42, i64 100, i1 false)
487  %call = tail call ptr @strncpy(ptr %out2, ptr %in, i64 100)
488  ret void
489}
490