xref: /llvm-project/llvm/test/Transforms/ObjCARC/nested.ll (revision 01e4f41b43b57dee751146fde9992c660bd7c714)
1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
2
3%struct.__objcFastEnumerationState = type { i64, ptr, ptr, [5 x i64] }
4
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"
9
10declare void @callee()
11declare ptr @returner()
12declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
13declare ptr @llvm.objc.retain(ptr)
14declare void @llvm.objc.enumerationMutation(ptr)
15declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
16declare ptr @objc_msgSend(ptr, ptr, ...) nonlazybind
17declare void @use(ptr)
18declare void @llvm.objc.release(ptr)
19declare ptr @def()
20declare void @__crasher_block_invoke(ptr nocapture)
21declare ptr @llvm.objc.retainBlock(ptr)
22declare void @__crasher_block_invoke1(ptr nocapture)
23
24!0 = !{}
25
26; Delete a nested retain+release pair.
27
28; CHECK-LABEL: define void @test0(
29; CHECK: call ptr @llvm.objc.retain
30; CHECK-NOT: @llvm.objc.retain
31; CHECK: }
32define void @test0(ptr %a) nounwind {
33entry:
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
43
44forcoll.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
50
51forcoll.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
56
57forcoll.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
63
64forcoll.mutated:
65  call void @llvm.objc.enumerationMutation(ptr %1)
66  br label %forcoll.notmutated
67
68forcoll.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
76
77forcoll.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
82
83forcoll.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
87}
88
89; Delete a nested retain+release pair.
90
91; CHECK-LABEL: define void @test2(
92; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
93; CHECK-NOT: @llvm.objc.retain
94; CHECK: }
95define void @test2() nounwind {
96entry:
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
107
108forcoll.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
114
115forcoll.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
120
121forcoll.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
127
128forcoll.mutated:
129  call void @llvm.objc.enumerationMutation(ptr %1)
130  br label %forcoll.notmutated
131
132forcoll.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
140
141forcoll.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
146
147forcoll.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
151}
152
153; Delete a nested retain+release pair.
154
155; CHECK-LABEL: define void @test4(
156; CHECK: call ptr @llvm.objc.retain
157; CHECK-NOT: @llvm.objc.retain
158; CHECK: }
159define void @test4() nounwind {
160entry:
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
171
172forcoll.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
178
179forcoll.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
184
185forcoll.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
191
192forcoll.mutated:
193  call void @llvm.objc.enumerationMutation(ptr %1)
194  br label %forcoll.notmutated
195
196forcoll.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
204
205forcoll.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
210
211forcoll.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
215}
216
217; Delete a nested retain+release pair.
218
219; CHECK-LABEL: define void @test5(
220; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
221; CHECK-NOT: @llvm.objc.retain
222; CHECK: }
223define void @test5() nounwind {
224entry:
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
235
236forcoll.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
242
243forcoll.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
248
249forcoll.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
255
256forcoll.mutated:
257  call void @llvm.objc.enumerationMutation(ptr %1)
258  br label %forcoll.notmutated
259
260forcoll.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
268
269forcoll.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
274
275forcoll.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
279}
280
281; We handle this now due to the fact that a release just needs a post dominating
282; use.
283;
284; CHECK-LABEL: define void @test6(
285; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
286; CHECK-NOT: @llvm.objc.retain
287; CHECK: }
288define void @test6() nounwind {
289entry:
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
300
301forcoll.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
307
308forcoll.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
313
314forcoll.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
320
321forcoll.mutated:
322  call void @llvm.objc.enumerationMutation(ptr %1)
323  br label %forcoll.notmutated
324
325forcoll.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
333
334forcoll.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
339
340forcoll.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
345}
346
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.
350
351; CHECK-LABEL: define void @test7(
352; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
353; CHECK: @llvm.objc.retain
354; CHECK: }
355define void @test7() nounwind {
356entry:
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
368
369forcoll.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
375
376forcoll.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
381
382forcoll.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
388
389forcoll.mutated:
390  call void @llvm.objc.enumerationMutation(ptr %1)
391  br label %forcoll.notmutated
392
393forcoll.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
401
402forcoll.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
407
408forcoll.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
413}
414
415; Delete a nested retain+release pair.
416
417; CHECK-LABEL: define void @test8(
418; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
419; CHECK-NOT: @llvm.objc.retain
420; CHECK: }
421define void @test8() nounwind {
422entry:
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
433
434forcoll.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
440
441forcoll.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
446
447forcoll.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
453
454forcoll.mutated:
455  call void @llvm.objc.enumerationMutation(ptr %1)
456  br label %forcoll.notmutated
457
458forcoll.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
464
465if.then:
466  call void @callee()
467  br label %forcoll.next
468
469forcoll.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
473
474forcoll.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
479
480forcoll.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
484}
485
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.
489
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: }
495define void @test9() nounwind {
496entry:
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
509
510forcoll.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
515
516forcoll.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
521
522forcoll.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
528
529forcoll.mutated:
530  call void @llvm.objc.enumerationMutation(ptr %2)
531  br label %forcoll.notmutated
532
533forcoll.notmutated:
534  %exitcond = icmp eq i64 %forcoll.index, %umax
535  br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge
536
537forcoll.notmutated.forcoll.loopbody_crit_edge:
538  %phitmp = add i64 %forcoll.index, 1
539  br label %forcoll.loopbody
540
541forcoll.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
546
547forcoll.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
552}
553
554; Like test9, but without a split backedge. TODO: optimize this.
555
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: }
561define void @test9b() nounwind {
562entry:
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
575
576forcoll.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
581
582forcoll.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
587
588forcoll.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
594
595forcoll.mutated:
596  call void @llvm.objc.enumerationMutation(ptr %2)
597  br label %forcoll.notmutated
598
599forcoll.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
603
604forcoll.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
609
610forcoll.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
615}
616
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.
620
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: }
626define void @test10() nounwind {
627entry:
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
641
642forcoll.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
647
648forcoll.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
653
654forcoll.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
660
661forcoll.mutated:
662  call void @llvm.objc.enumerationMutation(ptr %2)
663  br label %forcoll.notmutated
664
665forcoll.notmutated:
666  %exitcond = icmp eq i64 %forcoll.index, %umax
667  br i1 %exitcond, label %forcoll.refetch, label %forcoll.notmutated.forcoll.loopbody_crit_edge
668
669forcoll.notmutated.forcoll.loopbody_crit_edge:
670  %phitmp = add i64 %forcoll.index, 1
671  br label %forcoll.loopbody
672
673forcoll.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
678
679forcoll.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
684}
685
686; Like test10, but without a split backedge. TODO: optimize this.
687
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: }
693define void @test10b() nounwind {
694entry:
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
708
709forcoll.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
714
715forcoll.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
720
721forcoll.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
727
728forcoll.mutated:
729  call void @llvm.objc.enumerationMutation(ptr %2)
730  br label %forcoll.notmutated
731
732forcoll.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
736
737forcoll.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
742
743forcoll.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
748}
749
750; Pointers to strong pointers can obscure provenance relationships. Be conservative
751; in the face of escaping pointers. rdar://12150909.
752
753%struct.__block_d = type { i64, i64 }
754
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 }
758
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: }
764define void @test11() {
765entry:
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
807}
808
809
810; CHECK: attributes [[NUW]] = { nounwind }
811; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }
812; CHECK: attributes #2 = { nonlazybind }
813