1 ; RUN: opt -objc-arc -S < %s | FileCheck %s 2 3 declare i8* @objc_retain(i8*) 4 declare i8* @objc_retainAutoreleasedReturnValue(i8*) 5 declare void @objc_release(i8*) 6 declare i8* @objc_autorelease(i8*) 7 declare i8* @objc_autoreleaseReturnValue(i8*) 8 declare void @objc_autoreleasePoolPop(i8*) 9 declare i8* @objc_autoreleasePoolPush() 10 declare i8* @objc_retainBlock(i8*) 11 12 declare i8* @objc_retainedObject(i8*) 13 declare i8* @objc_unretainedObject(i8*) 14 declare i8* @objc_unretainedPointer(i8*) 15 16 declare void @use_pointer(i8*) 17 declare void @callee() 18 declare void @callee_fnptr(void ()*) 19 declare void @invokee() 20 declare i8* @returner() 21 declare i8* @returner1() 22 declare i8* @returner2() 23 declare void @bar(i32 ()*) 24 declare void @use_alloca(i8**) 25 26 declare void @llvm.dbg.value(metadata, i64, metadata) 27 28 declare i8* @objc_msgSend(i8*, i8*, ...) 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(i8* %x) 47 ; CHECK: @objc_retain(i8* %x) 48 ; CHECK: @objc_retain(i8* %x) 49 ; CHECK: @objc_release(i8* %y) 50 ; CHECK: @objc_release(i8* %x) 51 ; CHECK: ret void 52 ; CHECK: } 53 define void @test1a(i8* %x) { 54 entry: 55 %A = alloca i8* 56 tail call i8* @objc_retain(i8* %x) 57 tail call i8* @objc_retain(i8* %x) 58 store i8* %x, i8** %A, align 8 59 %y = load i8** %A 60 call void @use_alloca(i8** %A) 61 call void @objc_release(i8* %y), !clang.imprecise_release !0 62 call void @use_pointer(i8* %x) 63 call void @objc_release(i8* %x), !clang.imprecise_release !0 64 ret void 65 } 66 67 ; CHECK: define void @test1b(i8* %x) 68 ; CHECK: @objc_retain(i8* %x) 69 ; CHECK: @objc_retain(i8* %x) 70 ; CHECK: @objc_release(i8* %y) 71 ; CHECK: @objc_release(i8* %x) 72 ; CHECK: ret void 73 ; CHECK: } 74 define void @test1b(i8* %x) { 75 entry: 76 %A = alloca i8* 77 %gep = getelementptr i8** %A, i32 0 78 tail call i8* @objc_retain(i8* %x) 79 tail call i8* @objc_retain(i8* %x) 80 store i8* %x, i8** %gep, align 8 81 %y = load i8** %A 82 call void @use_alloca(i8** %A) 83 call void @objc_release(i8* %y), !clang.imprecise_release !0 84 call void @use_pointer(i8* %x) 85 call void @objc_release(i8* %x), !clang.imprecise_release !0 86 ret void 87 } 88 89 90 ; CHECK: define void @test1c(i8* %x) 91 ; CHECK: @objc_retain(i8* %x) 92 ; CHECK: @objc_retain(i8* %x) 93 ; CHECK: @objc_release(i8* %y) 94 ; CHECK: @objc_release(i8* %x) 95 ; CHECK: ret void 96 ; CHECK: } 97 define void @test1c(i8* %x) { 98 entry: 99 %A = alloca i8*, i32 3 100 %gep = getelementptr i8** %A, i32 2 101 tail call i8* @objc_retain(i8* %x) 102 tail call i8* @objc_retain(i8* %x) 103 store i8* %x, i8** %gep, align 8 104 %y = load i8** %gep 105 call void @use_alloca(i8** %A) 106 call void @objc_release(i8* %y), !clang.imprecise_release !0 107 call void @use_pointer(i8* %x) 108 call void @objc_release(i8* %x), !clang.imprecise_release !0 109 ret void 110 } 111 112 113 ; CHECK: define void @test1d(i8* %x) 114 ; CHECK: @objc_retain(i8* %x) 115 ; CHECK: @objc_retain(i8* %x) 116 ; CHECK: @objc_release(i8* %y) 117 ; CHECK: @objc_release(i8* %x) 118 ; CHECK: ret void 119 ; CHECK: } 120 define void @test1d(i8* %x) { 121 entry: 122 br i1 undef, label %use_allocaA, label %use_allocaB 123 124 use_allocaA: 125 %allocaA = alloca i8* 126 br label %exit 127 128 use_allocaB: 129 %allocaB = alloca i8* 130 br label %exit 131 132 exit: 133 %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ] 134 %gep = getelementptr i8** %A, i32 0 135 tail call i8* @objc_retain(i8* %x) 136 tail call i8* @objc_retain(i8* %x) 137 store i8* %x, i8** %gep, align 8 138 %y = load i8** %gep 139 call void @use_alloca(i8** %A) 140 call void @objc_release(i8* %y), !clang.imprecise_release !0 141 call void @use_pointer(i8* %x) 142 call void @objc_release(i8* %x), !clang.imprecise_release !0 143 ret void 144 } 145 146 ; CHECK: define void @test1e(i8* %x) 147 ; CHECK: @objc_retain(i8* %x) 148 ; CHECK: @objc_retain(i8* %x) 149 ; CHECK: @objc_release(i8* %y) 150 ; CHECK: @objc_release(i8* %x) 151 ; CHECK: ret void 152 ; CHECK: } 153 define void @test1e(i8* %x) { 154 entry: 155 br i1 undef, label %use_allocaA, label %use_allocaB 156 157 use_allocaA: 158 %allocaA = alloca i8*, i32 4 159 br label %exit 160 161 use_allocaB: 162 %allocaB = alloca i8*, i32 4 163 br label %exit 164 165 exit: 166 %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ] 167 %gep = getelementptr i8** %A, i32 2 168 tail call i8* @objc_retain(i8* %x) 169 tail call i8* @objc_retain(i8* %x) 170 store i8* %x, i8** %gep, align 8 171 %y = load i8** %gep 172 call void @use_alloca(i8** %A) 173 call void @objc_release(i8* %y), !clang.imprecise_release !0 174 call void @use_pointer(i8* %x) 175 call void @objc_release(i8* %x), !clang.imprecise_release !0 176 ret void 177 } 178 179 ; CHECK: define void @test1f(i8* %x) 180 ; CHECK: @objc_retain(i8* %x) 181 ; CHECK: @objc_retain(i8* %x) 182 ; CHECK: @objc_release(i8* %y) 183 ; CHECK: @objc_release(i8* %x) 184 ; CHECK: ret void 185 ; CHECK: } 186 define void @test1f(i8* %x) { 187 entry: 188 %allocaOne = alloca i8* 189 %allocaTwo = alloca i8* 190 %A = select i1 undef, i8** %allocaOne, i8** %allocaTwo 191 tail call i8* @objc_retain(i8* %x) 192 tail call i8* @objc_retain(i8* %x) 193 store i8* %x, i8** %A, align 8 194 %y = load i8** %A 195 call void @use_alloca(i8** %A) 196 call void @objc_release(i8* %y), !clang.imprecise_release !0 197 call void @use_pointer(i8* %x) 198 call void @objc_release(i8* %x), !clang.imprecise_release !0 199 ret void 200 } 201 202 ; Make sure that if a store is in a different basic block we handle known safe 203 ; conservatively. 204 205 206 ; CHECK: define void @test2a(i8* %x) 207 ; CHECK: @objc_retain(i8* %x) 208 ; CHECK: @objc_retain(i8* %x) 209 ; CHECK: @objc_release(i8* %y) 210 ; CHECK: @objc_release(i8* %x) 211 ; CHECK: ret void 212 ; CHECK: } 213 define void @test2a(i8* %x) { 214 entry: 215 %A = alloca i8* 216 store i8* %x, i8** %A, align 8 217 %y = load i8** %A 218 br label %bb1 219 220 bb1: 221 br label %bb2 222 223 bb2: 224 br label %bb3 225 226 bb3: 227 tail call i8* @objc_retain(i8* %x) 228 tail call i8* @objc_retain(i8* %x) 229 call void @use_alloca(i8** %A) 230 call void @objc_release(i8* %y), !clang.imprecise_release !0 231 call void @use_pointer(i8* %x) 232 call void @objc_release(i8* %x), !clang.imprecise_release !0 233 ret void 234 } 235 236 ; CHECK: define void @test2b(i8* %x) 237 ; CHECK: @objc_retain(i8* %x) 238 ; CHECK: @objc_retain(i8* %x) 239 ; CHECK: @objc_release(i8* %y) 240 ; CHECK: @objc_release(i8* %x) 241 ; CHECK: ret void 242 ; CHECK: } 243 define void @test2b(i8* %x) { 244 entry: 245 %A = alloca i8* 246 %gep1 = getelementptr i8** %A, i32 0 247 store i8* %x, i8** %gep1, align 8 248 %gep2 = getelementptr i8** %A, i32 0 249 %y = load i8** %gep2 250 br label %bb1 251 252 bb1: 253 br label %bb2 254 255 bb2: 256 br label %bb3 257 258 bb3: 259 tail call i8* @objc_retain(i8* %x) 260 tail call i8* @objc_retain(i8* %x) 261 call void @use_alloca(i8** %A) 262 call void @objc_release(i8* %y), !clang.imprecise_release !0 263 call void @use_pointer(i8* %x) 264 call void @objc_release(i8* %x), !clang.imprecise_release !0 265 ret void 266 } 267 268 ; CHECK: define void @test2c(i8* %x) 269 ; CHECK: @objc_retain(i8* %x) 270 ; CHECK: @objc_retain(i8* %x) 271 ; CHECK: @objc_release(i8* %y) 272 ; CHECK: @objc_release(i8* %x) 273 ; CHECK: ret void 274 ; CHECK: } 275 define void @test2c(i8* %x) { 276 entry: 277 %A = alloca i8*, i32 3 278 %gep1 = getelementptr i8** %A, i32 2 279 store i8* %x, i8** %gep1, align 8 280 %gep2 = getelementptr i8** %A, i32 2 281 %y = load i8** %gep2 282 tail call i8* @objc_retain(i8* %x) 283 br label %bb1 284 285 bb1: 286 br label %bb2 287 288 bb2: 289 br label %bb3 290 291 bb3: 292 tail call i8* @objc_retain(i8* %x) 293 call void @use_alloca(i8** %A) 294 call void @objc_release(i8* %y), !clang.imprecise_release !0 295 call void @use_pointer(i8* %x) 296 call void @objc_release(i8* %x), !clang.imprecise_release !0 297 ret void 298 } 299 300 ; CHECK: define void @test2d(i8* %x) 301 ; CHECK: @objc_retain(i8* %x) 302 ; CHECK: @objc_retain(i8* %x) 303 ; CHECK: @objc_release(i8* %y) 304 ; CHECK: @objc_release(i8* %x) 305 ; CHECK: ret void 306 ; CHECK: } 307 define void @test2d(i8* %x) { 308 entry: 309 tail call i8* @objc_retain(i8* %x) 310 br label %bb1 311 312 bb1: 313 %Abb1 = alloca i8*, i32 3 314 %gepbb11 = getelementptr i8** %Abb1, i32 2 315 store i8* %x, i8** %gepbb11, align 8 316 %gepbb12 = getelementptr i8** %Abb1, i32 2 317 %ybb1 = load i8** %gepbb12 318 br label %bb3 319 320 bb2: 321 %Abb2 = alloca i8*, i32 4 322 %gepbb21 = getelementptr i8** %Abb2, i32 2 323 store i8* %x, i8** %gepbb21, align 8 324 %gepbb22 = getelementptr i8** %Abb2, i32 2 325 %ybb2 = load i8** %gepbb22 326 br label %bb3 327 328 bb3: 329 %A = phi i8** [ %Abb1, %bb1 ], [ %Abb2, %bb2 ] 330 %y = phi i8* [ %ybb1, %bb1 ], [ %ybb2, %bb2 ] 331 tail call i8* @objc_retain(i8* %x) 332 call void @use_alloca(i8** %A) 333 call void @objc_release(i8* %y), !clang.imprecise_release !0 334 call void @use_pointer(i8* %x) 335 call void @objc_release(i8* %x), !clang.imprecise_release !0 336 ret void 337 } 338 339 ; Make sure in the presence of allocas, if we find a cfghazard we do not perform 340 ; code motion even if we are known safe. These two concepts are separate and 341 ; should be treated as such. 342 ; 343 ; rdar://13949644 344 345 ; CHECK: define void @test3a() { 346 ; CHECK: entry: 347 ; CHECK: @objc_retainAutoreleasedReturnValue 348 ; CHECK: @objc_retain 349 ; CHECK: @objc_retain 350 ; CHECK: @objc_retain 351 ; CHECK: @objc_retain 352 ; CHECK: arraydestroy.body: 353 ; CHECK: @objc_release 354 ; CHECK-NOT: @objc_release 355 ; CHECK: arraydestroy.done: 356 ; CHECK-NOT: @objc_release 357 ; CHECK: arraydestroy.body1: 358 ; CHECK: @objc_release 359 ; CHECK-NOT: @objc_release 360 ; CHECK: arraydestroy.done1: 361 ; CHECK: @objc_release 362 ; CHECK: ret void 363 ; CHECK: } 364 define void @test3a() { 365 entry: 366 %keys = alloca [2 x i8*], align 16 367 %objs = alloca [2 x i8*], align 16 368 369 %call1 = call i8* @returner() 370 %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call1) 371 372 %objs.begin = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0 373 tail call i8* @objc_retain(i8* %call1) 374 store i8* %call1, i8** %objs.begin, align 8 375 %objs.elt = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 1 376 tail call i8* @objc_retain(i8* %call1) 377 store i8* %call1, i8** %objs.elt 378 379 %call2 = call i8* @returner1() 380 %call3 = call i8* @returner2() 381 %keys.begin = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0 382 tail call i8* @objc_retain(i8* %call2) 383 store i8* %call2, i8** %keys.begin, align 8 384 %keys.elt = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 1 385 tail call i8* @objc_retain(i8* %call3) 386 store i8* %call3, i8** %keys.elt 387 388 %gep = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 2 389 br label %arraydestroy.body 390 391 arraydestroy.body: 392 %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ] 393 %arraydestroy.element = getelementptr inbounds i8** %arraydestroy.elementPast, i64 -1 394 %destroy_tmp = load i8** %arraydestroy.element, align 8 395 call void @objc_release(i8* %destroy_tmp), !clang.imprecise_release !0 396 %objs_ptr = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0 397 %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr 398 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body 399 400 arraydestroy.done: 401 %gep1 = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 2 402 br label %arraydestroy.body1 403 404 arraydestroy.body1: 405 %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ] 406 %arraydestroy.element1 = getelementptr inbounds i8** %arraydestroy.elementPast1, i64 -1 407 %destroy_tmp1 = load i8** %arraydestroy.element1, align 8 408 call void @objc_release(i8* %destroy_tmp1), !clang.imprecise_release !0 409 %keys_ptr = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0 410 %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr 411 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1 412 413 arraydestroy.done1: 414 call void @objc_release(i8* %call1), !clang.imprecise_release !0 415 ret void 416 } 417 418 ; Make sure that even though we stop said code motion we still allow for 419 ; pointers to be removed if we are known safe in both directions. 420 ; 421 ; rdar://13949644 422 423 ; CHECK: define void @test3b() { 424 ; CHECK: entry: 425 ; CHECK: @objc_retainAutoreleasedReturnValue 426 ; CHECK: @objc_retain 427 ; CHECK: @objc_retain 428 ; CHECK: @objc_retain 429 ; CHECK: @objc_retain 430 ; CHECK: arraydestroy.body: 431 ; CHECK: @objc_release 432 ; CHECK-NOT: @objc_release 433 ; CHECK: arraydestroy.done: 434 ; CHECK-NOT: @objc_release 435 ; CHECK: arraydestroy.body1: 436 ; CHECK: @objc_release 437 ; CHECK-NOT: @objc_release 438 ; CHECK: arraydestroy.done1: 439 ; CHECK: @objc_release 440 ; CHECK: ret void 441 ; CHECK: } 442 define void @test3b() { 443 entry: 444 %keys = alloca [2 x i8*], align 16 445 %objs = alloca [2 x i8*], align 16 446 447 %call1 = call i8* @returner() 448 %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call1) 449 %tmp1 = tail call i8* @objc_retain(i8* %call1) 450 451 %objs.begin = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0 452 tail call i8* @objc_retain(i8* %call1) 453 store i8* %call1, i8** %objs.begin, align 8 454 %objs.elt = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 1 455 tail call i8* @objc_retain(i8* %call1) 456 store i8* %call1, i8** %objs.elt 457 458 %call2 = call i8* @returner1() 459 %call3 = call i8* @returner2() 460 %keys.begin = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0 461 tail call i8* @objc_retain(i8* %call2) 462 store i8* %call2, i8** %keys.begin, align 8 463 %keys.elt = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 1 464 tail call i8* @objc_retain(i8* %call3) 465 store i8* %call3, i8** %keys.elt 466 467 %gep = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 2 468 br label %arraydestroy.body 469 470 arraydestroy.body: 471 %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ] 472 %arraydestroy.element = getelementptr inbounds i8** %arraydestroy.elementPast, i64 -1 473 %destroy_tmp = load i8** %arraydestroy.element, align 8 474 call void @objc_release(i8* %destroy_tmp), !clang.imprecise_release !0 475 %objs_ptr = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0 476 %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr 477 br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body 478 479 arraydestroy.done: 480 %gep1 = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 2 481 br label %arraydestroy.body1 482 483 arraydestroy.body1: 484 %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ] 485 %arraydestroy.element1 = getelementptr inbounds i8** %arraydestroy.elementPast1, i64 -1 486 %destroy_tmp1 = load i8** %arraydestroy.element1, align 8 487 call void @objc_release(i8* %destroy_tmp1), !clang.imprecise_release !0 488 %keys_ptr = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0 489 %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr 490 br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1 491 492 arraydestroy.done1: 493 call void @objc_release(i8* %call1), !clang.imprecise_release !0 494 call void @objc_release(i8* %call1), !clang.imprecise_release !0 495 ret void 496 } 497 498 !0 = metadata !{} 499 500 declare i32 @__gxx_personality_v0(...) 501