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