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-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: } 21define void @test0(i8* %zipFile) { 22entry: 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 28invoke.cont: ; preds = %entry 29 call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 30 ret void 31 32lpad: ; 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: } 53define void @test1(i8* %zipFile) { 54entry: 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 60invoke.cont: ; preds = %entry 61 call void @callee() 62 br label %done 63 64lpad: ; preds = %entry 65 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0 66 cleanup 67 call void @callee() 68 br label %done 69 70done: 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: } 88define void @test2() { 89entry: 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 93invoke.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 99finally.cont: ; preds = %invoke.cont 100 tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0 101 ret void 102 103finally.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: } 116define void @test3(i8* %p, i1 %b) { 117entry: 118 %0 = call i8* @objc_retain(i8* %p) 119 call void @callee() 120 br i1 %b, label %if.else, label %if.then 121 122if.then: 123 invoke void @use_pointer(i8* %p) 124 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 125 126if.else: 127 invoke void @use_pointer(i8* %p) 128 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 129 130lpad: 131 %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 132 cleanup 133 ret void 134 135if.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: } 152define void @test4(i8* %p, i1 %b) { 153entry: 154 %0 = call i8* @objc_retain(i8* %p) 155 call void @callee() 156 br i1 %b, label %if.else, label %if.then 157 158if.then: 159 invoke void @use_pointer(i8* %p) 160 to label %if.end unwind label %lpad 161 162if.else: 163 invoke void @use_pointer(i8* %p) 164 to label %if.end unwind label %lpad 165 166lpad: 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 172if.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: } 183define void @test5() { 184entry: 185 %z = invoke i8* @returner() 186 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 187 188lpad: 189 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 190 cleanup 191 ret void 192 193if.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: } 203define void @test6() { 204entry: 205 %z = invoke i8* @returner() 206 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 207 208lpad: 209 %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) 210 cleanup 211 ret void 212 213if.end: 214 call void @callee() 215 call i8* @objc_retainAutoreleasedReturnValue(i8* %z) 216 ret void 217} 218 219declare i32 @__gxx_personality_v0(...) 220declare i32 @__objc_personality_v0(...) 221 222; CHECK: attributes [[NUW]] = { nounwind } 223 224!0 = !{} 225