[rtsan] Add fork/execve interceptors (#117198)
[llvm-project.git] / llvm / test / Transforms / ObjCARC / nested.ll
blobd03cbd5f54e717958611f800a3b92c6dafb2a3c4
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)
19 declare ptr @def()
20 declare void @__crasher_block_invoke(ptr nocapture)
21 declare ptr @llvm.objc.retainBlock(ptr)
22 declare void @__crasher_block_invoke1(ptr nocapture)
24 !0 = !{}
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
31 ; CHECK: }
32 define void @test0(ptr %a) nounwind {
33 entry:
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
44 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
57 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
64 forcoll.mutated:
65   call void @llvm.objc.enumerationMutation(ptr %1)
66   br label %forcoll.notmutated
68 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
77 forcoll.refetch:
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
83 forcoll.empty:
84   call void @llvm.objc.release(ptr %1) nounwind
85   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
86   ret void
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
94 ; CHECK: }
95 define void @test2() nounwind {
96 entry:
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
108 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
121 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
128 forcoll.mutated:
129   call void @llvm.objc.enumerationMutation(ptr %1)
130   br label %forcoll.notmutated
132 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
141 forcoll.refetch:
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
147 forcoll.empty:
148   call void @llvm.objc.release(ptr %1) nounwind
149   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
150   ret void
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
158 ; CHECK: }
159 define void @test4() nounwind {
160 entry:
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
172 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
185 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
192 forcoll.mutated:
193   call void @llvm.objc.enumerationMutation(ptr %1)
194   br label %forcoll.notmutated
196 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
205 forcoll.refetch:
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
211 forcoll.empty:
212   call void @llvm.objc.release(ptr %1) nounwind
213   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
214   ret void
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
222 ; CHECK: }
223 define void @test5() nounwind {
224 entry:
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
236 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
249 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
256 forcoll.mutated:
257   call void @llvm.objc.enumerationMutation(ptr %1)
258   br label %forcoll.notmutated
260 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
269 forcoll.refetch:
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
275 forcoll.empty:
276   call void @llvm.objc.release(ptr %1) nounwind
277   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
278   ret void
281 ; We handle this now due to the fact that a release just needs a post dominating
282 ; use.
284 ; CHECK-LABEL: define void @test6(
285 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
286 ; CHECK-NOT: @llvm.objc.retain
287 ; CHECK: }
288 define void @test6() nounwind {
289 entry:
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
301 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
314 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
321 forcoll.mutated:
322   call void @llvm.objc.enumerationMutation(ptr %1)
323   br label %forcoll.notmutated
325 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
334 forcoll.refetch:
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
340 forcoll.empty:
341   call void @llvm.objc.release(ptr %1) nounwind
342   call void @callee()
343   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
344   ret void
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
354 ; CHECK: }
355 define void @test7() nounwind {
356 entry:
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
361   call void @callee()
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
369 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
382 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
389 forcoll.mutated:
390   call void @llvm.objc.enumerationMutation(ptr %1)
391   br label %forcoll.notmutated
393 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
402 forcoll.refetch:
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
408 forcoll.empty:
409   call void @llvm.objc.release(ptr %1) nounwind
410   call void @callee()
411   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
412   ret void
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
420 ; CHECK: }
421 define void @test8() nounwind {
422 entry:
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
434 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
447 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
454 forcoll.mutated:
455   call void @llvm.objc.enumerationMutation(ptr %1)
456   br label %forcoll.notmutated
458 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
465 if.then:
466   call void @callee()
467   br label %forcoll.next
469 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
474 forcoll.refetch:
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
480 forcoll.empty:
481   call void @llvm.objc.release(ptr %1) nounwind
482   call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
483   ret void
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
494 ; CHECK: }
495 define void @test9() nounwind {
496 entry:
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
510 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
522 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
529 forcoll.mutated:
530   call void @llvm.objc.enumerationMutation(ptr %2)
531   br label %forcoll.notmutated
533 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
541 forcoll.refetch:
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
547 forcoll.empty:
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
551   ret void
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
560 ; CHECK: }
561 define void @test9b() nounwind {
562 entry:
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
576 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
588 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
595 forcoll.mutated:
596   call void @llvm.objc.enumerationMutation(ptr %2)
597   br label %forcoll.notmutated
599 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
604 forcoll.refetch:
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
610 forcoll.empty:
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
614   ret void
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
625 ; CHECK: }
626 define void @test10() nounwind {
627 entry:
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
634   call void @callee()
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
642 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
654 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
661 forcoll.mutated:
662   call void @llvm.objc.enumerationMutation(ptr %2)
663   br label %forcoll.notmutated
665 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
673 forcoll.refetch:
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
679 forcoll.empty:
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
683   ret void
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
692 ; CHECK: }
693 define void @test10b() nounwind {
694 entry:
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
701   call void @callee()
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
709 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
721 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
728 forcoll.mutated:
729   call void @llvm.objc.enumerationMutation(ptr %2)
730   br label %forcoll.notmutated
732 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
737 forcoll.refetch:
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
743 forcoll.empty:
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
747   ret void
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
763 ; CHECK: }
764 define void @test11() {
765 entry:
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
806   ret void
810 ; CHECK: attributes [[NUW]] = { nounwind }
811 ; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }
812 ; CHECK: attributes #2 = { nonlazybind }