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