1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
3 declare i8* @objc_retain(i8*)
4 declare void @objc_release(i8*)
5 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
6 declare i8* @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: define void @test0(
15 ; CHECK: call void @objc_release(i8* %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
18 ; CHECK: call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
20 define void @test0(i8* %zipFile) {
22 call i8* @objc_retain(i8* %zipFile) nounwind
23 call void @use_pointer(i8* %zipFile)
24 invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
25 to label %invoke.cont unwind label %lpad
27 invoke.cont: ; preds = %entry
28 call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
31 lpad: ; preds = %entry
32 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
34 call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
38 ; ARCOpt should move the release before the callee calls.
40 ; CHECK: define void @test1(
42 ; CHECK: call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
43 ; CHECK: call void @callee()
44 ; CHECK: br label %done
46 ; CHECK: call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
47 ; CHECK: call void @callee()
48 ; CHECK: br label %done
50 ; CHECK-NEXT: ret void
51 define void @test1(i8* %zipFile) {
53 call i8* @objc_retain(i8* %zipFile) nounwind
54 call void @use_pointer(i8* %zipFile)
55 invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
56 to label %invoke.cont unwind label %lpad
58 invoke.cont: ; preds = %entry
62 lpad: ; preds = %entry
63 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
69 call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
73 ; The optimizer should ignore invoke unwind paths consistently.
76 ; CHECK: define void @test2() {
78 ; CHECK-NEXT: call i8* @objc_retain
80 ; CHECK: finally.cont:
81 ; CHECK-NEXT: call void @objc_release
83 ; CHECK: finally.rethrow:
86 define void @test2() {
88 %call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* ()*)()
89 to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
91 invoke.cont: ; preds = %entry
92 %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
93 call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ()*)(), !clang.arc.no_objc_arc_exceptions !0
94 invoke void @use_pointer(i8* %call)
95 to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
97 finally.cont: ; preds = %invoke.cont
98 tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0
101 finally.rethrow: ; preds = %invoke.cont, %entry
102 %tmp2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
107 ; Don't try to place code on invoke critical edges.
109 ; CHECK: define void @test3(
111 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
112 ; CHECK-NEXT: ret void
113 define void @test3(i8* %p, i1 %b) {
115 %0 = call i8* @objc_retain(i8* %p)
117 br i1 %b, label %if.else, label %if.then
120 invoke void @use_pointer(i8* %p)
121 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
124 invoke void @use_pointer(i8* %p)
125 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
128 %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
133 call void @objc_release(i8* %p)
137 ; Like test3, but with ARC-relevant exception handling.
139 ; CHECK: define void @test4(
141 ; CHECK-NEXT: %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
142 ; CHECK-NEXT: cleanup
143 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
144 ; CHECK-NEXT: ret void
146 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
147 ; CHECK-NEXT: ret void
148 define void @test4(i8* %p, i1 %b) {
150 %0 = call i8* @objc_retain(i8* %p)
152 br i1 %b, label %if.else, label %if.then
155 invoke void @use_pointer(i8* %p)
156 to label %if.end unwind label %lpad
159 invoke void @use_pointer(i8* %p)
160 to label %if.end unwind label %lpad
163 %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
165 call void @objc_release(i8* %p)
169 call void @objc_release(i8* %p)
173 ; Don't turn the retainAutoreleaseReturnValue into retain, because it's
174 ; for an invoke which we can assume codegen will put immediately prior.
176 ; CHECK: define void @test5(
177 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
179 define void @test5() {
181 %z = invoke i8* @returner()
182 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
185 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
190 call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
194 ; Like test5, but there's intervening code.
196 ; CHECK: define void @test6(
197 ; CHECK: call i8* @objc_retain(i8* %z)
199 define void @test6() {
201 %z = invoke i8* @returner()
202 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
205 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
211 call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
215 declare i32 @__gxx_personality_v0(...)
216 declare i32 @__objc_personality_v0(...)
218 ; CHECK: attributes [[NUW]] = { nounwind }