1 ; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
3 %struct.__objcFastEnumerationState = type { i64, ptr, ptr, [5 x i64] }
5 @"\01L_OBJC_METH_VAR_NAME_" = internal global [43 x i8] c"countByEnumeratingWithState:objects:count:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
6 @"\01L_OBJC_SELECTOR_REFERENCES_" = internal global ptr @"\01L_OBJC_METH_VAR_NAME_", section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
7 @g = common global ptr null, align 8
8 @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"
10 declare void @callee()
11 declare ptr @returner()
12 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
13 declare ptr @llvm.objc.retain(ptr)
14 declare void @llvm.objc.enumerationMutation(ptr)
15 declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
16 declare ptr @objc_msgSend(ptr, ptr, ...) nonlazybind
17 declare void @use(ptr)
18 declare void @llvm.objc.release(ptr)
20 declare void @__crasher_block_invoke(ptr nocapture)
21 declare ptr @llvm.objc.retainBlock(ptr)
22 declare void @__crasher_block_invoke1(ptr nocapture)
26 ; Delete a nested retain+release pair.
28 ; CHECK-LABEL: define void @test0(
29 ; CHECK: call ptr @llvm.objc.retain
30 ; CHECK-NOT: @llvm.objc.retain
32 define void @test0(ptr %a) nounwind {
34 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
35 %items.ptr = alloca [16 x ptr], align 8
36 %0 = call ptr @llvm.objc.retain(ptr %a) nounwind
37 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
38 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
39 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
40 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
41 %iszero = icmp eq i64 %call, 0
42 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
45 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
46 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
47 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
48 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
49 br label %forcoll.loopbody.outer
51 forcoll.loopbody.outer:
52 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call6, %forcoll.refetch ]
53 %tmp7 = icmp ugt i64 %forcoll.count.ph, 1
54 %umax = select i1 %tmp7, i64 %forcoll.count.ph, i64 1
55 br label %forcoll.loopbody
58 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
59 %mutationsptr3 = load ptr, ptr %mutationsptr.ptr, align 8
60 %statemutations = load i64, ptr %mutationsptr3, align 8
61 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
62 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
65 call void @llvm.objc.enumerationMutation(ptr %1)
66 br label %forcoll.notmutated
69 %stateitems = load ptr, ptr %stateitems.ptr, align 8
70 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
71 %3 = load ptr, ptr %currentitem.ptr, align 8
72 call void @use(ptr %3)
73 %4 = add i64 %forcoll.index, 1
74 %exitcond = icmp eq i64 %4, %umax
75 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
78 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
79 %call6 = call i64 @objc_msgSend(ptr %1, ptr %tmp5, ptr %state.ptr, ptr %items.ptr, i64 16)
80 %5 = icmp eq i64 %call6, 0
81 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
84 call void @llvm.objc.release(ptr %1) nounwind
85 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
89 ; Delete a nested retain+release pair.
91 ; CHECK-LABEL: define void @test2(
92 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
93 ; CHECK-NOT: @llvm.objc.retain
95 define void @test2() nounwind {
97 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
98 %items.ptr = alloca [16 x ptr], align 8
99 %call = call ptr @returner()
100 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
101 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
102 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
103 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
104 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
105 %iszero = icmp eq i64 %call3, 0
106 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
109 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
110 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
111 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
112 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
113 br label %forcoll.loopbody.outer
115 forcoll.loopbody.outer:
116 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
117 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1
118 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1
119 br label %forcoll.loopbody
122 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
123 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8
124 %statemutations = load i64, ptr %mutationsptr4, align 8
125 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
126 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
129 call void @llvm.objc.enumerationMutation(ptr %1)
130 br label %forcoll.notmutated
133 %stateitems = load ptr, ptr %stateitems.ptr, align 8
134 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
135 %3 = load ptr, ptr %currentitem.ptr, align 8
136 call void @use(ptr %3)
137 %4 = add i64 %forcoll.index, 1
138 %exitcond = icmp eq i64 %4, %umax
139 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
142 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
143 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
144 %5 = icmp eq i64 %call7, 0
145 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
148 call void @llvm.objc.release(ptr %1) nounwind
149 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
153 ; Delete a nested retain+release pair.
155 ; CHECK-LABEL: define void @test4(
156 ; CHECK: call ptr @llvm.objc.retain
157 ; CHECK-NOT: @llvm.objc.retain
159 define void @test4() nounwind {
161 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
162 %items.ptr = alloca [16 x ptr], align 8
163 %tmp = load ptr, ptr @g, align 8
164 %0 = call ptr @llvm.objc.retain(ptr %tmp) nounwind
165 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
166 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
167 %tmp4 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
168 %call = call i64 @objc_msgSend(ptr %1, ptr %tmp4, ptr %state.ptr, ptr %items.ptr, i64 16)
169 %iszero = icmp eq i64 %call, 0
170 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
173 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
174 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
175 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
176 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
177 br label %forcoll.loopbody.outer
179 forcoll.loopbody.outer:
180 %forcoll.count.ph = phi i64 [ %call, %forcoll.loopinit ], [ %call8, %forcoll.refetch ]
181 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1
182 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1
183 br label %forcoll.loopbody
186 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
187 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8
188 %statemutations = load i64, ptr %mutationsptr5, align 8
189 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
190 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
193 call void @llvm.objc.enumerationMutation(ptr %1)
194 br label %forcoll.notmutated
197 %stateitems = load ptr, ptr %stateitems.ptr, align 8
198 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
199 %3 = load ptr, ptr %currentitem.ptr, align 8
200 call void @use(ptr %3)
201 %4 = add i64 %forcoll.index, 1
202 %exitcond = icmp eq i64 %4, %umax
203 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
206 %tmp7 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
207 %call8 = call i64 @objc_msgSend(ptr %1, ptr %tmp7, ptr %state.ptr, ptr %items.ptr, i64 16)
208 %5 = icmp eq i64 %call8, 0
209 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
212 call void @llvm.objc.release(ptr %1) nounwind
213 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
217 ; Delete a nested retain+release pair.
219 ; CHECK-LABEL: define void @test5(
220 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
221 ; CHECK-NOT: @llvm.objc.retain
223 define void @test5() nounwind {
225 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
226 %items.ptr = alloca [16 x ptr], align 8
227 %call = call ptr @returner()
228 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
229 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
230 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
231 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
232 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
233 %iszero = icmp eq i64 %call3, 0
234 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
237 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
238 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
239 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
240 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
241 br label %forcoll.loopbody.outer
243 forcoll.loopbody.outer:
244 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
245 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1
246 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1
247 br label %forcoll.loopbody
250 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
251 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8
252 %statemutations = load i64, ptr %mutationsptr4, align 8
253 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
254 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
257 call void @llvm.objc.enumerationMutation(ptr %1)
258 br label %forcoll.notmutated
261 %stateitems = load ptr, ptr %stateitems.ptr, align 8
262 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
263 %3 = load ptr, ptr %currentitem.ptr, align 8
264 call void @use(ptr %3)
265 %4 = add i64 %forcoll.index, 1
266 %exitcond = icmp eq i64 %4, %umax
267 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
270 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
271 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
272 %5 = icmp eq i64 %call7, 0
273 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
276 call void @llvm.objc.release(ptr %1) nounwind
277 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
281 ; We handle this now due to the fact that a release just needs a post dominating
284 ; CHECK-LABEL: define void @test6(
285 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
286 ; CHECK-NOT: @llvm.objc.retain
288 define void @test6() nounwind {
290 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
291 %items.ptr = alloca [16 x ptr], align 8
292 %call = call ptr @returner()
293 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
294 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
295 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
296 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
297 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
298 %iszero = icmp eq i64 %call3, 0
299 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
302 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
303 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
304 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
305 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
306 br label %forcoll.loopbody.outer
308 forcoll.loopbody.outer:
309 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
310 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1
311 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1
312 br label %forcoll.loopbody
315 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
316 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8
317 %statemutations = load i64, ptr %mutationsptr4, align 8
318 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
319 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
322 call void @llvm.objc.enumerationMutation(ptr %1)
323 br label %forcoll.notmutated
326 %stateitems = load ptr, ptr %stateitems.ptr, align 8
327 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
328 %3 = load ptr, ptr %currentitem.ptr, align 8
329 call void @use(ptr %3)
330 %4 = add i64 %forcoll.index, 1
331 %exitcond = icmp eq i64 %4, %umax
332 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
335 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
336 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
337 %5 = icmp eq i64 %call7, 0
338 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
341 call void @llvm.objc.release(ptr %1) nounwind
343 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
347 ; TODO: Delete a nested retain+release pair.
348 ; The optimizer currently can't do this, because isn't isn't sophisticated enough in
349 ; reasnoning about nesting.
351 ; CHECK-LABEL: define void @test7(
352 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
353 ; CHECK: @llvm.objc.retain
355 define void @test7() nounwind {
357 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
358 %items.ptr = alloca [16 x ptr], align 8
359 %call = call ptr @returner()
360 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
362 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
363 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
364 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
365 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
366 %iszero = icmp eq i64 %call3, 0
367 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
370 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
371 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
372 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
373 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
374 br label %forcoll.loopbody.outer
376 forcoll.loopbody.outer:
377 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
378 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1
379 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1
380 br label %forcoll.loopbody
383 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.notmutated ]
384 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8
385 %statemutations = load i64, ptr %mutationsptr4, align 8
386 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
387 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
390 call void @llvm.objc.enumerationMutation(ptr %1)
391 br label %forcoll.notmutated
394 %stateitems = load ptr, ptr %stateitems.ptr, align 8
395 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
396 %3 = load ptr, ptr %currentitem.ptr, align 8
397 call void @use(ptr %3)
398 %4 = add i64 %forcoll.index, 1
399 %exitcond = icmp eq i64 %4, %umax
400 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
403 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
404 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
405 %5 = icmp eq i64 %call7, 0
406 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
409 call void @llvm.objc.release(ptr %1) nounwind
411 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
415 ; Delete a nested retain+release pair.
417 ; CHECK-LABEL: define void @test8(
418 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
419 ; CHECK-NOT: @llvm.objc.retain
421 define void @test8() nounwind {
423 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
424 %items.ptr = alloca [16 x ptr], align 8
425 %call = call ptr @returner()
426 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
427 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
428 %1 = call ptr @llvm.objc.retain(ptr %0) nounwind
429 %tmp2 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
430 %call3 = call i64 @objc_msgSend(ptr %1, ptr %tmp2, ptr %state.ptr, ptr %items.ptr, i64 16)
431 %iszero = icmp eq i64 %call3, 0
432 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
435 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
436 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
437 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
438 %stateitems.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 1
439 br label %forcoll.loopbody.outer
441 forcoll.loopbody.outer:
442 %forcoll.count.ph = phi i64 [ %call3, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
443 %tmp8 = icmp ugt i64 %forcoll.count.ph, 1
444 %umax = select i1 %tmp8, i64 %forcoll.count.ph, i64 1
445 br label %forcoll.loopbody
448 %forcoll.index = phi i64 [ 0, %forcoll.loopbody.outer ], [ %4, %forcoll.next ]
449 %mutationsptr4 = load ptr, ptr %mutationsptr.ptr, align 8
450 %statemutations = load i64, ptr %mutationsptr4, align 8
451 %2 = icmp eq i64 %statemutations, %forcoll.initial-mutations
452 br i1 %2, label %forcoll.notmutated, label %forcoll.mutated
455 call void @llvm.objc.enumerationMutation(ptr %1)
456 br label %forcoll.notmutated
459 %stateitems = load ptr, ptr %stateitems.ptr, align 8
460 %currentitem.ptr = getelementptr ptr, ptr %stateitems, i64 %forcoll.index
461 %3 = load ptr, ptr %currentitem.ptr, align 8
462 %tobool = icmp eq ptr %3, null
463 br i1 %tobool, label %forcoll.next, label %if.then
467 br label %forcoll.next
470 %4 = add i64 %forcoll.index, 1
471 %exitcond = icmp eq i64 %4, %umax
472 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
475 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
476 %call7 = call i64 @objc_msgSend(ptr %1, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
477 %5 = icmp eq i64 %call7, 0
478 br i1 %5, label %forcoll.empty, label %forcoll.loopbody.outer
481 call void @llvm.objc.release(ptr %1) nounwind
482 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
486 ; TODO: Delete a nested retain+release pair.
487 ; The optimizer currently can't do this, because of a split loop backedge.
488 ; See test9b for the same testcase without a split backedge.
490 ; CHECK-LABEL: define void @test9(
491 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
492 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
493 ; CHECK: call ptr @llvm.objc.retain
495 define void @test9() nounwind {
497 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
498 %items.ptr = alloca [16 x ptr], align 8
499 %call = call ptr @returner()
500 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
501 %call1 = call ptr @returner()
502 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind
503 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
504 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind
505 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
506 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)
507 %iszero = icmp eq i64 %call4, 0
508 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
511 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
512 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
513 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
514 br label %forcoll.loopbody.outer
516 forcoll.loopbody.outer:
517 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
518 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1
519 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1
520 br label %forcoll.loopbody
523 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated.forcoll.loopbody_crit_edge ], [ 1, %forcoll.loopbody.outer ]
524 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8
525 %statemutations = load i64, ptr %mutationsptr5, align 8
526 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations
527 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated
530 call void @llvm.objc.enumerationMutation(ptr %2)
531 br label %forcoll.notmutated
534 %exitcond = icmp eq i64 %forcoll.index, %umax
535 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge
537 forcoll.notmutated.forcoll.loopbody_crit_edge:
538 %phitmp = add i64 %forcoll.index, 1
539 br label %forcoll.loopbody
542 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
543 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
544 %4 = icmp eq i64 %call7, 0
545 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer
548 call void @llvm.objc.release(ptr %2) nounwind
549 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0
550 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
554 ; Like test9, but without a split backedge. TODO: optimize this.
556 ; CHECK-LABEL: define void @test9b(
557 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
558 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
559 ; CHECK: @llvm.objc.retain
561 define void @test9b() nounwind {
563 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
564 %items.ptr = alloca [16 x ptr], align 8
565 %call = call ptr @returner()
566 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
567 %call1 = call ptr @returner()
568 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind
569 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
570 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind
571 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
572 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)
573 %iszero = icmp eq i64 %call4, 0
574 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
577 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
578 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
579 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
580 br label %forcoll.loopbody.outer
582 forcoll.loopbody.outer:
583 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
584 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1
585 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1
586 br label %forcoll.loopbody
589 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ]
590 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8
591 %statemutations = load i64, ptr %mutationsptr5, align 8
592 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations
593 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated
596 call void @llvm.objc.enumerationMutation(ptr %2)
597 br label %forcoll.notmutated
600 %phitmp = add i64 %forcoll.index, 1
601 %exitcond = icmp eq i64 %phitmp, %umax
602 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
605 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
606 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
607 %4 = icmp eq i64 %call7, 0
608 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer
611 call void @llvm.objc.release(ptr %2) nounwind
612 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0
613 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
617 ; TODO: Delete a nested retain+release pair.
618 ; The optimizer currently can't do this, because of a split loop backedge.
619 ; See test10b for the same testcase without a split backedge.
621 ; CHECK-LABEL: define void @test10(
622 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
623 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
624 ; CHECK: call ptr @llvm.objc.retain
626 define void @test10() nounwind {
628 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
629 %items.ptr = alloca [16 x ptr], align 8
630 %call = call ptr @returner()
631 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
632 %call1 = call ptr @returner()
633 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind
635 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
636 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind
637 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
638 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)
639 %iszero = icmp eq i64 %call4, 0
640 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
643 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
644 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
645 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
646 br label %forcoll.loopbody.outer
648 forcoll.loopbody.outer:
649 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
650 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1
651 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1
652 br label %forcoll.loopbody
655 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated.forcoll.loopbody_crit_edge ], [ 1, %forcoll.loopbody.outer ]
656 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8
657 %statemutations = load i64, ptr %mutationsptr5, align 8
658 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations
659 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated
662 call void @llvm.objc.enumerationMutation(ptr %2)
663 br label %forcoll.notmutated
666 %exitcond = icmp eq i64 %forcoll.index, %umax
667 br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge
669 forcoll.notmutated.forcoll.loopbody_crit_edge:
670 %phitmp = add i64 %forcoll.index, 1
671 br label %forcoll.loopbody
674 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
675 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
676 %4 = icmp eq i64 %call7, 0
677 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer
680 call void @llvm.objc.release(ptr %2) nounwind
681 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0
682 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
686 ; Like test10, but without a split backedge. TODO: optimize this.
688 ; CHECK-LABEL: define void @test10b(
689 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
690 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
691 ; CHECK: @llvm.objc.retain
693 define void @test10b() nounwind {
695 %state.ptr = alloca %struct.__objcFastEnumerationState, align 8
696 %items.ptr = alloca [16 x ptr], align 8
697 %call = call ptr @returner()
698 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
699 %call1 = call ptr @returner()
700 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1) nounwind
702 call void @llvm.memset.p0.i64(ptr align 8 %state.ptr, i8 0, i64 64, i1 false)
703 %2 = call ptr @llvm.objc.retain(ptr %0) nounwind
704 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
705 %call4 = call i64 @objc_msgSend(ptr %2, ptr %tmp3, ptr %state.ptr, ptr %items.ptr, i64 16)
706 %iszero = icmp eq i64 %call4, 0
707 br i1 %iszero, label %forcoll.empty, label %forcoll.loopinit
710 %mutationsptr.ptr = getelementptr inbounds %struct.__objcFastEnumerationState, ptr %state.ptr, i64 0, i32 2
711 %mutationsptr = load ptr, ptr %mutationsptr.ptr, align 8
712 %forcoll.initial-mutations = load i64, ptr %mutationsptr, align 8
713 br label %forcoll.loopbody.outer
715 forcoll.loopbody.outer:
716 %forcoll.count.ph = phi i64 [ %call4, %forcoll.loopinit ], [ %call7, %forcoll.refetch ]
717 %tmp9 = icmp ugt i64 %forcoll.count.ph, 1
718 %umax = select i1 %tmp9, i64 %forcoll.count.ph, i64 1
719 br label %forcoll.loopbody
722 %forcoll.index = phi i64 [ %phitmp, %forcoll.notmutated ], [ 0, %forcoll.loopbody.outer ]
723 %mutationsptr5 = load ptr, ptr %mutationsptr.ptr, align 8
724 %statemutations = load i64, ptr %mutationsptr5, align 8
725 %3 = icmp eq i64 %statemutations, %forcoll.initial-mutations
726 br i1 %3, label %forcoll.notmutated, label %forcoll.mutated
729 call void @llvm.objc.enumerationMutation(ptr %2)
730 br label %forcoll.notmutated
733 %phitmp = add i64 %forcoll.index, 1
734 %exitcond = icmp eq i64 %phitmp, %umax
735 br i1 %exitcond, label %forcoll.refetch, label %forcoll.loopbody
738 %tmp6 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
739 %call7 = call i64 @objc_msgSend(ptr %2, ptr %tmp6, ptr %state.ptr, ptr %items.ptr, i64 16)
740 %4 = icmp eq i64 %call7, 0
741 br i1 %4, label %forcoll.empty, label %forcoll.loopbody.outer
744 call void @llvm.objc.release(ptr %2) nounwind
745 call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0
746 call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
750 ; Pointers to strong pointers can obscure provenance relationships. Be conservative
751 ; in the face of escaping pointers. rdar://12150909.
753 %struct.__block_d = type { i64, i64 }
755 @_NSConcreteStackBlock = external global ptr
756 @__block_d_tmp = external hidden constant { i64, i64, ptr, ptr, ptr, ptr }
757 @__block_d_tmp5 = external hidden constant { i64, i64, ptr, ptr, ptr, ptr }
759 ; CHECK-LABEL: define void @test11(
760 ; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW:#[0-9]+]]
761 ; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW]]
762 ; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]], !clang.imprecise_release !0
764 define void @test11() {
766 %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
767 %block9 = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
768 %call = call ptr @def(), !clang.arc.no_objc_arc_exceptions !0
769 %foo = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 5
770 %block.isa = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 0
771 store ptr @_NSConcreteStackBlock, ptr %block.isa, align 8
772 %block.flags = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 1
773 store i32 1107296256, ptr %block.flags, align 8
774 %block.reserved = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 2
775 store i32 0, ptr %block.reserved, align 4
776 %block.invoke = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 3
777 store ptr @__crasher_block_invoke, ptr %block.invoke, align 8
778 %block.d = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block, i64 0, i32 4
779 store ptr @__block_d_tmp, ptr %block.d, align 8
780 %foo2 = tail call ptr @llvm.objc.retain(ptr %call) nounwind
781 store ptr %foo2, ptr %foo, align 8
782 %foo5 = call ptr @llvm.objc.retainBlock(ptr %block) nounwind
783 call void @use(ptr %foo5), !clang.arc.no_objc_arc_exceptions !0
784 call void @llvm.objc.release(ptr %foo5) nounwind
785 %strongdestroy = load ptr, ptr %foo, align 8
786 call void @llvm.objc.release(ptr %strongdestroy) nounwind, !clang.imprecise_release !0
787 %foo10 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 5
788 %block.isa11 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 0
789 store ptr @_NSConcreteStackBlock, ptr %block.isa11, align 8
790 %block.flags12 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 1
791 store i32 1107296256, ptr %block.flags12, align 8
792 %block.reserved13 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 2
793 store i32 0, ptr %block.reserved13, align 4
794 %block.invoke14 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 3
795 store ptr @__crasher_block_invoke1, ptr %block.invoke14, align 8
796 %block.d15 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %block9, i64 0, i32 4
797 store ptr @__block_d_tmp5, ptr %block.d15, align 8
798 %foo18 = call ptr @llvm.objc.retain(ptr %call) nounwind
799 store ptr %call, ptr %foo10, align 8
800 %foo21 = call ptr @llvm.objc.retainBlock(ptr %block9) nounwind
801 call void @use(ptr %foo21), !clang.arc.no_objc_arc_exceptions !0
802 call void @llvm.objc.release(ptr %foo21) nounwind
803 %strongdestroy25 = load ptr, ptr %foo10, align 8
804 call void @llvm.objc.release(ptr %strongdestroy25) nounwind, !clang.imprecise_release !0
805 call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0
810 ; CHECK: attributes [[NUW]] = { nounwind }
811 ; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }
812 ; CHECK: attributes #2 = { nonlazybind }