1 ; RUN: opt -S -objc-arc < %s | FileCheck %s 2 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*) 8 declare void @callee() 9 declare 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) [[NUW:#[0-9]+]], !clang.imprecise_release !0 16 ; CHECK: ret void 17 ; CHECK: lpad: 18 ; CHECK: call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0 19 ; CHECK: ret void 20 define void @test0(i8* %zipFile) { 21 entry: 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 27 invoke.cont: ; preds = %entry 28 call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 29 ret void 30 31 lpad: ; 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) [[NUW]], !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) [[NUW]], !clang.imprecise_release !0 47 ; CHECK: call void @callee() 48 ; CHECK: br label %done 49 ; CHECK: done: 50 ; CHECK-NEXT: ret void 51 define void @test1(i8* %zipFile) { 52 entry: 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 58 invoke.cont: ; preds = %entry 59 call void @callee() 60 br label %done 61 62 lpad: ; preds = %entry 63 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0 64 cleanup 65 call void @callee() 66 br label %done 67 68 done: 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 ; CHECK-NOT: @objc_r 80 ; CHECK: finally.cont: 81 ; CHECK-NEXT: call void @objc_release 82 ; CHECK-NOT: @objc 83 ; CHECK: finally.rethrow: 84 ; CHECK-NOT: @objc 85 ; CHECK: } 86 define void @test2() { 87 entry: 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 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 96 97 finally.cont: ; preds = %invoke.cont 98 tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0 99 ret void 100 101 finally.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) [[NUW]] 112 ; CHECK-NEXT: ret void 113 define void @test3(i8* %p, i1 %b) { 114 entry: 115 %0 = call i8* @objc_retain(i8* %p) 116 call void @callee() 117 br i1 %b, label %if.else, label %if.then 118 119 if.then: 120 invoke void @use_pointer(i8* %p) 121 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 122 123 if.else: 124 invoke void @use_pointer(i8* %p) 125 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 126 127 lpad: 128 %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 129 cleanup 130 ret void 131 132 if.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) [[NUW]] 144 ; CHECK-NEXT: ret void 145 ; CHECK: if.end: 146 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]] 147 ; CHECK-NEXT: ret void 148 define void @test4(i8* %p, i1 %b) { 149 entry: 150 %0 = call i8* @objc_retain(i8* %p) 151 call void @callee() 152 br i1 %b, label %if.else, label %if.then 153 154 if.then: 155 invoke void @use_pointer(i8* %p) 156 to label %if.end unwind label %lpad 157 158 if.else: 159 invoke void @use_pointer(i8* %p) 160 to label %if.end unwind label %lpad 161 162 lpad: 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 168 if.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: } 179 define void @test5() { 180 entry: 181 %z = invoke i8* @returner() 182 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 183 184 lpad: 185 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 186 cleanup 187 ret void 188 189 if.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: } 199 define void @test6() { 200 entry: 201 %z = invoke i8* @returner() 202 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 203 204 lpad: 205 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 206 cleanup 207 ret void 208 209 if.end: 210 call void @callee() 211 call i8* @objc_retainAutoreleasedReturnValue(i8* %z) 212 ret void 213 } 214 215 declare i32 @__gxx_personality_v0(...) 216 declare i32 @__objc_personality_v0(...) 217 218 ; CHECK: attributes [[NUW]] = { nounwind } 219 220 !0 = metadata !{} 221