1f4a2713aSLionel Sambuc; RUN: opt -S -objc-arc < %s | FileCheck %s
2f4a2713aSLionel Sambuc
3f4a2713aSLionel Sambucdeclare i8* @objc_retain(i8*)
4f4a2713aSLionel Sambucdeclare void @objc_release(i8*)
5f4a2713aSLionel Sambucdeclare i8* @objc_retainAutoreleasedReturnValue(i8*)
6f4a2713aSLionel Sambucdeclare i8* @objc_msgSend(i8*, i8*, ...)
7f4a2713aSLionel Sambucdeclare void @use_pointer(i8*)
8f4a2713aSLionel Sambucdeclare void @callee()
9f4a2713aSLionel Sambucdeclare i8* @returner()
10f4a2713aSLionel Sambuc
11f4a2713aSLionel Sambuc; ARCOpt shouldn't try to move the releases to the block containing the invoke.
12f4a2713aSLionel Sambuc
13f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test0(
14f4a2713aSLionel Sambuc; CHECK: invoke.cont:
15f4a2713aSLionel Sambuc; CHECK:   call void @objc_release(i8* %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
16f4a2713aSLionel Sambuc; CHECK:   ret void
17f4a2713aSLionel Sambuc; CHECK: lpad:
18f4a2713aSLionel Sambuc; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
19f4a2713aSLionel Sambuc; CHECK:   ret void
20f4a2713aSLionel Sambuc; CHECK-NEXT: }
21f4a2713aSLionel Sambucdefine void @test0(i8* %zipFile) {
22f4a2713aSLionel Sambucentry:
23f4a2713aSLionel Sambuc  call i8* @objc_retain(i8* %zipFile) nounwind
24f4a2713aSLionel Sambuc  call void @use_pointer(i8* %zipFile)
25f4a2713aSLionel Sambuc  invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
26f4a2713aSLionel Sambuc          to label %invoke.cont unwind label %lpad
27f4a2713aSLionel Sambuc
28f4a2713aSLionel Sambucinvoke.cont:                                      ; preds = %entry
29f4a2713aSLionel Sambuc  call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
30f4a2713aSLionel Sambuc  ret void
31f4a2713aSLionel Sambuc
32f4a2713aSLionel Sambuclpad:                                             ; preds = %entry
33f4a2713aSLionel Sambuc  %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
34f4a2713aSLionel Sambuc           cleanup
35f4a2713aSLionel Sambuc  call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
36f4a2713aSLionel Sambuc  ret void
37f4a2713aSLionel Sambuc}
38f4a2713aSLionel Sambuc
39f4a2713aSLionel Sambuc; ARCOpt should move the release before the callee calls.
40f4a2713aSLionel Sambuc
41f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test1(
42f4a2713aSLionel Sambuc; CHECK: invoke.cont:
43f4a2713aSLionel Sambuc; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
44f4a2713aSLionel Sambuc; CHECK:   call void @callee()
45f4a2713aSLionel Sambuc; CHECK:   br label %done
46f4a2713aSLionel Sambuc; CHECK: lpad:
47f4a2713aSLionel Sambuc; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
48f4a2713aSLionel Sambuc; CHECK:   call void @callee()
49f4a2713aSLionel Sambuc; CHECK:   br label %done
50f4a2713aSLionel Sambuc; CHECK: done:
51f4a2713aSLionel Sambuc; CHECK-NEXT: ret void
52f4a2713aSLionel Sambuc; CHECK-NEXT: }
53f4a2713aSLionel Sambucdefine void @test1(i8* %zipFile) {
54f4a2713aSLionel Sambucentry:
55f4a2713aSLionel Sambuc  call i8* @objc_retain(i8* %zipFile) nounwind
56f4a2713aSLionel Sambuc  call void @use_pointer(i8* %zipFile)
57f4a2713aSLionel Sambuc  invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
58f4a2713aSLionel Sambuc          to label %invoke.cont unwind label %lpad
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambucinvoke.cont:                                      ; preds = %entry
61f4a2713aSLionel Sambuc  call void @callee()
62f4a2713aSLionel Sambuc  br label %done
63f4a2713aSLionel Sambuc
64f4a2713aSLionel Sambuclpad:                                             ; preds = %entry
65f4a2713aSLionel Sambuc  %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
66f4a2713aSLionel Sambuc           cleanup
67f4a2713aSLionel Sambuc  call void @callee()
68f4a2713aSLionel Sambuc  br label %done
69f4a2713aSLionel Sambuc
70f4a2713aSLionel Sambucdone:
71f4a2713aSLionel Sambuc  call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
72f4a2713aSLionel Sambuc  ret void
73f4a2713aSLionel Sambuc}
74f4a2713aSLionel Sambuc
75f4a2713aSLionel Sambuc; The optimizer should ignore invoke unwind paths consistently.
76f4a2713aSLionel Sambuc; PR12265
77f4a2713aSLionel Sambuc
78f4a2713aSLionel Sambuc; CHECK: define void @test2() {
79f4a2713aSLionel Sambuc; CHECK: invoke.cont:
80f4a2713aSLionel Sambuc; CHECK-NEXT: call i8* @objc_retain
81f4a2713aSLionel Sambuc; CHECK-NOT: @objc_r
82f4a2713aSLionel Sambuc; CHECK: finally.cont:
83f4a2713aSLionel Sambuc; CHECK-NEXT: call void @objc_release
84f4a2713aSLionel Sambuc; CHECK-NOT: @objc
85f4a2713aSLionel Sambuc; CHECK: finally.rethrow:
86f4a2713aSLionel Sambuc; CHECK-NOT: @objc
87f4a2713aSLionel Sambuc; CHECK: }
88f4a2713aSLionel Sambucdefine void @test2() {
89f4a2713aSLionel Sambucentry:
90f4a2713aSLionel Sambuc  %call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* ()*)()
91f4a2713aSLionel Sambuc          to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
92f4a2713aSLionel Sambuc
93f4a2713aSLionel Sambucinvoke.cont:                                      ; preds = %entry
94f4a2713aSLionel Sambuc  %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
95f4a2713aSLionel Sambuc  call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ()*)(), !clang.arc.no_objc_arc_exceptions !0
96f4a2713aSLionel Sambuc  invoke void @use_pointer(i8* %call)
97f4a2713aSLionel Sambuc          to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
98f4a2713aSLionel Sambuc
99f4a2713aSLionel Sambucfinally.cont:                                     ; preds = %invoke.cont
100f4a2713aSLionel Sambuc  tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0
101f4a2713aSLionel Sambuc  ret void
102f4a2713aSLionel Sambuc
103f4a2713aSLionel Sambucfinally.rethrow:                                  ; preds = %invoke.cont, %entry
104f4a2713aSLionel Sambuc  %tmp2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
105f4a2713aSLionel Sambuc          catch i8* null
106f4a2713aSLionel Sambuc  unreachable
107f4a2713aSLionel Sambuc}
108f4a2713aSLionel Sambuc
109f4a2713aSLionel Sambuc; Don't try to place code on invoke critical edges.
110f4a2713aSLionel Sambuc
111f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test3(
112f4a2713aSLionel Sambuc; CHECK: if.end:
113f4a2713aSLionel Sambuc; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
114f4a2713aSLionel Sambuc; CHECK-NEXT: ret void
115f4a2713aSLionel Sambuc; CHECK-NEXT: }
116f4a2713aSLionel Sambucdefine void @test3(i8* %p, i1 %b) {
117f4a2713aSLionel Sambucentry:
118f4a2713aSLionel Sambuc  %0 = call i8* @objc_retain(i8* %p)
119f4a2713aSLionel Sambuc  call void @callee()
120f4a2713aSLionel Sambuc  br i1 %b, label %if.else, label %if.then
121f4a2713aSLionel Sambuc
122f4a2713aSLionel Sambucif.then:
123f4a2713aSLionel Sambuc  invoke void @use_pointer(i8* %p)
124f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
125f4a2713aSLionel Sambuc
126f4a2713aSLionel Sambucif.else:
127f4a2713aSLionel Sambuc  invoke void @use_pointer(i8* %p)
128f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
129f4a2713aSLionel Sambuc
130f4a2713aSLionel Sambuclpad:
131f4a2713aSLionel Sambuc  %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
132f4a2713aSLionel Sambuc       cleanup
133f4a2713aSLionel Sambuc  ret void
134f4a2713aSLionel Sambuc
135f4a2713aSLionel Sambucif.end:
136f4a2713aSLionel Sambuc  call void @objc_release(i8* %p)
137f4a2713aSLionel Sambuc  ret void
138f4a2713aSLionel Sambuc}
139f4a2713aSLionel Sambuc
140f4a2713aSLionel Sambuc; Like test3, but with ARC-relevant exception handling.
141f4a2713aSLionel Sambuc
142f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test4(
143f4a2713aSLionel Sambuc; CHECK: lpad:
144f4a2713aSLionel Sambuc; CHECK-NEXT: %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
145f4a2713aSLionel Sambuc; CHECK-NEXT: cleanup
146f4a2713aSLionel Sambuc; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
147f4a2713aSLionel Sambuc; CHECK-NEXT: ret void
148f4a2713aSLionel Sambuc; CHECK: if.end:
149f4a2713aSLionel Sambuc; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
150f4a2713aSLionel Sambuc; CHECK-NEXT: ret void
151f4a2713aSLionel Sambuc; CHECK-NEXT: }
152f4a2713aSLionel Sambucdefine void @test4(i8* %p, i1 %b) {
153f4a2713aSLionel Sambucentry:
154f4a2713aSLionel Sambuc  %0 = call i8* @objc_retain(i8* %p)
155f4a2713aSLionel Sambuc  call void @callee()
156f4a2713aSLionel Sambuc  br i1 %b, label %if.else, label %if.then
157f4a2713aSLionel Sambuc
158f4a2713aSLionel Sambucif.then:
159f4a2713aSLionel Sambuc  invoke void @use_pointer(i8* %p)
160f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad
161f4a2713aSLionel Sambuc
162f4a2713aSLionel Sambucif.else:
163f4a2713aSLionel Sambuc  invoke void @use_pointer(i8* %p)
164f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad
165f4a2713aSLionel Sambuc
166f4a2713aSLionel Sambuclpad:
167f4a2713aSLionel Sambuc  %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
168f4a2713aSLionel Sambuc       cleanup
169f4a2713aSLionel Sambuc  call void @objc_release(i8* %p)
170f4a2713aSLionel Sambuc  ret void
171f4a2713aSLionel Sambuc
172f4a2713aSLionel Sambucif.end:
173f4a2713aSLionel Sambuc  call void @objc_release(i8* %p)
174f4a2713aSLionel Sambuc  ret void
175f4a2713aSLionel Sambuc}
176f4a2713aSLionel Sambuc
177f4a2713aSLionel Sambuc; Don't turn the retainAutoreleaseReturnValue into retain, because it's
178f4a2713aSLionel Sambuc; for an invoke which we can assume codegen will put immediately prior.
179f4a2713aSLionel Sambuc
180f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test5(
181f4a2713aSLionel Sambuc; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
182f4a2713aSLionel Sambuc; CHECK: }
183f4a2713aSLionel Sambucdefine void @test5() {
184f4a2713aSLionel Sambucentry:
185f4a2713aSLionel Sambuc  %z = invoke i8* @returner()
186f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
187f4a2713aSLionel Sambuc
188f4a2713aSLionel Sambuclpad:
189f4a2713aSLionel Sambuc  %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
190f4a2713aSLionel Sambuc          cleanup
191f4a2713aSLionel Sambuc  ret void
192f4a2713aSLionel Sambuc
193f4a2713aSLionel Sambucif.end:
194f4a2713aSLionel Sambuc  call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
195f4a2713aSLionel Sambuc  ret void
196f4a2713aSLionel Sambuc}
197f4a2713aSLionel Sambuc
198f4a2713aSLionel Sambuc; Like test5, but there's intervening code.
199f4a2713aSLionel Sambuc
200f4a2713aSLionel Sambuc; CHECK-LABEL: define void @test6(
201f4a2713aSLionel Sambuc; CHECK: call i8* @objc_retain(i8* %z)
202f4a2713aSLionel Sambuc; CHECK: }
203f4a2713aSLionel Sambucdefine void @test6() {
204f4a2713aSLionel Sambucentry:
205f4a2713aSLionel Sambuc  %z = invoke i8* @returner()
206f4a2713aSLionel Sambuc          to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
207f4a2713aSLionel Sambuc
208f4a2713aSLionel Sambuclpad:
209f4a2713aSLionel Sambuc  %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
210f4a2713aSLionel Sambuc          cleanup
211f4a2713aSLionel Sambuc  ret void
212f4a2713aSLionel Sambuc
213f4a2713aSLionel Sambucif.end:
214f4a2713aSLionel Sambuc  call void @callee()
215f4a2713aSLionel Sambuc  call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
216f4a2713aSLionel Sambuc  ret void
217f4a2713aSLionel Sambuc}
218f4a2713aSLionel Sambuc
219f4a2713aSLionel Sambucdeclare i32 @__gxx_personality_v0(...)
220f4a2713aSLionel Sambucdeclare i32 @__objc_personality_v0(...)
221f4a2713aSLionel Sambuc
222f4a2713aSLionel Sambuc; CHECK: attributes [[NUW]] = { nounwind }
223f4a2713aSLionel Sambuc
224*0a6a1f1dSLionel Sambuc!0 = !{}
225