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:%.*]]
21 ; CHECK-NEXT: br label [[BB3]]
23 ; CHECK-NEXT: call void @free(ptr [[P:%.*]])
24 ; CHECK-NEXT: store i32 1, ptr [[P]], align 4
25 ; CHECK-NEXT: ret void
28 br i1 true, label %bb1, label %bb3
33 call void @free(ptr %P)
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:%.*]]
45 ; CHECK-NEXT: call void @unknown_func()
46 ; CHECK-NEXT: br label [[BB3]]
48 ; CHECK-NEXT: call void @free(ptr [[P]])
49 ; CHECK-NEXT: ret void
52 br i1 true, label %bb1, label %bb3
54 call void @unknown_func()
58 call void @free(ptr %P)
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:%.*]]
66 ; CHECK-NEXT: br label [[BB3]]
68 ; CHECK-NEXT: call void @free(ptr [[P:%.*]])
69 ; CHECK-NEXT: [[LV:%.*]] = load i8, ptr [[P]], align 1
70 ; CHECK-NEXT: ret void
73 br i1 true, label %bb1, label %bb3
78 call void @free(ptr %P)
83 define void @test19(ptr noalias %P) {
84 ; CHECK-LABEL: @test19(
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:%.*]]
90 ; CHECK-NEXT: br label [[BB3:%.*]]
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]]
96 ; CHECK-NEXT: ret void
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
105 %arrayidx1 = getelementptr inbounds i32, ptr %P, i64 1
106 store i32 1, ptr %arrayidx1, align 4
113 define void @test20(ptr noalias %P) {
114 ; CHECK-LABEL: @test20(
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:%.*]]
121 ; CHECK-NEXT: br label [[BB3:%.*]]
123 ; CHECK-NEXT: br label [[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
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
138 %arrayidx1 = getelementptr inbounds i32, ptr %P, i64 1
139 store i32 1, ptr %arrayidx1, align 4
143 define ptr @test26() {
144 ; CHECK-LABEL: @test26(
146 ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
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]]
152 ; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
153 ; CHECK-NEXT: ret ptr [[R]]
156 br i1 true, label %bb2, label %bb3
158 %m = call noalias ptr @malloc(i64 10)
162 %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
167 define void @test27() {
168 ; CHECK-LABEL: @test27(
170 ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
172 ; CHECK-NEXT: [[M:%.*]] = call noalias ptr @malloc(i64 10)
173 ; CHECK-NEXT: br label [[BB3]]
175 ; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
176 ; CHECK-NEXT: ret void
179 br i1 true, label %bb2, label %bb3
181 %m = call noalias ptr @malloc(i64 10)
185 %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
189 define ptr @test27_pointer_escape() {
190 ; CHECK-LABEL: @test27_pointer_escape(
192 ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB3:%.*]]
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]]
198 ; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ]
199 ; CHECK-NEXT: ret ptr [[R]]
202 br i1 true, label %bb2, label %bb3
204 %m = call noalias ptr @malloc(i64 10)
208 %r = phi ptr [ null, %bb1 ], [ %m, %bb2 ]
212 define ptr @test28() {
213 ; CHECK-LABEL: @test28(
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]]
220 %m = call noalias ptr @malloc(i64 10)
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(
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:%.*]]
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:%.*]]
248 ; CHECK-NEXT: tail call void @free(ptr nonnull [[CALL]])
249 ; CHECK-NEXT: br label [[CLEANUP]]
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]]
257 ; CHECK-NEXT: tail call void @free(ptr nonnull [[CALL]])
258 ; CHECK-NEXT: br label [[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]]
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)
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)
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 ]
296 %struct.BitfieldStruct = type { i32, ptr }
298 define noalias ptr @Bitfield_new(i32 %bitsNeeded) {
299 ; CHECK-LABEL: @Bitfield_new(
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:%.*]]
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:%.*]]
314 ; CHECK-NEXT: tail call void @free(ptr nonnull [[CALL]])
315 ; CHECK-NEXT: br label [[CLEANUP]]
317 ; CHECK-NEXT: store i32 [[BITSNEEDED]], ptr [[CALL]], align 8
318 ; CHECK-NEXT: br label [[CLEANUP]]
320 ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[CALL]], [[IF_END5]] ], [ null, [[IF_THEN4]] ], [ null, [[ENTRY:%.*]] ]
321 ; CHECK-NEXT: ret ptr [[RETVAL_0]]
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)
342 if.end5: ; preds = %if.end
343 store i32 %bitsNeeded, ptr %call, align 8
346 cleanup: ; preds = %entry, %if.end5, %if.then4
347 %retval.0 = phi ptr [ %call, %if.end5 ], [ null, %if.then4 ], [ null, %entry ]
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") }