1 ; RUN: opt -S -passes=objc-arc < %s | FileCheck %s
3 declare ptr @llvm.objc.retain(ptr)
4 declare void @llvm.objc.release(ptr)
5 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
6 declare ptr @objc_msgSend(ptr, ptr, ...)
7 declare void @use_pointer(ptr)
9 declare ptr @returner()
11 ; ARCOpt shouldn't try to move the releases to the block containing the invoke.
13 ; CHECK-LABEL: define void @test0(
15 ; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
18 ; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
21 define void @test0(ptr %zipFile) personality ptr @__gxx_personality_v0 {
23 call ptr @llvm.objc.retain(ptr %zipFile) nounwind
24 call void @use_pointer(ptr %zipFile)
25 invoke void @objc_msgSend(ptr %zipFile)
26 to label %invoke.cont unwind label %lpad
28 invoke.cont: ; preds = %entry
29 call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
32 lpad: ; preds = %entry
33 %exn = landingpad {ptr, i32}
35 call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
39 ; ARCOpt should move the release before the callee calls.
41 ; CHECK-LABEL: define void @test1(
43 ; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
44 ; CHECK: call void @callee()
45 ; CHECK: br label %done
47 ; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
48 ; CHECK: call void @callee()
49 ; CHECK: br label %done
51 ; CHECK-NEXT: ret void
53 define void @test1(ptr %zipFile) personality ptr @__gxx_personality_v0 {
55 call ptr @llvm.objc.retain(ptr %zipFile) nounwind
56 call void @use_pointer(ptr %zipFile)
57 invoke void @objc_msgSend(ptr %zipFile)
58 to label %invoke.cont unwind label %lpad
60 invoke.cont: ; preds = %entry
64 lpad: ; preds = %entry
65 %exn = landingpad {ptr, i32}
71 call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
75 ; The optimizer should ignore invoke unwind paths consistently.
78 ; CHECK: define void @test2() personality ptr @__objc_personality_v0 {
80 ; CHECK-NEXT: call ptr @llvm.objc.retain
81 ; CHECK-NOT: @llvm.objc.r
82 ; CHECK: finally.cont:
83 ; CHECK-NEXT: call void @llvm.objc.release
85 ; CHECK: finally.rethrow:
88 define void @test2() personality ptr @__objc_personality_v0 {
90 %call = invoke ptr @objc_msgSend()
91 to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
93 invoke.cont: ; preds = %entry
94 %tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
95 call void @objc_msgSend(), !clang.arc.no_objc_arc_exceptions !0
96 invoke void @use_pointer(ptr %call)
97 to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
99 finally.cont: ; preds = %invoke.cont
100 tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0
103 finally.rethrow: ; preds = %invoke.cont, %entry
104 %tmp2 = landingpad { ptr, i32 }
109 ; Don't try to place code on invoke critical edges.
111 ; CHECK-LABEL: define void @test3(
113 ; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
114 ; CHECK-NEXT: ret void
116 define void @test3(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
118 %0 = call ptr @llvm.objc.retain(ptr %p)
120 br i1 %b, label %if.else, label %if.then
123 invoke void @use_pointer(ptr %p)
124 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
127 invoke void @use_pointer(ptr %p)
128 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
131 %r = landingpad { ptr, i32 }
136 call void @llvm.objc.release(ptr %p)
140 ; Like test3, but with ARC-relevant exception handling.
142 ; CHECK-LABEL: define void @test4(
144 ; CHECK-NEXT: %r = landingpad { ptr, i32 }
145 ; CHECK-NEXT: cleanup
146 ; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
147 ; CHECK-NEXT: ret void
149 ; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
150 ; CHECK-NEXT: ret void
152 define void @test4(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
154 %0 = call ptr @llvm.objc.retain(ptr %p)
156 br i1 %b, label %if.else, label %if.then
159 invoke void @use_pointer(ptr %p)
160 to label %if.end unwind label %lpad
163 invoke void @use_pointer(ptr %p)
164 to label %if.end unwind label %lpad
167 %r = landingpad { ptr, i32 }
169 call void @llvm.objc.release(ptr %p)
173 call void @llvm.objc.release(ptr %p)
177 ; Don't turn the retainAutoreleaseReturnValue into retain, because it's
178 ; for an invoke which we can assume codegen will put immediately prior.
180 ; CHECK-LABEL: define void @test5(
181 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
183 define void @test5() personality ptr @__objc_personality_v0 {
185 %z = invoke ptr @returner()
186 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
189 %r13 = landingpad { ptr, i32 }
194 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
198 ; Like test5, but there's intervening code.
200 ; CHECK-LABEL: define void @test6(
201 ; CHECK: call ptr @llvm.objc.retain(ptr %z)
203 define void @test6() personality ptr @__objc_personality_v0 {
205 %z = invoke ptr @returner()
206 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
209 %r13 = landingpad { ptr, i32 }
215 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
219 declare i32 @__gxx_personality_v0(...)
220 declare i32 @__objc_personality_v0(...)
222 ; CHECK: attributes [[NUW]] = { nounwind }