1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
3 declare i8* @llvm.objc.retain(i8*)
4 declare void @llvm.objc.release(i8*)
5 declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
6 declare i8* @llvm.objc.msgSend(i8*, i8*, ...)
7 declare void @use_pointer(i8*)
9 declare i8* @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(i8* %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
18 ; CHECK: call void @llvm.objc.release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
21 define void @test0(i8* %zipFile) personality i32 (...)* @__gxx_personality_v0 {
23 call i8* @llvm.objc.retain(i8* %zipFile) nounwind
24 call void @use_pointer(i8* %zipFile)
25 invoke void bitcast (i8* (i8*, i8*, ...)* @llvm.objc.msgSend to void (i8*)*)(i8* %zipFile)
26 to label %invoke.cont unwind label %lpad
28 invoke.cont: ; preds = %entry
29 call void @llvm.objc.release(i8* %zipFile) nounwind, !clang.imprecise_release !0
32 lpad: ; preds = %entry
33 %exn = landingpad {i8*, i32}
35 call void @llvm.objc.release(i8* %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(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
44 ; CHECK: call void @callee()
45 ; CHECK: br label %done
47 ; CHECK: call void @llvm.objc.release(i8* %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(i8* %zipFile) personality i32 (...)* @__gxx_personality_v0 {
55 call i8* @llvm.objc.retain(i8* %zipFile) nounwind
56 call void @use_pointer(i8* %zipFile)
57 invoke void bitcast (i8* (i8*, i8*, ...)* @llvm.objc.msgSend to void (i8*)*)(i8* %zipFile)
58 to label %invoke.cont unwind label %lpad
60 invoke.cont: ; preds = %entry
64 lpad: ; preds = %entry
65 %exn = landingpad {i8*, i32}
71 call void @llvm.objc.release(i8* %zipFile) nounwind, !clang.imprecise_release !0
75 ; The optimizer should ignore invoke unwind paths consistently.
78 ; CHECK: define void @test2() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
80 ; CHECK-NEXT: call i8* @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 i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
90 %call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @llvm.objc.msgSend to i8* ()*)()
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 i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
95 call void bitcast (i8* (i8*, i8*, ...)* @llvm.objc.msgSend to void ()*)(), !clang.arc.no_objc_arc_exceptions !0
96 invoke void @use_pointer(i8* %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(i8* %call) nounwind, !clang.imprecise_release !0
103 finally.rethrow: ; preds = %invoke.cont, %entry
104 %tmp2 = landingpad { i8*, 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(i8* %p) [[NUW]]
114 ; CHECK-NEXT: ret void
116 define void @test3(i8* %p, i1 %b) personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
118 %0 = call i8* @llvm.objc.retain(i8* %p)
120 br i1 %b, label %if.else, label %if.then
123 invoke void @use_pointer(i8* %p)
124 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
127 invoke void @use_pointer(i8* %p)
128 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
131 %r = landingpad { i8*, i32 }
136 call void @llvm.objc.release(i8* %p)
140 ; Like test3, but with ARC-relevant exception handling.
142 ; CHECK-LABEL: define void @test4(
144 ; CHECK-NEXT: %r = landingpad { i8*, i32 }
145 ; CHECK-NEXT: cleanup
146 ; CHECK-NEXT: call void @llvm.objc.release(i8* %p) [[NUW]]
147 ; CHECK-NEXT: ret void
149 ; CHECK-NEXT: call void @llvm.objc.release(i8* %p) [[NUW]]
150 ; CHECK-NEXT: ret void
152 define void @test4(i8* %p, i1 %b) personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
154 %0 = call i8* @llvm.objc.retain(i8* %p)
156 br i1 %b, label %if.else, label %if.then
159 invoke void @use_pointer(i8* %p)
160 to label %if.end unwind label %lpad
163 invoke void @use_pointer(i8* %p)
164 to label %if.end unwind label %lpad
167 %r = landingpad { i8*, i32 }
169 call void @llvm.objc.release(i8* %p)
173 call void @llvm.objc.release(i8* %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 i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
183 define void @test5() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
185 %z = invoke i8* @returner()
186 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
189 %r13 = landingpad { i8*, i32 }
194 call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
198 ; Like test5, but there's intervening code.
200 ; CHECK-LABEL: define void @test6(
201 ; CHECK: call i8* @llvm.objc.retain(i8* %z)
203 define void @test6() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
205 %z = invoke i8* @returner()
206 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
209 %r13 = landingpad { i8*, i32 }
215 call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
219 declare i32 @__gxx_personality_v0(...)
220 declare i32 @__objc_personality_v0(...)
222 ; CHECK: attributes [[NUW]] = { nounwind }