1 ; RUN: opt -objc-arc -S < %s | FileCheck %s
3 declare i8* @llvm.objc.retain(i8*)
4 declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
5 declare void @llvm.objc.release(i8*)
6 declare i8* @llvm.objc.autorelease(i8*)
7 declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
8 declare void @llvm.objc.autoreleasePoolPop(i8*)
9 declare i8* @llvm.objc.autoreleasePoolPush()
10 declare i8* @llvm.objc.retainBlock(i8*)
12 declare i8* @objc_retainedObject(i8*)
13 declare i8* @objc_unretainedObject(i8*)
14 declare i8* @objc_unretainedPointer(i8*)
16 declare void @use_pointer(i8*)
17 declare void @callee()
18 declare void @callee_fnptr(void ()*)
19 declare void @invokee()
20 declare i8* @returner()
21 declare i8* @returner1()
22 declare i8* @returner2()
23 declare void @bar(i32 ()*)
24 declare void @use_alloca(i8**)
26 declare void @llvm.dbg.value(metadata, metadata, metadata)
28 declare i8* @llvm.objc.msgSend(i8*, i8*, ...)
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(i8* %x)
47 ; CHECK: @llvm.objc.retain(i8* %x)
48 ; CHECK: @llvm.objc.retain(i8* %x)
49 ; CHECK: @llvm.objc.release(i8* %y)
50 ; CHECK: @llvm.objc.release(i8* %x)
53 define void @test1a(i8* %x) {
56 tail call i8* @llvm.objc.retain(i8* %x)
57 tail call i8* @llvm.objc.retain(i8* %x)
58 store i8* %x, i8** %A, align 8
59 %y = load i8*, i8** %A
60 call void @use_alloca(i8** %A)
61 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
62 call void @use_pointer(i8* %x)
63 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
67 ; CHECK: define void @test1b(i8* %x)
68 ; CHECK: @llvm.objc.retain(i8* %x)
69 ; CHECK: @llvm.objc.retain(i8* %x)
70 ; CHECK: @llvm.objc.release(i8* %y)
71 ; CHECK: @llvm.objc.release(i8* %x)
74 define void @test1b(i8* %x) {
77 %gep = getelementptr i8*, i8** %A, i32 0
78 tail call i8* @llvm.objc.retain(i8* %x)
79 tail call i8* @llvm.objc.retain(i8* %x)
80 store i8* %x, i8** %gep, align 8
81 %y = load i8*, i8** %A
82 call void @use_alloca(i8** %A)
83 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
84 call void @use_pointer(i8* %x)
85 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
90 ; CHECK: define void @test1c(i8* %x)
91 ; CHECK: @llvm.objc.retain(i8* %x)
92 ; CHECK: @llvm.objc.retain(i8* %x)
93 ; CHECK: @llvm.objc.release(i8* %y)
94 ; CHECK: @llvm.objc.release(i8* %x)
97 define void @test1c(i8* %x) {
99 %A = alloca i8*, i32 3
100 %gep = getelementptr i8*, i8** %A, i32 2
101 tail call i8* @llvm.objc.retain(i8* %x)
102 tail call i8* @llvm.objc.retain(i8* %x)
103 store i8* %x, i8** %gep, align 8
104 %y = load i8*, i8** %gep
105 call void @use_alloca(i8** %A)
106 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
107 call void @use_pointer(i8* %x)
108 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
113 ; CHECK: define void @test1d(i8* %x)
114 ; CHECK: @llvm.objc.retain(i8* %x)
115 ; CHECK: @llvm.objc.retain(i8* %x)
116 ; CHECK: @llvm.objc.release(i8* %y)
117 ; CHECK: @llvm.objc.release(i8* %x)
120 define void @test1d(i8* %x) {
122 br i1 undef, label %use_allocaA, label %use_allocaB
125 %allocaA = alloca i8*
129 %allocaB = alloca i8*
133 %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
134 %gep = getelementptr i8*, i8** %A, i32 0
135 tail call i8* @llvm.objc.retain(i8* %x)
136 tail call i8* @llvm.objc.retain(i8* %x)
137 store i8* %x, i8** %gep, align 8
138 %y = load i8*, i8** %gep
139 call void @use_alloca(i8** %A)
140 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
141 call void @use_pointer(i8* %x)
142 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
146 ; CHECK: define void @test1e(i8* %x)
147 ; CHECK: @llvm.objc.retain(i8* %x)
148 ; CHECK: @llvm.objc.retain(i8* %x)
149 ; CHECK: @llvm.objc.release(i8* %y)
150 ; CHECK: @llvm.objc.release(i8* %x)
153 define void @test1e(i8* %x) {
155 br i1 undef, label %use_allocaA, label %use_allocaB
158 %allocaA = alloca i8*, i32 4
162 %allocaB = alloca i8*, i32 4
166 %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
167 %gep = getelementptr i8*, i8** %A, i32 2
168 tail call i8* @llvm.objc.retain(i8* %x)
169 tail call i8* @llvm.objc.retain(i8* %x)
170 store i8* %x, i8** %gep, align 8
171 %y = load i8*, i8** %gep
172 call void @use_alloca(i8** %A)
173 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
174 call void @use_pointer(i8* %x)
175 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
179 ; CHECK: define void @test1f(i8* %x)
180 ; CHECK: @llvm.objc.retain(i8* %x)
181 ; CHECK: @llvm.objc.retain(i8* %x)
182 ; CHECK: @llvm.objc.release(i8* %y)
183 ; CHECK: @llvm.objc.release(i8* %x)
186 define void @test1f(i8* %x) {
188 %allocaOne = alloca i8*
189 %allocaTwo = alloca i8*
190 %A = select i1 undef, i8** %allocaOne, i8** %allocaTwo
191 tail call i8* @llvm.objc.retain(i8* %x)
192 tail call i8* @llvm.objc.retain(i8* %x)
193 store i8* %x, i8** %A, align 8
194 %y = load i8*, i8** %A
195 call void @use_alloca(i8** %A)
196 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
197 call void @use_pointer(i8* %x)
198 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
202 ; Make sure that if a store is in a different basic block we handle known safe
206 ; CHECK: define void @test2a(i8* %x)
207 ; CHECK: @llvm.objc.retain(i8* %x)
208 ; CHECK: @llvm.objc.retain(i8* %x)
209 ; CHECK: @llvm.objc.release(i8* %y)
210 ; CHECK: @llvm.objc.release(i8* %x)
213 define void @test2a(i8* %x) {
216 store i8* %x, i8** %A, align 8
217 %y = load i8*, i8** %A
227 tail call i8* @llvm.objc.retain(i8* %x)
228 tail call i8* @llvm.objc.retain(i8* %x)
229 call void @use_alloca(i8** %A)
230 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
231 call void @use_pointer(i8* %x)
232 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
236 ; CHECK: define void @test2b(i8* %x)
237 ; CHECK: @llvm.objc.retain(i8* %x)
238 ; CHECK: @llvm.objc.retain(i8* %x)
239 ; CHECK: @llvm.objc.release(i8* %y)
240 ; CHECK: @llvm.objc.release(i8* %x)
243 define void @test2b(i8* %x) {
246 %gep1 = getelementptr i8*, i8** %A, i32 0
247 store i8* %x, i8** %gep1, align 8
248 %gep2 = getelementptr i8*, i8** %A, i32 0
249 %y = load i8*, i8** %gep2
259 tail call i8* @llvm.objc.retain(i8* %x)
260 tail call i8* @llvm.objc.retain(i8* %x)
261 call void @use_alloca(i8** %A)
262 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
263 call void @use_pointer(i8* %x)
264 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
268 ; CHECK: define void @test2c(i8* %x)
269 ; CHECK: @llvm.objc.retain(i8* %x)
270 ; CHECK: @llvm.objc.retain(i8* %x)
271 ; CHECK: @llvm.objc.release(i8* %y)
272 ; CHECK: @llvm.objc.release(i8* %x)
275 define void @test2c(i8* %x) {
277 %A = alloca i8*, i32 3
278 %gep1 = getelementptr i8*, i8** %A, i32 2
279 store i8* %x, i8** %gep1, align 8
280 %gep2 = getelementptr i8*, i8** %A, i32 2
281 %y = load i8*, i8** %gep2
282 tail call i8* @llvm.objc.retain(i8* %x)
292 tail call i8* @llvm.objc.retain(i8* %x)
293 call void @use_alloca(i8** %A)
294 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
295 call void @use_pointer(i8* %x)
296 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
300 ; CHECK: define void @test2d(i8* %x)
301 ; CHECK: @llvm.objc.retain(i8* %x)
302 ; CHECK: @llvm.objc.retain(i8* %x)
303 ; CHECK: @llvm.objc.release(i8* %y)
304 ; CHECK: @llvm.objc.release(i8* %x)
307 define void @test2d(i8* %x) {
309 tail call i8* @llvm.objc.retain(i8* %x)
313 %Abb1 = alloca i8*, i32 3
314 %gepbb11 = getelementptr i8*, i8** %Abb1, i32 2
315 store i8* %x, i8** %gepbb11, align 8
316 %gepbb12 = getelementptr i8*, i8** %Abb1, i32 2
317 %ybb1 = load i8*, i8** %gepbb12
321 %Abb2 = alloca i8*, i32 4
322 %gepbb21 = getelementptr i8*, i8** %Abb2, i32 2
323 store i8* %x, i8** %gepbb21, align 8
324 %gepbb22 = getelementptr i8*, i8** %Abb2, i32 2
325 %ybb2 = load i8*, i8** %gepbb22
329 %A = phi i8** [ %Abb1, %bb1 ], [ %Abb2, %bb2 ]
330 %y = phi i8* [ %ybb1, %bb1 ], [ %ybb2, %bb2 ]
331 tail call i8* @llvm.objc.retain(i8* %x)
332 call void @use_alloca(i8** %A)
333 call void @llvm.objc.release(i8* %y), !clang.imprecise_release !0
334 call void @use_pointer(i8* %x)
335 call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
339 ; Make sure in the presence of allocas, if we find a cfghazard we do not perform
340 ; code motion even if we are known safe. These two concepts are separate and
341 ; should be treated as such.
345 ; CHECK: define void @test3a() {
347 ; CHECK: @llvm.objc.retainAutoreleasedReturnValue
348 ; CHECK: @llvm.objc.retain
349 ; CHECK: @llvm.objc.retain
350 ; CHECK: @llvm.objc.retain
351 ; CHECK: @llvm.objc.retain
352 ; CHECK: arraydestroy.body:
353 ; CHECK: @llvm.objc.release
354 ; CHECK-NOT: @llvm.objc.release
355 ; CHECK: arraydestroy.done:
356 ; CHECK-NOT: @llvm.objc.release
357 ; CHECK: arraydestroy.body1:
358 ; CHECK: @llvm.objc.release
359 ; CHECK-NOT: @llvm.objc.release
360 ; CHECK: arraydestroy.done1:
361 ; CHECK: @llvm.objc.release
364 define void @test3a() {
366 %keys = alloca [2 x i8*], align 16
367 %objs = alloca [2 x i8*], align 16
369 %call1 = call i8* @returner()
370 %tmp0 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call1)
372 %objs.begin = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 0
373 tail call i8* @llvm.objc.retain(i8* %call1)
374 store i8* %call1, i8** %objs.begin, align 8
375 %objs.elt = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 1
376 tail call i8* @llvm.objc.retain(i8* %call1)
377 store i8* %call1, i8** %objs.elt
379 %call2 = call i8* @returner1()
380 %call3 = call i8* @returner2()
381 %keys.begin = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 0
382 tail call i8* @llvm.objc.retain(i8* %call2)
383 store i8* %call2, i8** %keys.begin, align 8
384 %keys.elt = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 1
385 tail call i8* @llvm.objc.retain(i8* %call3)
386 store i8* %call3, i8** %keys.elt
388 %gep = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 2
389 br label %arraydestroy.body
392 %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
393 %arraydestroy.element = getelementptr inbounds i8*, i8** %arraydestroy.elementPast, i64 -1
394 %destroy_tmp = load i8*, i8** %arraydestroy.element, align 8
395 call void @llvm.objc.release(i8* %destroy_tmp), !clang.imprecise_release !0
396 %objs_ptr = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 0
397 %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr
398 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
401 %gep1 = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 2
402 br label %arraydestroy.body1
405 %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
406 %arraydestroy.element1 = getelementptr inbounds i8*, i8** %arraydestroy.elementPast1, i64 -1
407 %destroy_tmp1 = load i8*, i8** %arraydestroy.element1, align 8
408 call void @llvm.objc.release(i8* %destroy_tmp1), !clang.imprecise_release !0
409 %keys_ptr = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 0
410 %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr
411 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
414 call void @llvm.objc.release(i8* %call1), !clang.imprecise_release !0
418 ; Make sure that even though we stop said code motion we still allow for
419 ; pointers to be removed if we are known safe in both directions.
423 ; CHECK: define void @test3b() {
425 ; CHECK: @llvm.objc.retainAutoreleasedReturnValue
426 ; CHECK: @llvm.objc.retain
427 ; CHECK: @llvm.objc.retain
428 ; CHECK: @llvm.objc.retain
429 ; CHECK: @llvm.objc.retain
430 ; CHECK: arraydestroy.body:
431 ; CHECK: @llvm.objc.release
432 ; CHECK-NOT: @llvm.objc.release
433 ; CHECK: arraydestroy.done:
434 ; CHECK-NOT: @llvm.objc.release
435 ; CHECK: arraydestroy.body1:
436 ; CHECK: @llvm.objc.release
437 ; CHECK-NOT: @llvm.objc.release
438 ; CHECK: arraydestroy.done1:
439 ; CHECK: @llvm.objc.release
442 define void @test3b() {
444 %keys = alloca [2 x i8*], align 16
445 %objs = alloca [2 x i8*], align 16
447 %call1 = call i8* @returner()
448 %tmp0 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call1)
449 %tmp1 = tail call i8* @llvm.objc.retain(i8* %call1)
451 %objs.begin = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 0
452 tail call i8* @llvm.objc.retain(i8* %call1)
453 store i8* %call1, i8** %objs.begin, align 8
454 %objs.elt = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 1
455 tail call i8* @llvm.objc.retain(i8* %call1)
456 store i8* %call1, i8** %objs.elt
458 %call2 = call i8* @returner1()
459 %call3 = call i8* @returner2()
460 %keys.begin = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 0
461 tail call i8* @llvm.objc.retain(i8* %call2)
462 store i8* %call2, i8** %keys.begin, align 8
463 %keys.elt = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 1
464 tail call i8* @llvm.objc.retain(i8* %call3)
465 store i8* %call3, i8** %keys.elt
467 %gep = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 2
468 br label %arraydestroy.body
471 %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
472 %arraydestroy.element = getelementptr inbounds i8*, i8** %arraydestroy.elementPast, i64 -1
473 %destroy_tmp = load i8*, i8** %arraydestroy.element, align 8
474 call void @llvm.objc.release(i8* %destroy_tmp), !clang.imprecise_release !0
475 %objs_ptr = getelementptr inbounds [2 x i8*], [2 x i8*]* %objs, i64 0, i64 0
476 %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr
477 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
480 %gep1 = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 2
481 br label %arraydestroy.body1
484 %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
485 %arraydestroy.element1 = getelementptr inbounds i8*, i8** %arraydestroy.elementPast1, i64 -1
486 %destroy_tmp1 = load i8*, i8** %arraydestroy.element1, align 8
487 call void @llvm.objc.release(i8* %destroy_tmp1), !clang.imprecise_release !0
488 %keys_ptr = getelementptr inbounds [2 x i8*], [2 x i8*]* %keys, i64 0, i64 0
489 %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr
490 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
493 call void @llvm.objc.release(i8* %call1), !clang.imprecise_release !0
494 call void @llvm.objc.release(i8* %call1), !clang.imprecise_release !0
500 declare i32 @__gxx_personality_v0(...)