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