489 lines · plain
1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s2 3declare ptr @llvm.objc.retain(ptr)4declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)5declare void @llvm.objc.release(ptr)6declare ptr @llvm.objc.autorelease(ptr)7declare ptr @llvm.objc.autoreleaseReturnValue(ptr)8declare void @llvm.objc.autoreleasePoolPop(ptr)9declare ptr @llvm.objc.autoreleasePoolPush()10declare ptr @llvm.objc.retainBlock(ptr)11 12declare ptr @objc_retainedObject(ptr)13declare ptr @objc_unretainedObject(ptr)14declare ptr @objc_unretainedPointer(ptr)15 16declare void @use_pointer(ptr)17declare void @callee()18declare void @callee_fnptr(ptr)19declare void @invokee()20declare ptr @returner()21declare ptr @returner1()22declare ptr @returner2()23declare void @bar(ptr)24declare void @use_alloca(ptr)25 26declare void @llvm.dbg.value(metadata, metadata, metadata)27 28declare ptr @objc_msgSend(ptr, ptr, ...)29 30 31; In the presence of allocas, unconditionally remove retain/release pairs only32; if they are known safe in both directions. This prevents matching up an inner33; retain with the boundary guarding release in the following situation:34; 35; %A = alloca36; retain(%x)37; retain(%x) <--- Inner Retain38; store %x, %A39; %y = load %A40; ... DO STUFF ...41; release(%y)42; release(%x) <--- Guarding Release43;44; rdar://1375031945 46; CHECK: define void @test1a(ptr %x)47; CHECK: @llvm.objc.retain(ptr %x)48; CHECK: @llvm.objc.retain(ptr %x)49; CHECK: @llvm.objc.release(ptr %y)50; CHECK: @llvm.objc.release(ptr %x)51; CHECK: ret void52; CHECK: }53define void @test1a(ptr %x) {54entry:55 %A = alloca ptr56 tail call ptr @llvm.objc.retain(ptr %x)57 tail call ptr @llvm.objc.retain(ptr %x)58 store ptr %x, ptr %A, align 859 %y = load ptr, ptr %A60 call void @use_alloca(ptr %A)61 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !062 call void @use_pointer(ptr %x)63 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !064 ret void65}66 67; CHECK: define void @test1b(ptr %x)68; CHECK: @llvm.objc.retain(ptr %x)69; CHECK: @llvm.objc.retain(ptr %x)70; CHECK: @llvm.objc.release(ptr %y)71; CHECK: @llvm.objc.release(ptr %x)72; CHECK: ret void73; CHECK: }74define void @test1b(ptr %x) {75entry:76 %A = alloca ptr77 tail call ptr @llvm.objc.retain(ptr %x)78 tail call ptr @llvm.objc.retain(ptr %x)79 store ptr %x, ptr %A, align 880 %y = load ptr, ptr %A81 call void @use_alloca(ptr %A)82 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !083 call void @use_pointer(ptr %x)84 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !085 ret void86}87 88 89; CHECK: define void @test1c(ptr %x)90; CHECK: @llvm.objc.retain(ptr %x)91; CHECK: @llvm.objc.retain(ptr %x)92; CHECK: @llvm.objc.release(ptr %y)93; CHECK: @llvm.objc.release(ptr %x)94; CHECK: ret void95; CHECK: }96define void @test1c(ptr %x) {97entry:98 %A = alloca ptr, i32 399 %gep = getelementptr ptr, ptr %A, i32 2100 tail call ptr @llvm.objc.retain(ptr %x)101 tail call ptr @llvm.objc.retain(ptr %x)102 store ptr %x, ptr %gep, align 8103 %y = load ptr, ptr %gep104 call void @use_alloca(ptr %A)105 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0106 call void @use_pointer(ptr %x)107 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0108 ret void109}110 111 112; CHECK: define void @test1d(ptr %x, i1 %arg)113; CHECK: @llvm.objc.retain(ptr %x)114; CHECK: @llvm.objc.retain(ptr %x)115; CHECK: @llvm.objc.release(ptr %y)116; CHECK: @llvm.objc.release(ptr %x)117; CHECK: ret void118; CHECK: }119define void @test1d(ptr %x, i1 %arg) {120entry:121 br i1 %arg, label %use_allocaA, label %use_allocaB122 123use_allocaA:124 %allocaA = alloca ptr125 br label %exit126 127use_allocaB:128 %allocaB = alloca ptr129 br label %exit130 131exit:132 %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]133 tail call ptr @llvm.objc.retain(ptr %x)134 tail call ptr @llvm.objc.retain(ptr %x)135 store ptr %x, ptr %A, align 8136 %y = load ptr, ptr %A137 call void @use_alloca(ptr %A)138 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0139 call void @use_pointer(ptr %x)140 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0141 ret void142}143 144; CHECK: define void @test1e(ptr %x, i1 %arg)145; CHECK: @llvm.objc.retain(ptr %x)146; CHECK: @llvm.objc.retain(ptr %x)147; CHECK: @llvm.objc.release(ptr %y)148; CHECK: @llvm.objc.release(ptr %x)149; CHECK: ret void150; CHECK: }151define void @test1e(ptr %x, i1 %arg) {152entry:153 br i1 %arg, label %use_allocaA, label %use_allocaB154 155use_allocaA:156 %allocaA = alloca ptr, i32 4157 br label %exit158 159use_allocaB:160 %allocaB = alloca ptr, i32 4161 br label %exit162 163exit:164 %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]165 %gep = getelementptr ptr, ptr %A, i32 2166 tail call ptr @llvm.objc.retain(ptr %x)167 tail call ptr @llvm.objc.retain(ptr %x)168 store ptr %x, ptr %gep, align 8169 %y = load ptr, ptr %gep170 call void @use_alloca(ptr %A)171 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0172 call void @use_pointer(ptr %x)173 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0174 ret void175}176 177; CHECK: define void @test1f(ptr %x)178; CHECK: @llvm.objc.retain(ptr %x)179; CHECK: @llvm.objc.retain(ptr %x)180; CHECK: @llvm.objc.release(ptr %y)181; CHECK: @llvm.objc.release(ptr %x)182; CHECK: ret void183; CHECK: }184define void @test1f(ptr %x) {185entry:186 %allocaOne = alloca ptr187 %allocaTwo = alloca ptr188 %A = select i1 undef, ptr %allocaOne, ptr %allocaTwo189 tail call ptr @llvm.objc.retain(ptr %x)190 tail call ptr @llvm.objc.retain(ptr %x)191 store ptr %x, ptr %A, align 8192 %y = load ptr, ptr %A193 call void @use_alloca(ptr %A)194 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0195 call void @use_pointer(ptr %x)196 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0197 ret void198}199 200; Make sure that if a store is in a different basic block we handle known safe201; conservatively.202 203 204; CHECK: define void @test2a(ptr %x)205; CHECK: @llvm.objc.retain(ptr %x)206; CHECK: @llvm.objc.retain(ptr %x)207; CHECK: @llvm.objc.release(ptr %y)208; CHECK: @llvm.objc.release(ptr %x)209; CHECK: ret void210; CHECK: }211define void @test2a(ptr %x) {212entry:213 %A = alloca ptr214 store ptr %x, ptr %A, align 8215 %y = load ptr, ptr %A216 br label %bb1217 218bb1:219 br label %bb2220 221bb2:222 br label %bb3223 224bb3:225 tail call ptr @llvm.objc.retain(ptr %x)226 tail call ptr @llvm.objc.retain(ptr %x)227 call void @use_alloca(ptr %A)228 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0229 call void @use_pointer(ptr %x)230 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0231 ret void232}233 234; CHECK: define void @test2b(ptr %x)235; CHECK: @llvm.objc.retain(ptr %x)236; CHECK: @llvm.objc.retain(ptr %x)237; CHECK: @llvm.objc.release(ptr %y)238; CHECK: @llvm.objc.release(ptr %x)239; CHECK: ret void240; CHECK: }241define void @test2b(ptr %x) {242entry:243 %A = alloca ptr244 store ptr %x, ptr %A, align 8245 %y = load ptr, ptr %A246 br label %bb1247 248bb1:249 br label %bb2250 251bb2:252 br label %bb3253 254bb3:255 tail call ptr @llvm.objc.retain(ptr %x)256 tail call ptr @llvm.objc.retain(ptr %x)257 call void @use_alloca(ptr %A)258 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0259 call void @use_pointer(ptr %x)260 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0261 ret void262}263 264; CHECK: define void @test2c(ptr %x)265; CHECK: @llvm.objc.retain(ptr %x)266; CHECK: @llvm.objc.retain(ptr %x)267; CHECK: @llvm.objc.release(ptr %y)268; CHECK: @llvm.objc.release(ptr %x)269; CHECK: ret void270; CHECK: }271define void @test2c(ptr %x) {272entry:273 %A = alloca ptr, i32 3274 %gep1 = getelementptr ptr, ptr %A, i32 2275 store ptr %x, ptr %gep1, align 8276 %gep2 = getelementptr ptr, ptr %A, i32 2277 %y = load ptr, ptr %gep2278 tail call ptr @llvm.objc.retain(ptr %x)279 br label %bb1280 281bb1:282 br label %bb2283 284bb2:285 br label %bb3286 287bb3:288 tail call ptr @llvm.objc.retain(ptr %x)289 call void @use_alloca(ptr %A)290 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0291 call void @use_pointer(ptr %x)292 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0293 ret void294}295 296; CHECK: define void @test2d(ptr %x)297; CHECK: @llvm.objc.retain(ptr %x)298; CHECK: @llvm.objc.retain(ptr %x)299; CHECK: @llvm.objc.release(ptr %y)300; CHECK: @llvm.objc.release(ptr %x)301; CHECK: ret void302; CHECK: }303define void @test2d(ptr %x) {304entry:305 tail call ptr @llvm.objc.retain(ptr %x)306 br label %bb1307 308bb1:309 %Abb1 = alloca ptr, i32 3310 %gepbb11 = getelementptr ptr, ptr %Abb1, i32 2311 store ptr %x, ptr %gepbb11, align 8312 %gepbb12 = getelementptr ptr, ptr %Abb1, i32 2313 %ybb1 = load ptr, ptr %gepbb12314 br label %bb3315 316bb2:317 %Abb2 = alloca ptr, i32 4318 %gepbb21 = getelementptr ptr, ptr %Abb2, i32 2319 store ptr %x, ptr %gepbb21, align 8320 %gepbb22 = getelementptr ptr, ptr %Abb2, i32 2321 %ybb2 = load ptr, ptr %gepbb22322 br label %bb3323 324bb3:325 %A = phi ptr [ %Abb1, %bb1 ], [ %Abb2, %bb2 ]326 %y = phi ptr [ %ybb1, %bb1 ], [ %ybb2, %bb2 ]327 tail call ptr @llvm.objc.retain(ptr %x)328 call void @use_alloca(ptr %A)329 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0330 call void @use_pointer(ptr %x)331 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0332 ret void333}334 335; Make sure in the presence of allocas, if we find a cfghazard we do not perform336; code motion even if we are known safe. These two concepts are separate and337; should be treated as such.338;339; rdar://13949644340 341; CHECK: define void @test3a() {342; CHECK: entry:343; CHECK: @llvm.objc.retainAutoreleasedReturnValue344; CHECK: @llvm.objc.retain345; CHECK: @llvm.objc.retain346; CHECK: @llvm.objc.retain347; CHECK: @llvm.objc.retain348; CHECK: arraydestroy.body:349; CHECK: @llvm.objc.release350; CHECK-NOT: @llvm.objc.release351; CHECK: arraydestroy.done:352; CHECK-NOT: @llvm.objc.release353; CHECK: arraydestroy.body1:354; CHECK: @llvm.objc.release355; CHECK-NOT: @llvm.objc.release356; CHECK: arraydestroy.done1:357; CHECK: @llvm.objc.release358; CHECK: ret void359; CHECK: }360define void @test3a() {361entry:362 %keys = alloca [2 x ptr], align 16363 %objs = alloca [2 x ptr], align 16364 365 %call1 = call ptr @returner()366 %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)367 368 tail call ptr @llvm.objc.retain(ptr %call1)369 store ptr %call1, ptr %objs, align 8370 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1371 tail call ptr @llvm.objc.retain(ptr %call1)372 store ptr %call1, ptr %objs.elt373 374 %call2 = call ptr @returner1()375 %call3 = call ptr @returner2()376 tail call ptr @llvm.objc.retain(ptr %call2)377 store ptr %call2, ptr %keys, align 8378 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1379 tail call ptr @llvm.objc.retain(ptr %call3)380 store ptr %call3, ptr %keys.elt 381 382 %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2383 br label %arraydestroy.body384 385arraydestroy.body:386 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]387 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1388 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8389 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0390 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs391 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body392 393arraydestroy.done:394 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2395 br label %arraydestroy.body1396 397arraydestroy.body1:398 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]399 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1400 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8401 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0402 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys403 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1404 405arraydestroy.done1:406 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0407 ret void408}409 410; Make sure that even though we stop said code motion we still allow for411; pointers to be removed if we are known safe in both directions.412;413; rdar://13949644414 415; CHECK: define void @test3b() {416; CHECK: entry:417; CHECK: @llvm.objc.retainAutoreleasedReturnValue418; CHECK: @llvm.objc.retain419; CHECK: @llvm.objc.retain420; CHECK: @llvm.objc.retain421; CHECK: @llvm.objc.retain422; CHECK: arraydestroy.body:423; CHECK: @llvm.objc.release424; CHECK-NOT: @llvm.objc.release425; CHECK: arraydestroy.done:426; CHECK-NOT: @llvm.objc.release427; CHECK: arraydestroy.body1:428; CHECK: @llvm.objc.release429; CHECK-NOT: @llvm.objc.release430; CHECK: arraydestroy.done1:431; CHECK: @llvm.objc.release432; CHECK: ret void433; CHECK: }434define void @test3b() {435entry:436 %keys = alloca [2 x ptr], align 16437 %objs = alloca [2 x ptr], align 16438 439 %call1 = call ptr @returner()440 %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)441 %tmp1 = tail call ptr @llvm.objc.retain(ptr %call1)442 443 tail call ptr @llvm.objc.retain(ptr %call1)444 store ptr %call1, ptr %objs, align 8445 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1446 tail call ptr @llvm.objc.retain(ptr %call1)447 store ptr %call1, ptr %objs.elt448 449 %call2 = call ptr @returner1()450 %call3 = call ptr @returner2()451 tail call ptr @llvm.objc.retain(ptr %call2)452 store ptr %call2, ptr %keys, align 8453 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1454 tail call ptr @llvm.objc.retain(ptr %call3)455 store ptr %call3, ptr %keys.elt 456 457 %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2458 br label %arraydestroy.body459 460arraydestroy.body:461 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]462 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1463 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8464 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0465 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs466 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body467 468arraydestroy.done:469 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2470 br label %arraydestroy.body1471 472arraydestroy.body1:473 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]474 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1475 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8476 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0477 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys478 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1479 480arraydestroy.done1:481 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0482 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0483 ret void484}485 486!0 = !{}487 488declare i32 @__gxx_personality_v0(...)489