1; RUN: opt -S -passes=objc-arc < %s | FileCheck %s 2 3declare ptr @llvm.objc.retain(ptr) 4declare void @llvm.objc.release(ptr) 5declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr) 6declare ptr @objc_msgSend(ptr, ptr, ...) 7declare void @use_pointer(ptr) 8declare void @callee() 9declare ptr @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 @llvm.objc.release(ptr %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0 16; CHECK: ret void 17; CHECK: lpad: 18; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0 19; CHECK: ret void 20; CHECK-NEXT: } 21define void @test0(ptr %zipFile) personality ptr @__gxx_personality_v0 { 22entry: 23 call ptr @llvm.objc.retain(ptr %zipFile) nounwind 24 call void @use_pointer(ptr %zipFile) 25 invoke void @objc_msgSend(ptr %zipFile) 26 to label %invoke.cont unwind label %lpad 27 28invoke.cont: ; preds = %entry 29 call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0 30 ret void 31 32lpad: ; preds = %entry 33 %exn = landingpad {ptr, i32} 34 cleanup 35 call void @llvm.objc.release(ptr %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 @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0 44; CHECK: call void @callee() 45; CHECK: br label %done 46; CHECK: lpad: 47; CHECK: call void @llvm.objc.release(ptr %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(ptr %zipFile) personality ptr @__gxx_personality_v0 { 54entry: 55 call ptr @llvm.objc.retain(ptr %zipFile) nounwind 56 call void @use_pointer(ptr %zipFile) 57 invoke void @objc_msgSend(ptr %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 {ptr, i32} 66 cleanup 67 call void @callee() 68 br label %done 69 70done: 71 call void @llvm.objc.release(ptr %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() personality ptr @__objc_personality_v0 { 79; CHECK: invoke.cont: 80; CHECK-NEXT: call ptr @llvm.objc.retain 81; CHECK-NOT: @llvm.objc.r 82; CHECK: finally.cont: 83; CHECK-NEXT: call void @llvm.objc.release 84; CHECK-NOT: @objc 85; CHECK: finally.rethrow: 86; CHECK-NOT: @objc 87; CHECK: } 88define void @test2() personality ptr @__objc_personality_v0 { 89entry: 90 %call = invoke ptr @objc_msgSend() 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 ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind 95 call void @objc_msgSend(), !clang.arc.no_objc_arc_exceptions !0 96 invoke void @use_pointer(ptr %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 @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0 101 ret void 102 103finally.rethrow: ; preds = %invoke.cont, %entry 104 %tmp2 = landingpad { ptr, i32 } 105 catch ptr 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 @llvm.objc.release(ptr %p) [[NUW]] 114; CHECK-NEXT: ret void 115; CHECK-NEXT: } 116define void @test3(ptr %p, i1 %b) personality ptr @__objc_personality_v0 { 117entry: 118 %0 = call ptr @llvm.objc.retain(ptr %p) 119 call void @callee() 120 br i1 %b, label %if.else, label %if.then 121 122if.then: 123 invoke void @use_pointer(ptr %p) 124 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 125 126if.else: 127 invoke void @use_pointer(ptr %p) 128 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 129 130lpad: 131 %r = landingpad { ptr, i32 } 132 cleanup 133 ret void 134 135if.end: 136 call void @llvm.objc.release(ptr %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 { ptr, i32 } 145; CHECK-NEXT: cleanup 146; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]] 147; CHECK-NEXT: ret void 148; CHECK: if.end: 149; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]] 150; CHECK-NEXT: ret void 151; CHECK-NEXT: } 152define void @test4(ptr %p, i1 %b) personality ptr @__objc_personality_v0 { 153entry: 154 %0 = call ptr @llvm.objc.retain(ptr %p) 155 call void @callee() 156 br i1 %b, label %if.else, label %if.then 157 158if.then: 159 invoke void @use_pointer(ptr %p) 160 to label %if.end unwind label %lpad 161 162if.else: 163 invoke void @use_pointer(ptr %p) 164 to label %if.end unwind label %lpad 165 166lpad: 167 %r = landingpad { ptr, i32 } 168 cleanup 169 call void @llvm.objc.release(ptr %p) 170 ret void 171 172if.end: 173 call void @llvm.objc.release(ptr %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 ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z) 182; CHECK: } 183define void @test5() personality ptr @__objc_personality_v0 { 184entry: 185 %z = invoke ptr @returner() 186 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 187 188lpad: 189 %r13 = landingpad { ptr, i32 } 190 cleanup 191 ret void 192 193if.end: 194 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z) 195 ret void 196} 197 198; Like test5, but there's intervening code. 199 200; CHECK-LABEL: define void @test6( 201; CHECK: call ptr @llvm.objc.retain(ptr %z) 202; CHECK: } 203define void @test6() personality ptr @__objc_personality_v0 { 204entry: 205 %z = invoke ptr @returner() 206 to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0 207 208lpad: 209 %r13 = landingpad { ptr, i32 } 210 cleanup 211 ret void 212 213if.end: 214 call void @callee() 215 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %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