[rtsan] Add fork/execve interceptors (#117198)
[llvm-project.git] / llvm / test / Transforms / DeadStoreElimination / multiblock-malloc-free.ll
blobd32d562eedc44fc581baaa74a165ee01d318b973
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
3 ; RUN: opt < %s -passes=dse -S | FileCheck %s
5 target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
6 declare void @unknown_func()
7 declare void @llvm.lifetime.start.p0(i64, ptr nocapture) nounwind
8 declare void @llvm.lifetime.end.p0(i64, ptr nocapture) nounwind
9 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
10 declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i32, i1) nounwind
12 declare noalias ptr @calloc(i64, i64) #5
13 declare noalias ptr @malloc(i64) #0
14 declare noalias ptr @strdup(ptr nocapture readonly) #1
15 declare void @free(ptr nocapture) #2
17 define void @test16(ptr noalias %P) {
18 ; CHECK-LABEL: @test16(
19 ; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB3:%.*]]
20 ; CHECK:       bb1:
21 ; CHECK-NEXT:    br label [[BB3]]
22 ; CHECK:       bb3:
23 ; CHECK-NEXT:    call void @free(ptr [[P:%.*]])
24 ; CHECK-NEXT:    store i32 1, ptr [[P]], align 4
25 ; CHECK-NEXT:    ret void
27   store i32 1, ptr %P
28   br i1 true, label %bb1, label %bb3
29 bb1:
30   store i32 1, ptr %P
31   br label %bb3
32 bb3:
33   call void @free(ptr %P)
34   store i32 1, ptr %P
35   ret void
38 ; We cannot remove the store in the entry block, because @unknown_func could
39 ; unwind and the stored value could be read by the caller.
40 define void @test17(ptr noalias %P) {
41 ; CHECK-LABEL: @test17(
42 ; CHECK-NEXT:    store i32 1, ptr [[P:%.*]], align 4
43 ; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB3:%.*]]
44 ; CHECK:       bb1:
45 ; CHECK-NEXT:    call void @unknown_func()
46 ; CHECK-NEXT:    br label [[BB3]]
47 ; CHECK:       bb3:
48 ; CHECK-NEXT:    call void @free(ptr [[P]])
49 ; CHECK-NEXT:    ret void
51   store i32 1, ptr %P
52   br i1 true, label %bb1, label %bb3
53 bb1:
54   call void @unknown_func()
55   store i32 1, ptr %P
56   br label %bb3
57 bb3:
58   call void @free(ptr %P)
59   ret void
62 define void @test17_read_after_free(ptr noalias %P) {
63 ; CHECK-LABEL: @test17_read_after_free(
64 ; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB3:%.*]]
65 ; CHECK:       bb1:
66 ; CHECK-NEXT:    br label [[BB3]]
67 ; CHECK:       bb3:
68 ; CHECK-NEXT:    call void @free(ptr [[P:%.*]])
69 ; CHECK-NEXT:    [[LV:%.*]] = load i8, ptr [[P]], align 1
70 ; CHECK-NEXT:    ret void
72   store i32 1, ptr %P
73   br i1 true, label %bb1, label %bb3
74 bb1:
75   store i32 1, ptr %P
76   br label %bb3
77 bb3:
78   call void @free(ptr %P)
79   %lv = load i8, ptr %P
80   ret void
83 define void @test19(ptr noalias %P) {
84 ; CHECK-LABEL: @test19(
85 ; CHECK-NEXT:  entry:
86 ; CHECK-NEXT:    [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
87 ; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 4 [[ARRAYIDX0]], i8 0, i64 28, i1 false)
88 ; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB2:%.*]]
89 ; CHECK:       bb1:
90 ; CHECK-NEXT:    br label [[BB3:%.*]]
91 ; CHECK:       bb2:
92 ; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 1
93 ; CHECK-NEXT:    store i32 1, ptr [[ARRAYIDX1]], align 4
94 ; CHECK-NEXT:    br label [[BB3]]
95 ; CHECK:       bb3:
96 ; CHECK-NEXT:    ret void
98 entry:
99   %arrayidx0 = getelementptr inbounds i32, ptr %P, i64 1
100   call void @llvm.memset.p0.i64(ptr %arrayidx0, i8 0, i64 28, i32 4, i1 false)
101   br i1 true, label %bb1, label %bb2
102 bb1:
103   br label %bb3
104 bb2:
105   %arrayidx1 = getelementptr inbounds i32, ptr %P, i64 1
106   store i32 1, ptr %arrayidx1, align 4
107   br label %bb3
108 bb3:
109   ret void
113 define void @test20(ptr noalias %P) {
114 ; CHECK-LABEL: @test20(
115 ; CHECK-NEXT:  entry:
116 ; CHECK-NEXT:    [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
117 ; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARRAYIDX0]], i64 4
118 ; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 4 [[TMP0]], i8 0, i64 24, i1 false)
119 ; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB2:%.*]]
120 ; CHECK:       bb1:
121 ; CHECK-NEXT:    br label [[BB3:%.*]]
122 ; CHECK:       bb2:
123 ; CHECK-NEXT:    br label [[BB3]]
124 ; CHECK:       bb3:
125 ; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 1
126 ; CHECK-NEXT:    store i32 1, ptr [[ARRAYIDX1]], align 4
127 ; CHECK-NEXT:    ret void
129 entry:
130   %arrayidx0 = getelementptr inbounds i32, ptr %P, i64 1
131   call void @llvm.memset.p0.i64(ptr %arrayidx0, i8 0, i64 28, i32 4, i1 false)
132   br i1 true, label %bb1, label %bb2
133 bb1:
134   br label %bb3
135 bb2:
136   br label %bb3
137 bb3:
138   %arrayidx1 = getelementptr inbounds i32, ptr %P, i64 1
139   store i32 1, ptr %arrayidx1, align 4
140   ret void
143 define ptr @test26() {
144 ; CHECK-LABEL: @test26(
145 ; CHECK-NEXT:  bb1:
146 ; CHECK-NEXT:    br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
147 ; CHECK:       bb2:
148 ; CHECK-NEXT:    [[M:%.*]] = call noalias ptr @malloc(i64 10)
149 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
150 ; CHECK-NEXT:    br label [[BB3]]
151 ; CHECK:       bb3:
152 ; CHECK-NEXT:    [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
153 ; CHECK-NEXT:    ret ptr [[R]]
155 bb1:
156   br i1 true, label %bb2, label %bb3
157 bb2:
158   %m = call noalias ptr @malloc(i64 10)
159   store i8 1, ptr %m
160   br label %bb3
161 bb3:
162   %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
163   ret ptr %r
167 define void @test27() {
168 ; CHECK-LABEL: @test27(
169 ; CHECK-NEXT:  bb1:
170 ; CHECK-NEXT:    br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
171 ; CHECK:       bb2:
172 ; CHECK-NEXT:    [[M:%.*]] = call noalias ptr @malloc(i64 10)
173 ; CHECK-NEXT:    br label [[BB3]]
174 ; CHECK:       bb3:
175 ; CHECK-NEXT:    [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
176 ; CHECK-NEXT:    ret void
178 bb1:
179   br i1 true, label %bb2, label %bb3
180 bb2:
181   %m = call noalias ptr @malloc(i64 10)
182   store i8 1, ptr %m
183   br label %bb3
184 bb3:
185   %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
186   ret void
189 define ptr @test27_pointer_escape() {
190 ; CHECK-LABEL: @test27_pointer_escape(
191 ; CHECK-NEXT:  bb1:
192 ; CHECK-NEXT:    br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
193 ; CHECK:       bb2:
194 ; CHECK-NEXT:    [[M:%.*]] = call noalias ptr @malloc(i64 10)
195 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
196 ; CHECK-NEXT:    br label [[BB3]]
197 ; CHECK:       bb3:
198 ; CHECK-NEXT:    [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
199 ; CHECK-NEXT:    ret ptr [[R]]
201 bb1:
202   br i1 true, label %bb2, label %bb3
203 bb2:
204   %m = call noalias ptr @malloc(i64 10)
205   store i8 1, ptr %m
206   br label %bb3
207 bb3:
208   %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
209   ret ptr %r
212 define ptr @test28() {
213 ; CHECK-LABEL: @test28(
214 ; CHECK-NEXT:  bb0:
215 ; CHECK-NEXT:    [[M:%.*]] = call noalias ptr @malloc(i64 10)
216 ; CHECK-NEXT:    store i8 2, ptr [[M]], align 1
217 ; CHECK-NEXT:    ret ptr [[M]]
219 bb0:
220   %m = call noalias ptr @malloc(i64 10)
221   store i8 2, ptr %m
222   ret ptr %m
225 %struct.SystemCallMapElementStruct = type { ptr, i32, ptr }
226 %struct.NodePtrVecStruct = type { i32, i32, ptr }
227 %struct.NodeStruct = type { i32, i32, ptr, i32, i32, ptr, ptr, ptr, i32, i32 }
228 %struct.NodeListStruct = type { ptr, ptr }
229 %struct.EdgeListStruct = type { i32, ptr, ptr }
230 %struct.SystemCallMapStruct = type { i32, i32, ptr }
232 declare ptr @NodePtrVec_new(i32)
234 define noalias ptr @SystemCallMapElement_new(ptr nocapture readonly %label, i32 %initialSize) {
235 ; CHECK-LABEL: @SystemCallMapElement_new(
236 ; CHECK-NEXT:  entry:
237 ; CHECK-NEXT:    [[CALL:%.*]] = tail call dereferenceable_or_null(24) ptr @malloc(i64 24) #[[ATTR7:[0-9]+]]
238 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[CALL]], null
239 ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[IF_THEN:%.*]]
240 ; CHECK:       if.then:
241 ; CHECK-NEXT:    [[CALL1:%.*]] = tail call ptr @strdup(ptr [[LABEL:%.*]])
242 ; CHECK-NEXT:    store ptr [[CALL1]], ptr [[CALL]], align 8
243 ; CHECK-NEXT:    [[INDEX:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
244 ; CHECK-NEXT:    store i32 -1, ptr [[INDEX]], align 8
245 ; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp eq ptr [[CALL1]], null
246 ; CHECK-NEXT:    br i1 [[TOBOOL4]], label [[IF_THEN5:%.*]], label [[IF_END:%.*]]
247 ; CHECK:       if.then5:
248 ; CHECK-NEXT:    tail call void @free(ptr nonnull [[CALL]])
249 ; CHECK-NEXT:    br label [[CLEANUP]]
250 ; CHECK:       if.end:
251 ; CHECK-NEXT:    [[CALL6:%.*]] = tail call ptr @NodePtrVec_new(i32 [[INITIALSIZE:%.*]]) #[[ATTR5:[0-9]+]]
252 ; CHECK-NEXT:    [[NODES:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 16
253 ; CHECK-NEXT:    store ptr [[CALL6]], ptr [[NODES]], align 8
254 ; CHECK-NEXT:    [[TOBOOL8:%.*]] = icmp eq ptr [[CALL6]], null
255 ; CHECK-NEXT:    br i1 [[TOBOOL8]], label [[IF_THEN9:%.*]], label [[CLEANUP]]
256 ; CHECK:       if.then9:
257 ; CHECK-NEXT:    tail call void @free(ptr nonnull [[CALL]])
258 ; CHECK-NEXT:    br label [[CLEANUP]]
259 ; CHECK:       cleanup:
260 ; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ null, [[IF_THEN9]] ], [ null, [[IF_THEN5]] ], [ [[CALL]], [[IF_END]] ], [ [[CALL]], [[ENTRY:%.*]] ]
261 ; CHECK-NEXT:    ret ptr [[RETVAL_0]]
263 entry:
264   %call = tail call dereferenceable_or_null(24) ptr @malloc(i64 24) #4
265   %tobool = icmp eq ptr %call, null
266   br i1 %tobool, label %cleanup, label %if.then
268 if.then:                                          ; preds = %entry
269   %call1 = tail call ptr @strdup(ptr %label)
270   store ptr %call1, ptr %call, align 8
271   %index = getelementptr inbounds i8, ptr %call, i64 8
272   store i32 -1, ptr %index, align 8
273   %tobool4 = icmp eq ptr %call1, null
274   br i1 %tobool4, label %if.then5, label %if.end
276 if.then5:                                         ; preds = %if.then
277   tail call void @free(ptr nonnull %call)
278   br label %cleanup
280 if.end:                                           ; preds = %if.then
281   %call6 = tail call ptr @NodePtrVec_new(i32 %initialSize) #2
282   %nodes = getelementptr inbounds i8, ptr %call, i64 16
283   store ptr %call6, ptr %nodes, align 8
284   %tobool8 = icmp eq ptr %call6, null
285   br i1 %tobool8, label %if.then9, label %cleanup
287 if.then9:                                         ; preds = %if.end
288   tail call void @free(ptr nonnull %call)
289   br label %cleanup
291 cleanup:                                          ; preds = %entry, %if.end, %if.then9, %if.then5
292   %retval.0 = phi ptr [ null, %if.then9 ], [ null, %if.then5 ], [ %call, %if.end ], [ %call, %entry ]
293   ret ptr %retval.0
296 %struct.BitfieldStruct = type { i32, ptr }
298 define noalias ptr @Bitfield_new(i32 %bitsNeeded) {
299 ; CHECK-LABEL: @Bitfield_new(
300 ; CHECK-NEXT:  entry:
301 ; CHECK-NEXT:    [[CALL:%.*]] = tail call dereferenceable_or_null(16) ptr @malloc(i64 16) #[[ATTR7]]
302 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq ptr [[CALL]], null
303 ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[IF_END:%.*]]
304 ; CHECK:       if.end:
305 ; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[BITSNEEDED:%.*]], 7
306 ; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD]], 8
307 ; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[DIV]] to i64
308 ; CHECK-NEXT:    [[CALL1:%.*]] = tail call ptr @calloc(i64 [[CONV]], i64 1) #[[ATTR8:[0-9]+]]
309 ; CHECK-NEXT:    [[BITFIELD:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
310 ; CHECK-NEXT:    store ptr [[CALL1]], ptr [[BITFIELD]], align 8
311 ; CHECK-NEXT:    [[TOBOOL3:%.*]] = icmp eq ptr [[CALL1]], null
312 ; CHECK-NEXT:    br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
313 ; CHECK:       if.then4:
314 ; CHECK-NEXT:    tail call void @free(ptr nonnull [[CALL]])
315 ; CHECK-NEXT:    br label [[CLEANUP]]
316 ; CHECK:       if.end5:
317 ; CHECK-NEXT:    store i32 [[BITSNEEDED]], ptr [[CALL]], align 8
318 ; CHECK-NEXT:    br label [[CLEANUP]]
319 ; CHECK:       cleanup:
320 ; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[CALL]], [[IF_END5]] ], [ null, [[IF_THEN4]] ], [ null, [[ENTRY:%.*]] ]
321 ; CHECK-NEXT:    ret ptr [[RETVAL_0]]
323 entry:
324   %call = tail call dereferenceable_or_null(16) ptr @malloc(i64 16) #4
325   %tobool = icmp eq ptr %call, null
326   br i1 %tobool, label %cleanup, label %if.end
328 if.end:                                           ; preds = %entry
329   %add = add nsw i32 %bitsNeeded, 7
330   %div = sdiv i32 %add, 8
331   %conv = sext i32 %div to i64
332   %call1 = tail call ptr @calloc(i64 %conv, i64 1) #3
333   %bitfield = getelementptr inbounds i8, ptr %call, i64 8
334   store ptr %call1, ptr %bitfield, align 8
335   %tobool3 = icmp eq ptr %call1, null
336   br i1 %tobool3, label %if.then4, label %if.end5
338 if.then4:                                         ; preds = %if.end
339   tail call void @free(ptr nonnull %call)
340   br label %cleanup
342 if.end5:                                          ; preds = %if.end
343   store i32 %bitsNeeded, ptr %call, align 8
344   br label %cleanup
346 cleanup:                                          ; preds = %entry, %if.end5, %if.then4
347   %retval.0 = phi ptr [ %call, %if.end5 ], [ null, %if.then4 ], [ null, %entry ]
348   ret ptr %retval.0
351 attributes #0 = { nofree nounwind allocsize(0) allockind("alloc,uninitialized") }
352 attributes #1 = { nofree nounwind }
353 attributes #2 = { nounwind allockind("free") }
354 attributes #3 = { allocsize(0,1) }
355 attributes #4 = { allocsize(0) }
356 attributes #5 = { nofree nounwind allocsize(0,1) allockind("alloc,zeroed") }