1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s 2 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 only 32; if they are known safe in both directions. This prevents matching up an inner 33; retain with the boundary guarding release in the following situation: 34; 35; %A = alloca 36; retain(%x) 37; retain(%x) <--- Inner Retain 38; store %x, %A 39; %y = load %A 40; ... DO STUFF ... 41; release(%y) 42; release(%x) <--- Guarding Release 43; 44; rdar://13750319 45 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 void 52; CHECK: } 53define void @test1a(ptr %x) { 54entry: 55 %A = alloca ptr 56 tail call ptr @llvm.objc.retain(ptr %x) 57 tail call ptr @llvm.objc.retain(ptr %x) 58 store ptr %x, ptr %A, align 8 59 %y = load ptr, ptr %A 60 call void @use_alloca(ptr %A) 61 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 62 call void @use_pointer(ptr %x) 63 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 64 ret void 65} 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 void 73; CHECK: } 74define void @test1b(ptr %x) { 75entry: 76 %A = alloca ptr 77 tail call ptr @llvm.objc.retain(ptr %x) 78 tail call ptr @llvm.objc.retain(ptr %x) 79 store ptr %x, ptr %A, align 8 80 %y = load ptr, ptr %A 81 call void @use_alloca(ptr %A) 82 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 83 call void @use_pointer(ptr %x) 84 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 85 ret void 86} 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 void 95; CHECK: } 96define void @test1c(ptr %x) { 97entry: 98 %A = alloca ptr, i32 3 99 %gep = getelementptr ptr, ptr %A, i32 2 100 tail call ptr @llvm.objc.retain(ptr %x) 101 tail call ptr @llvm.objc.retain(ptr %x) 102 store ptr %x, ptr %gep, align 8 103 %y = load ptr, ptr %gep 104 call void @use_alloca(ptr %A) 105 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 106 call void @use_pointer(ptr %x) 107 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 108 ret void 109} 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 void 118; CHECK: } 119define void @test1d(ptr %x, i1 %arg) { 120entry: 121 br i1 %arg, label %use_allocaA, label %use_allocaB 122 123use_allocaA: 124 %allocaA = alloca ptr 125 br label %exit 126 127use_allocaB: 128 %allocaB = alloca ptr 129 br label %exit 130 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 8 136 %y = load ptr, ptr %A 137 call void @use_alloca(ptr %A) 138 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 139 call void @use_pointer(ptr %x) 140 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 141 ret void 142} 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 void 150; CHECK: } 151define void @test1e(ptr %x, i1 %arg) { 152entry: 153 br i1 %arg, label %use_allocaA, label %use_allocaB 154 155use_allocaA: 156 %allocaA = alloca ptr, i32 4 157 br label %exit 158 159use_allocaB: 160 %allocaB = alloca ptr, i32 4 161 br label %exit 162 163exit: 164 %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ] 165 %gep = getelementptr ptr, ptr %A, i32 2 166 tail call ptr @llvm.objc.retain(ptr %x) 167 tail call ptr @llvm.objc.retain(ptr %x) 168 store ptr %x, ptr %gep, align 8 169 %y = load ptr, ptr %gep 170 call void @use_alloca(ptr %A) 171 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 172 call void @use_pointer(ptr %x) 173 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 174 ret void 175} 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 void 183; CHECK: } 184define void @test1f(ptr %x) { 185entry: 186 %allocaOne = alloca ptr 187 %allocaTwo = alloca ptr 188 %A = select i1 undef, ptr %allocaOne, ptr %allocaTwo 189 tail call ptr @llvm.objc.retain(ptr %x) 190 tail call ptr @llvm.objc.retain(ptr %x) 191 store ptr %x, ptr %A, align 8 192 %y = load ptr, ptr %A 193 call void @use_alloca(ptr %A) 194 call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0 195 call void @use_pointer(ptr %x) 196 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 197 ret void 198} 199 200; Make sure that if a store is in a different basic block we handle known safe 201; 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 void 210; CHECK: } 211define void @test2a(ptr %x) { 212entry: 213 %A = alloca ptr 214 store ptr %x, ptr %A, align 8 215 %y = load ptr, ptr %A 216 br label %bb1 217 218bb1: 219 br label %bb2 220 221bb2: 222 br label %bb3 223 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 !0 229 call void @use_pointer(ptr %x) 230 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 231 ret void 232} 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 void 240; CHECK: } 241define void @test2b(ptr %x) { 242entry: 243 %A = alloca ptr 244 store ptr %x, ptr %A, align 8 245 %y = load ptr, ptr %A 246 br label %bb1 247 248bb1: 249 br label %bb2 250 251bb2: 252 br label %bb3 253 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 !0 259 call void @use_pointer(ptr %x) 260 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 261 ret void 262} 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 void 270; CHECK: } 271define void @test2c(ptr %x) { 272entry: 273 %A = alloca ptr, i32 3 274 %gep1 = getelementptr ptr, ptr %A, i32 2 275 store ptr %x, ptr %gep1, align 8 276 %gep2 = getelementptr ptr, ptr %A, i32 2 277 %y = load ptr, ptr %gep2 278 tail call ptr @llvm.objc.retain(ptr %x) 279 br label %bb1 280 281bb1: 282 br label %bb2 283 284bb2: 285 br label %bb3 286 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 !0 291 call void @use_pointer(ptr %x) 292 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 293 ret void 294} 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 void 302; CHECK: } 303define void @test2d(ptr %x) { 304entry: 305 tail call ptr @llvm.objc.retain(ptr %x) 306 br label %bb1 307 308bb1: 309 %Abb1 = alloca ptr, i32 3 310 %gepbb11 = getelementptr ptr, ptr %Abb1, i32 2 311 store ptr %x, ptr %gepbb11, align 8 312 %gepbb12 = getelementptr ptr, ptr %Abb1, i32 2 313 %ybb1 = load ptr, ptr %gepbb12 314 br label %bb3 315 316bb2: 317 %Abb2 = alloca ptr, i32 4 318 %gepbb21 = getelementptr ptr, ptr %Abb2, i32 2 319 store ptr %x, ptr %gepbb21, align 8 320 %gepbb22 = getelementptr ptr, ptr %Abb2, i32 2 321 %ybb2 = load ptr, ptr %gepbb22 322 br label %bb3 323 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 !0 330 call void @use_pointer(ptr %x) 331 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 332 ret void 333} 334 335; Make sure in the presence of allocas, if we find a cfghazard we do not perform 336; code motion even if we are known safe. These two concepts are separate and 337; should be treated as such. 338; 339; rdar://13949644 340 341; CHECK: define void @test3a() { 342; CHECK: entry: 343; CHECK: @llvm.objc.retainAutoreleasedReturnValue 344; CHECK: @llvm.objc.retain 345; CHECK: @llvm.objc.retain 346; CHECK: @llvm.objc.retain 347; CHECK: @llvm.objc.retain 348; CHECK: arraydestroy.body: 349; CHECK: @llvm.objc.release 350; CHECK-NOT: @llvm.objc.release 351; CHECK: arraydestroy.done: 352; CHECK-NOT: @llvm.objc.release 353; CHECK: arraydestroy.body1: 354; CHECK: @llvm.objc.release 355; CHECK-NOT: @llvm.objc.release 356; CHECK: arraydestroy.done1: 357; CHECK: @llvm.objc.release 358; CHECK: ret void 359; CHECK: } 360define void @test3a() { 361entry: 362 %keys = alloca [2 x ptr], align 16 363 %objs = alloca [2 x ptr], align 16 364 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 8 370 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1 371 tail call ptr @llvm.objc.retain(ptr %call1) 372 store ptr %call1, ptr %objs.elt 373 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 8 378 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1 379 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 2 383 br label %arraydestroy.body 384 385arraydestroy.body: 386 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ] 387 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1 388 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8 389 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0 390 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs 391 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body 392 393arraydestroy.done: 394 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2 395 br label %arraydestroy.body1 396 397arraydestroy.body1: 398 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ] 399 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1 400 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8 401 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0 402 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys 403 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1 404 405arraydestroy.done1: 406 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0 407 ret void 408} 409 410; Make sure that even though we stop said code motion we still allow for 411; pointers to be removed if we are known safe in both directions. 412; 413; rdar://13949644 414 415; CHECK: define void @test3b() { 416; CHECK: entry: 417; CHECK: @llvm.objc.retainAutoreleasedReturnValue 418; CHECK: @llvm.objc.retain 419; CHECK: @llvm.objc.retain 420; CHECK: @llvm.objc.retain 421; CHECK: @llvm.objc.retain 422; CHECK: arraydestroy.body: 423; CHECK: @llvm.objc.release 424; CHECK-NOT: @llvm.objc.release 425; CHECK: arraydestroy.done: 426; CHECK-NOT: @llvm.objc.release 427; CHECK: arraydestroy.body1: 428; CHECK: @llvm.objc.release 429; CHECK-NOT: @llvm.objc.release 430; CHECK: arraydestroy.done1: 431; CHECK: @llvm.objc.release 432; CHECK: ret void 433; CHECK: } 434define void @test3b() { 435entry: 436 %keys = alloca [2 x ptr], align 16 437 %objs = alloca [2 x ptr], align 16 438 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 8 445 %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1 446 tail call ptr @llvm.objc.retain(ptr %call1) 447 store ptr %call1, ptr %objs.elt 448 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 8 453 %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1 454 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 2 458 br label %arraydestroy.body 459 460arraydestroy.body: 461 %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ] 462 %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1 463 %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8 464 call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0 465 %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs 466 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body 467 468arraydestroy.done: 469 %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2 470 br label %arraydestroy.body1 471 472arraydestroy.body1: 473 %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ] 474 %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1 475 %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8 476 call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0 477 %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys 478 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1 479 480arraydestroy.done1: 481 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0 482 call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0 483 ret void 484} 485 486!0 = !{} 487 488declare i32 @__gxx_personality_v0(...) 489