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
4 target triple = "x86_64-unknown-linux-gnu"
6 declare ptr @__memset_chk(ptr writeonly, i32, i64, i64) argmemonly
7 declare ptr @__memcpy_chk(ptr writeonly, ptr readonly, i64, i64) argmemonly nounwind
9 declare ptr @strncpy(ptr %dest, ptr %src, i64 %n) nounwind
10 declare void @use(ptr)
12 ; strncpy -> __memset_chk, full overwrite
13 define void @dse_strncpy_memset_chk_test1(ptr noalias %out, ptr noalias %in, i64 %n) {
14 ; CHECK-LABEL: @dse_strncpy_memset_chk_test1(
15 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]])
16 ; CHECK-NEXT: ret void
18 %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
19 %call.2 = tail call ptr @__memset_chk(ptr %out, i32 42, i64 100, i64 %n)
23 define void @dse_memset_chk_eliminate_store1(ptr %out, i64 %n) {
24 ; CHECK-LABEL: @dse_memset_chk_eliminate_store1(
25 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]])
26 ; CHECK-NEXT: ret void
29 %call.2 = tail call ptr @__memset_chk(ptr %out, i32 42, i64 100, i64 %n)
33 define void @dse_memset_chk_eliminate_store2(ptr %out, i64 %n) {
34 ; CHECK-LABEL: @dse_memset_chk_eliminate_store2(
35 ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[OUT:%.*]], i64 100
36 ; CHECK-NEXT: store i8 10, ptr [[GEP]], align 1
37 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
38 ; CHECK-NEXT: ret void
40 %gep = getelementptr inbounds i8, ptr %out, i64 100
42 %call.2 = tail call ptr @__memset_chk(ptr %out, i32 42, i64 100, i64 %n)
46 define void @dse_memset_chk_eliminates_store_local_object_escapes_after(i64 %n) {
47 ; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_after(
48 ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
49 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, ptr [[A]], i64 100
50 ; CHECK-NEXT: store i8 10, ptr [[OUT_100]], align 1
51 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[A]], i32 42, i64 100, i64 [[N:%.*]])
52 ; CHECK-NEXT: call void @use(ptr [[A]])
53 ; CHECK-NEXT: ret void
55 %a = alloca [200 x i8]
57 %out.100 = getelementptr i8, ptr %a, i64 100
58 store i8 10, ptr %out.100
59 %call.2 = tail call ptr @__memset_chk(ptr %a, i32 42, i64 100, i64 %n)
60 call void @use(ptr %a)
64 define void @dse_memset_chk_eliminates_store_local_object_escapes_before(i64 %n) {
65 ; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_before(
66 ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
67 ; CHECK-NEXT: call void @use(ptr [[A]])
68 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, ptr [[A]], i64 100
69 ; CHECK-NEXT: store i8 0, ptr [[OUT_100]], align 1
70 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[A]], i32 42, i64 100, i64 [[N:%.*]])
71 ; CHECK-NEXT: call void @use(ptr [[A]])
72 ; CHECK-NEXT: ret void
74 %a = alloca [200 x i8]
75 call void @use(ptr %a)
77 %out.100 = getelementptr i8, ptr %a, i64 100
78 store i8 0, ptr %out.100
79 %call.2 = tail call ptr @__memset_chk(ptr %a, i32 42, i64 100, i64 %n)
80 call void @use(ptr %a)
84 ; strncpy -> memset_chk, partial overwrite
85 define void @dse_strncpy_memset_chk_test2(ptr noalias %out, ptr noalias %in, i64 %n) {
86 ; CHECK-LABEL: @dse_strncpy_memset_chk_test2(
87 ; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT:%.*]], ptr [[IN:%.*]], i64 100)
88 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT]], i32 42, i64 99, i64 [[N:%.*]])
89 ; CHECK-NEXT: ret void
91 %call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
92 %call.2 = tail call ptr @__memset_chk(ptr %out, i32 42, i64 99, i64 %n)
96 ; strncpy -> memset_chk, different destination
97 define void @dse_strncpy_chk_test3(ptr noalias %out1, ptr noalias %out2, ptr noalias %in, i64 %n) {
98 ; CHECK-LABEL: @dse_strncpy_chk_test3(
99 ; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT1:%.*]], ptr [[IN:%.*]], i64 100)
100 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT2:%.*]], i32 42, i64 100, i64 [[N:%.*]])
101 ; CHECK-NEXT: ret void
103 %call = tail call ptr @strncpy(ptr %out1, ptr %in, i64 100)
104 %call.2 = tail call ptr @__memset_chk(ptr %out2, i32 42, i64 100, i64 %n)
108 define void @dse_strncpy_memcpy_chk_test1(ptr noalias %out, ptr noalias %in, i64 %n) {
109 ; CHECK-LABEL: @dse_strncpy_memcpy_chk_test1(
110 ; CHECK-NEXT: [[CALL_1:%.*]] = tail call ptr @__memcpy_chk(ptr [[OUT:%.*]], ptr [[IN:%.*]], i64 100, i64 [[N:%.*]])
111 ; CHECK-NEXT: ret void
113 store i32 0, ptr %out
114 %call.1 = tail call ptr @__memcpy_chk(ptr %out, ptr %in, i64 100, i64 %n)
118 define void @dse_strncpy_memcpy_chk_test2(ptr noalias %out, ptr noalias %in, i64 %n) {
119 ; CHECK-LABEL: @dse_strncpy_memcpy_chk_test2(
120 ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[OUT:%.*]], i64 100
121 ; CHECK-NEXT: store i8 10, ptr [[GEP]], align 1
122 ; CHECK-NEXT: [[CALL_1:%.*]] = tail call ptr @__memcpy_chk(ptr [[OUT]], ptr [[IN:%.*]], i64 100, i64 [[N:%.*]])
123 ; CHECK-NEXT: ret void
125 %gep = getelementptr inbounds i8, ptr %out, i64 100
126 store i8 10, ptr %gep
127 %call.1 = tail call ptr @__memcpy_chk(ptr %out, ptr %in, i64 100, i64 %n)
131 define void @test_memcpy_intrinsic_and_memcpy_chk(ptr %A, ptr %B, ptr noalias %C) {
132 ; CHECK-LABEL: @test_memcpy_intrinsic_and_memcpy_chk(
133 ; CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64(ptr [[A:%.*]], ptr [[B:%.*]], i64 48, i1 false)
134 ; CHECK-NEXT: [[CALL:%.*]] = call ptr @__memcpy_chk(ptr [[A]], ptr [[C:%.*]], i64 1, i64 10)
135 ; CHECK-NEXT: ret void
137 tail call void @llvm.memcpy.p0.p0.i64(ptr %A, ptr %B, i64 48, i1 false)
138 %call = call ptr @__memcpy_chk(ptr %A, ptr %C, i64 1, i64 10)
142 declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)