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