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