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