1 ; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
3 declare ptr @llvm.objc.retain(ptr)
4 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
5 declare void @llvm.objc.release(ptr)
6 declare ptr @llvm.objc.autorelease(ptr)
7 declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
8 declare void @llvm.objc.autoreleasePoolPop(ptr)
9 declare ptr @llvm.objc.autoreleasePoolPush()
10 declare ptr @llvm.objc.retainBlock(ptr)
12 declare ptr @objc_retainedObject(ptr)
13 declare ptr @objc_unretainedObject(ptr)
14 declare ptr @objc_unretainedPointer(ptr)
16 declare void @use_pointer(ptr)
17 declare void @callee()
18 declare void @callee_fnptr(ptr)
19 declare void @invokee()
20 declare ptr @returner()
21 declare ptr @returner1()
22 declare ptr @returner2()
23 declare void @bar(ptr)
24 declare void @use_alloca(ptr)
26 declare void @llvm.dbg.value(metadata, metadata, metadata)
28 declare ptr @objc_msgSend(ptr, ptr, ...)
31 ; In the presence of allocas, unconditionally remove retain/release pairs only
32 ; if they are known safe in both directions. This prevents matching up an inner
33 ; retain with the boundary guarding release in the following situation:
37 ; retain(%x) <--- Inner Retain
42 ; release(%x) <--- Guarding Release
46 ; CHECK: define void @test1a(ptr %x)
47 ; CHECK: @llvm.objc.retain(ptr %x)
48 ; CHECK: @llvm.objc.retain(ptr %x)
49 ; CHECK: @llvm.objc.release(ptr %y)
50 ; CHECK: @llvm.objc.release(ptr %x)
53 define void @test1a(ptr %x) {
56 tail call ptr @llvm.objc.retain(ptr %x)
57 tail call ptr @llvm.objc.retain(ptr %x)
58 store ptr %x, ptr %A, align 8
60 call void @use_alloca(ptr %A)
61 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
62 call void @use_pointer(ptr %x)
63 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
67 ; CHECK: define void @test1b(ptr %x)
68 ; CHECK: @llvm.objc.retain(ptr %x)
69 ; CHECK: @llvm.objc.retain(ptr %x)
70 ; CHECK: @llvm.objc.release(ptr %y)
71 ; CHECK: @llvm.objc.release(ptr %x)
74 define void @test1b(ptr %x) {
77 tail call ptr @llvm.objc.retain(ptr %x)
78 tail call ptr @llvm.objc.retain(ptr %x)
79 store ptr %x, ptr %A, align 8
81 call void @use_alloca(ptr %A)
82 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
83 call void @use_pointer(ptr %x)
84 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
89 ; CHECK: define void @test1c(ptr %x)
90 ; CHECK: @llvm.objc.retain(ptr %x)
91 ; CHECK: @llvm.objc.retain(ptr %x)
92 ; CHECK: @llvm.objc.release(ptr %y)
93 ; CHECK: @llvm.objc.release(ptr %x)
96 define void @test1c(ptr %x) {
98 %A = alloca ptr, i32 3
99 %gep = getelementptr ptr, ptr %A, i32 2
100 tail call ptr @llvm.objc.retain(ptr %x)
101 tail call ptr @llvm.objc.retain(ptr %x)
102 store ptr %x, ptr %gep, align 8
103 %y = load ptr, ptr %gep
104 call void @use_alloca(ptr %A)
105 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
106 call void @use_pointer(ptr %x)
107 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
112 ; CHECK: define void @test1d(ptr %x, i1 %arg)
113 ; CHECK: @llvm.objc.retain(ptr %x)
114 ; CHECK: @llvm.objc.retain(ptr %x)
115 ; CHECK: @llvm.objc.release(ptr %y)
116 ; CHECK: @llvm.objc.release(ptr %x)
119 define void @test1d(ptr %x, i1 %arg) {
121 br i1 %arg, label %use_allocaA, label %use_allocaB
124 %allocaA = alloca ptr
128 %allocaB = alloca ptr
132 %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
133 tail call ptr @llvm.objc.retain(ptr %x)
134 tail call ptr @llvm.objc.retain(ptr %x)
135 store ptr %x, ptr %A, align 8
136 %y = load ptr, ptr %A
137 call void @use_alloca(ptr %A)
138 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
139 call void @use_pointer(ptr %x)
140 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
144 ; CHECK: define void @test1e(ptr %x, i1 %arg)
145 ; CHECK: @llvm.objc.retain(ptr %x)
146 ; CHECK: @llvm.objc.retain(ptr %x)
147 ; CHECK: @llvm.objc.release(ptr %y)
148 ; CHECK: @llvm.objc.release(ptr %x)
151 define void @test1e(ptr %x, i1 %arg) {
153 br i1 %arg, label %use_allocaA, label %use_allocaB
156 %allocaA = alloca ptr, i32 4
160 %allocaB = alloca ptr, i32 4
164 %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
165 %gep = getelementptr ptr, ptr %A, i32 2
166 tail call ptr @llvm.objc.retain(ptr %x)
167 tail call ptr @llvm.objc.retain(ptr %x)
168 store ptr %x, ptr %gep, align 8
169 %y = load ptr, ptr %gep
170 call void @use_alloca(ptr %A)
171 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
172 call void @use_pointer(ptr %x)
173 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
177 ; CHECK: define void @test1f(ptr %x)
178 ; CHECK: @llvm.objc.retain(ptr %x)
179 ; CHECK: @llvm.objc.retain(ptr %x)
180 ; CHECK: @llvm.objc.release(ptr %y)
181 ; CHECK: @llvm.objc.release(ptr %x)
184 define void @test1f(ptr %x) {
186 %allocaOne = alloca ptr
187 %allocaTwo = alloca ptr
188 %A = select i1 undef, ptr %allocaOne, ptr %allocaTwo
189 tail call ptr @llvm.objc.retain(ptr %x)
190 tail call ptr @llvm.objc.retain(ptr %x)
191 store ptr %x, ptr %A, align 8
192 %y = load ptr, ptr %A
193 call void @use_alloca(ptr %A)
194 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
195 call void @use_pointer(ptr %x)
196 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
200 ; Make sure that if a store is in a different basic block we handle known safe
204 ; CHECK: define void @test2a(ptr %x)
205 ; CHECK: @llvm.objc.retain(ptr %x)
206 ; CHECK: @llvm.objc.retain(ptr %x)
207 ; CHECK: @llvm.objc.release(ptr %y)
208 ; CHECK: @llvm.objc.release(ptr %x)
211 define void @test2a(ptr %x) {
214 store ptr %x, ptr %A, align 8
215 %y = load ptr, ptr %A
225 tail call ptr @llvm.objc.retain(ptr %x)
226 tail call ptr @llvm.objc.retain(ptr %x)
227 call void @use_alloca(ptr %A)
228 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
229 call void @use_pointer(ptr %x)
230 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
234 ; CHECK: define void @test2b(ptr %x)
235 ; CHECK: @llvm.objc.retain(ptr %x)
236 ; CHECK: @llvm.objc.retain(ptr %x)
237 ; CHECK: @llvm.objc.release(ptr %y)
238 ; CHECK: @llvm.objc.release(ptr %x)
241 define void @test2b(ptr %x) {
244 store ptr %x, ptr %A, align 8
245 %y = load ptr, ptr %A
255 tail call ptr @llvm.objc.retain(ptr %x)
256 tail call ptr @llvm.objc.retain(ptr %x)
257 call void @use_alloca(ptr %A)
258 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
259 call void @use_pointer(ptr %x)
260 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
264 ; CHECK: define void @test2c(ptr %x)
265 ; CHECK: @llvm.objc.retain(ptr %x)
266 ; CHECK: @llvm.objc.retain(ptr %x)
267 ; CHECK: @llvm.objc.release(ptr %y)
268 ; CHECK: @llvm.objc.release(ptr %x)
271 define void @test2c(ptr %x) {
273 %A = alloca ptr, i32 3
274 %gep1 = getelementptr ptr, ptr %A, i32 2
275 store ptr %x, ptr %gep1, align 8
276 %gep2 = getelementptr ptr, ptr %A, i32 2
277 %y = load ptr, ptr %gep2
278 tail call ptr @llvm.objc.retain(ptr %x)
288 tail call ptr @llvm.objc.retain(ptr %x)
289 call void @use_alloca(ptr %A)
290 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
291 call void @use_pointer(ptr %x)
292 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
296 ; CHECK: define void @test2d(ptr %x)
297 ; CHECK: @llvm.objc.retain(ptr %x)
298 ; CHECK: @llvm.objc.retain(ptr %x)
299 ; CHECK: @llvm.objc.release(ptr %y)
300 ; CHECK: @llvm.objc.release(ptr %x)
303 define void @test2d(ptr %x) {
305 tail call ptr @llvm.objc.retain(ptr %x)
309 %Abb1 = alloca ptr, i32 3
310 %gepbb11 = getelementptr ptr, ptr %Abb1, i32 2
311 store ptr %x, ptr %gepbb11, align 8
312 %gepbb12 = getelementptr ptr, ptr %Abb1, i32 2
313 %ybb1 = load ptr, ptr %gepbb12
317 %Abb2 = alloca ptr, i32 4
318 %gepbb21 = getelementptr ptr, ptr %Abb2, i32 2
319 store ptr %x, ptr %gepbb21, align 8
320 %gepbb22 = getelementptr ptr, ptr %Abb2, i32 2
321 %ybb2 = load ptr, ptr %gepbb22
325 %A = phi ptr [ %Abb1, %bb1 ], [ %Abb2, %bb2 ]
326 %y = phi ptr [ %ybb1, %bb1 ], [ %ybb2, %bb2 ]
327 tail call ptr @llvm.objc.retain(ptr %x)
328 call void @use_alloca(ptr %A)
329 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
330 call void @use_pointer(ptr %x)
331 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
335 ; Make sure in the presence of allocas, if we find a cfghazard we do not perform
336 ; code motion even if we are known safe. These two concepts are separate and
337 ; should be treated as such.
341 ; CHECK: define void @test3a() {
343 ; CHECK: @llvm.objc.retainAutoreleasedReturnValue
344 ; CHECK: @llvm.objc.retain
345 ; CHECK: @llvm.objc.retain
346 ; CHECK: @llvm.objc.retain
347 ; CHECK: @llvm.objc.retain
348 ; CHECK: arraydestroy.body:
349 ; CHECK: @llvm.objc.release
350 ; CHECK-NOT: @llvm.objc.release
351 ; CHECK: arraydestroy.done:
352 ; CHECK-NOT: @llvm.objc.release
353 ; CHECK: arraydestroy.body1:
354 ; CHECK: @llvm.objc.release
355 ; CHECK-NOT: @llvm.objc.release
356 ; CHECK: arraydestroy.done1:
357 ; CHECK: @llvm.objc.release
360 define void @test3a() {
362 %keys = alloca [2 x ptr], align 16
363 %objs = alloca [2 x ptr], align 16
365 %call1 = call ptr @returner()
366 %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
368 tail call ptr @llvm.objc.retain(ptr %call1)
369 store ptr %call1, ptr %objs, align 8
370 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1
371 tail call ptr @llvm.objc.retain(ptr %call1)
372 store ptr %call1, ptr %objs.elt
374 %call2 = call ptr @returner1()
375 %call3 = call ptr @returner2()
376 tail call ptr @llvm.objc.retain(ptr %call2)
377 store ptr %call2, ptr %keys, align 8
378 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
379 tail call ptr @llvm.objc.retain(ptr %call3)
380 store ptr %call3, ptr %keys.elt
382 %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
383 br label %arraydestroy.body
386 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
387 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1
388 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8
389 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0
390 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs
391 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
394 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2
395 br label %arraydestroy.body1
398 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
399 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1
400 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8
401 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0
402 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys
403 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
406 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
410 ; Make sure that even though we stop said code motion we still allow for
411 ; pointers to be removed if we are known safe in both directions.
415 ; CHECK: define void @test3b() {
417 ; CHECK: @llvm.objc.retainAutoreleasedReturnValue
418 ; CHECK: @llvm.objc.retain
419 ; CHECK: @llvm.objc.retain
420 ; CHECK: @llvm.objc.retain
421 ; CHECK: @llvm.objc.retain
422 ; CHECK: arraydestroy.body:
423 ; CHECK: @llvm.objc.release
424 ; CHECK-NOT: @llvm.objc.release
425 ; CHECK: arraydestroy.done:
426 ; CHECK-NOT: @llvm.objc.release
427 ; CHECK: arraydestroy.body1:
428 ; CHECK: @llvm.objc.release
429 ; CHECK-NOT: @llvm.objc.release
430 ; CHECK: arraydestroy.done1:
431 ; CHECK: @llvm.objc.release
434 define void @test3b() {
436 %keys = alloca [2 x ptr], align 16
437 %objs = alloca [2 x ptr], align 16
439 %call1 = call ptr @returner()
440 %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
441 %tmp1 = tail call ptr @llvm.objc.retain(ptr %call1)
443 tail call ptr @llvm.objc.retain(ptr %call1)
444 store ptr %call1, ptr %objs, align 8
445 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1
446 tail call ptr @llvm.objc.retain(ptr %call1)
447 store ptr %call1, ptr %objs.elt
449 %call2 = call ptr @returner1()
450 %call3 = call ptr @returner2()
451 tail call ptr @llvm.objc.retain(ptr %call2)
452 store ptr %call2, ptr %keys, align 8
453 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
454 tail call ptr @llvm.objc.retain(ptr %call3)
455 store ptr %call3, ptr %keys.elt
457 %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
458 br label %arraydestroy.body
461 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
462 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1
463 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8
464 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0
465 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs
466 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
469 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2
470 br label %arraydestroy.body1
473 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
474 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1
475 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8
476 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0
477 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys
478 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
481 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
482 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
488 declare i32 @__gxx_personality_v0(...)