1; RUN: opt -aa-pipeline=basic-aa -passes=objc-arc -S < %s | FileCheck %s 2 3target datalayout = "e-p:64:64:64" 4 5declare ptr @llvm.objc.retain(ptr) 6declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr) 7declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr) 8declare void @llvm.objc.release(ptr) 9declare ptr @llvm.objc.autorelease(ptr) 10declare ptr @llvm.objc.autoreleaseReturnValue(ptr) 11declare void @llvm.objc.autoreleasePoolPop(ptr) 12declare ptr @llvm.objc.autoreleasePoolPush() 13declare ptr @llvm.objc.retainBlock(ptr) 14 15declare ptr @llvm.objc.retainedObject(ptr) 16declare ptr @llvm.objc.unretainedObject(ptr) 17declare ptr @llvm.objc.unretainedPointer(ptr) 18 19declare void @use_pointer(ptr) 20declare void @callee() 21declare void @callee2(ptr, ptr) 22declare void @callee_fnptr(ptr) 23declare void @invokee() 24declare ptr @returner() 25declare void @bar(ptr) 26 27declare void @llvm.dbg.value(metadata, metadata, metadata) 28 29declare ptr @objc_msgSend(ptr, ptr, ...) 30 31; Simple retain+release pair deletion, with some intervening control 32; flow and harmless instructions. 33 34; CHECK: define void @test0_precise(ptr %x, i1 %p) [[NUW:#[0-9]+]] { 35; CHECK: @llvm.objc.retain 36; CHECK: @llvm.objc.release 37; CHECK: {{^}}} 38define void @test0_precise(ptr %x, i1 %p) nounwind { 39entry: 40 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 41 br i1 %p, label %t, label %f 42 43t: 44 store i8 3, ptr %x 45 store float 2.0, ptr %x 46 br label %return 47 48f: 49 store i32 7, ptr %x 50 br label %return 51 52return: 53 call void @llvm.objc.release(ptr %x) nounwind 54 ret void 55} 56 57; CHECK: define void @test0_imprecise(ptr %x, i1 %p) [[NUW]] { 58; CHECK-NOT: @llvm.objc. 59; CHECK: {{^}}} 60define void @test0_imprecise(ptr %x, i1 %p) nounwind { 61entry: 62 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 63 br i1 %p, label %t, label %f 64 65t: 66 store i8 3, ptr %x 67 store float 2.0, ptr %x 68 br label %return 69 70f: 71 store i32 7, ptr %x 72 br label %return 73 74return: 75 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 76 ret void 77} 78 79; Like test0 but the release isn't always executed when the retain is, 80; so the optimization is not safe. 81 82; TODO: Make the llvm.objc.release's argument be %0. 83 84; CHECK: define void @test1_precise(ptr %x, i1 %p, i1 %q) [[NUW]] { 85; CHECK: @llvm.objc.retain(ptr %x) 86; CHECK: @llvm.objc.release(ptr %x) 87; CHECK: {{^}}} 88define void @test1_precise(ptr %x, i1 %p, i1 %q) nounwind { 89entry: 90 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 91 br i1 %p, label %t, label %f 92 93t: 94 store i8 3, ptr %x 95 store float 2.0, ptr %x 96 br label %return 97 98f: 99 store i32 7, ptr %x 100 call void @callee() 101 br i1 %q, label %return, label %alt_return 102 103return: 104 call void @llvm.objc.release(ptr %x) nounwind 105 ret void 106 107alt_return: 108 ret void 109} 110 111; CHECK: define void @test1_imprecise(ptr %x, i1 %p, i1 %q) [[NUW]] { 112; CHECK: @llvm.objc.retain(ptr %x) 113; CHECK: @llvm.objc.release 114; CHECK: {{^}}} 115define void @test1_imprecise(ptr %x, i1 %p, i1 %q) nounwind { 116entry: 117 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 118 br i1 %p, label %t, label %f 119 120t: 121 store i8 3, ptr %x 122 store float 2.0, ptr %x 123 br label %return 124 125f: 126 store i32 7, ptr %x 127 call void @callee() 128 br i1 %q, label %return, label %alt_return 129 130return: 131 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 132 ret void 133 134alt_return: 135 ret void 136} 137 138 139; Don't do partial elimination into two different CFG diamonds. 140 141; CHECK: define void @test1b_precise(ptr %x, i1 %p, i1 %q) { 142; CHECK: entry: 143; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 144; CHECK-NOT: @llvm.objc. 145; CHECK: if.end5: 146; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]] 147; CHECK-NOT: @llvm.objc. 148; CHECK: {{^}}} 149define void @test1b_precise(ptr %x, i1 %p, i1 %q) { 150entry: 151 tail call ptr @llvm.objc.retain(ptr %x) nounwind 152 br i1 %p, label %if.then, label %if.end 153 154if.then: ; preds = %entry 155 tail call void @callee() 156 br label %if.end 157 158if.end: ; preds = %if.then, %entry 159 br i1 %q, label %if.then3, label %if.end5 160 161if.then3: ; preds = %if.end 162 tail call void @use_pointer(ptr %x) 163 br label %if.end5 164 165if.end5: ; preds = %if.then3, %if.end 166 tail call void @llvm.objc.release(ptr %x) nounwind 167 ret void 168} 169 170; CHECK-LABEL: define void @test1b_imprecise( 171; CHECK: entry: 172; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW:#[0-9]+]] 173; CHECK-NOT: @llvm.objc. 174; CHECK: if.end5: 175; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE:[0-9]+]] 176; CHECK-NOT: @llvm.objc. 177; CHECK: {{^}}} 178define void @test1b_imprecise(ptr %x, i1 %p, i1 %q) { 179entry: 180 tail call ptr @llvm.objc.retain(ptr %x) nounwind 181 br i1 %p, label %if.then, label %if.end 182 183if.then: ; preds = %entry 184 tail call void @callee() 185 br label %if.end 186 187if.end: ; preds = %if.then, %entry 188 br i1 %q, label %if.then3, label %if.end5 189 190if.then3: ; preds = %if.end 191 tail call void @use_pointer(ptr %x) 192 br label %if.end5 193 194if.end5: ; preds = %if.then3, %if.end 195 tail call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 196 ret void 197} 198 199 200; Like test0 but the pointer is passed to an intervening call, 201; so the optimization is not safe. 202 203; CHECK-LABEL: define void @test2_precise( 204; CHECK: @llvm.objc.retain(ptr %x) 205; CHECK: @llvm.objc.release 206; CHECK: {{^}}} 207define void @test2_precise(ptr %x, i1 %p) nounwind { 208entry: 209 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 210 br i1 %p, label %t, label %f 211 212t: 213 store i8 3, ptr %x 214 store float 2.0, ptr %x 215 br label %return 216 217f: 218 store i32 7, ptr %x 219 call void @use_pointer(ptr %0) 220 store float 3.0, ptr %x 221 br label %return 222 223return: 224 call void @llvm.objc.release(ptr %x) nounwind 225 ret void 226} 227 228; CHECK-LABEL: define void @test2_imprecise( 229; CHECK: @llvm.objc.retain(ptr %x) 230; CHECK: @llvm.objc.release 231; CHECK: {{^}}} 232define void @test2_imprecise(ptr %x, i1 %p) nounwind { 233entry: 234 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 235 br i1 %p, label %t, label %f 236 237t: 238 store i8 3, ptr %x 239 store float 2.0, ptr %x 240 br label %return 241 242f: 243 store i32 7, ptr %x 244 call void @use_pointer(ptr %0) 245 store float 3.0, ptr %x 246 br label %return 247 248return: 249 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 250 ret void 251} 252 253; Like test0 but the release is in a loop, 254; so the optimization is not safe. 255 256; TODO: For now, assume this can't happen. 257 258; CHECK-LABEL: define void @test3_precise( 259; TODO: @llvm.objc.retain(ptr %a) 260; TODO: @llvm.objc.release 261; CHECK: {{^}}} 262define void @test3_precise(ptr %x, ptr %q) nounwind { 263entry: 264 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 265 br label %loop 266 267loop: 268 call void @llvm.objc.release(ptr %x) nounwind 269 %j = load volatile i1, ptr %q 270 br i1 %j, label %loop, label %return 271 272return: 273 ret void 274} 275 276; CHECK-LABEL: define void @test3_imprecise( 277; TODO: @llvm.objc.retain(ptr %a) 278; TODO: @llvm.objc.release 279; CHECK: {{^}}} 280define void @test3_imprecise(ptr %x, ptr %q) nounwind { 281entry: 282 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 283 br label %loop 284 285loop: 286 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 287 %j = load volatile i1, ptr %q 288 br i1 %j, label %loop, label %return 289 290return: 291 ret void 292} 293 294 295; TODO: For now, assume this can't happen. 296 297; Like test0 but the retain is in a loop, 298; so the optimization is not safe. 299 300; CHECK-LABEL: define void @test4_precise( 301; TODO: @llvm.objc.retain(ptr %a) 302; TODO: @llvm.objc.release 303; CHECK: {{^}}} 304define void @test4_precise(ptr %x, ptr %q) nounwind { 305entry: 306 br label %loop 307 308loop: 309 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 310 %j = load volatile i1, ptr %q 311 br i1 %j, label %loop, label %return 312 313return: 314 call void @llvm.objc.release(ptr %x) nounwind 315 ret void 316} 317 318; CHECK-LABEL: define void @test4_imprecise( 319; TODO: @llvm.objc.retain(ptr %a) 320; TODO: @llvm.objc.release 321; CHECK: {{^}}} 322define void @test4_imprecise(ptr %x, ptr %q) nounwind { 323entry: 324 br label %loop 325 326loop: 327 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 328 %j = load volatile i1, ptr %q 329 br i1 %j, label %loop, label %return 330 331return: 332 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 333 ret void 334} 335 336 337; Like test0 but the pointer is conditionally passed to an intervening call, 338; so the optimization is not safe. 339 340; CHECK-LABEL: define void @test5a( 341; CHECK: @llvm.objc.retain(ptr 342; CHECK: @llvm.objc.release 343; CHECK: {{^}}} 344define void @test5a(ptr %x, i1 %q, ptr %y) nounwind { 345entry: 346 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 347 %s = select i1 %q, ptr %y, ptr %0 348 call void @use_pointer(ptr %s) 349 store i32 7, ptr %x 350 call void @llvm.objc.release(ptr %x) nounwind 351 ret void 352} 353 354; CHECK-LABEL: define void @test5b( 355; CHECK: @llvm.objc.retain(ptr 356; CHECK: @llvm.objc.release 357; CHECK: {{^}}} 358define void @test5b(ptr %x, i1 %q, ptr %y) nounwind { 359entry: 360 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 361 %s = select i1 %q, ptr %y, ptr %0 362 call void @use_pointer(ptr %s) 363 store i32 7, ptr %x 364 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 365 ret void 366} 367 368 369; retain+release pair deletion, where the release happens on two different 370; flow paths. 371 372; CHECK-LABEL: define void @test6a( 373; CHECK: entry: 374; CHECK: tail call ptr @llvm.objc.retain 375; CHECK: t: 376; CHECK: call void @llvm.objc.release 377; CHECK: f: 378; CHECK: call void @llvm.objc.release 379; CHECK: return: 380; CHECK: {{^}}} 381define void @test6a(ptr %x, i1 %p) nounwind { 382entry: 383 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 384 br i1 %p, label %t, label %f 385 386t: 387 store i8 3, ptr %x 388 store float 2.0, ptr %x 389 call void @llvm.objc.release(ptr %x) nounwind 390 br label %return 391 392f: 393 store i32 7, ptr %x 394 call void @callee() 395 call void @llvm.objc.release(ptr %x) nounwind 396 br label %return 397 398return: 399 ret void 400} 401 402; CHECK-LABEL: define void @test6b( 403; CHECK-NOT: @llvm.objc. 404; CHECK: {{^}}} 405define void @test6b(ptr %x, i1 %p) nounwind { 406entry: 407 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 408 br i1 %p, label %t, label %f 409 410t: 411 store i8 3, ptr %x 412 store float 2.0, ptr %x 413 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 414 br label %return 415 416f: 417 store i32 7, ptr %x 418 call void @callee() 419 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 420 br label %return 421 422return: 423 ret void 424} 425 426; CHECK-LABEL: define void @test6c( 427; CHECK: entry: 428; CHECK: tail call ptr @llvm.objc.retain 429; CHECK: t: 430; CHECK: call void @llvm.objc.release 431; CHECK: f: 432; CHECK: call void @llvm.objc.release 433; CHECK: return: 434; CHECK: {{^}}} 435define void @test6c(ptr %x, i1 %p) nounwind { 436entry: 437 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 438 br i1 %p, label %t, label %f 439 440t: 441 store i8 3, ptr %x 442 store float 2.0, ptr %x 443 call void @llvm.objc.release(ptr %x) nounwind 444 br label %return 445 446f: 447 store i32 7, ptr %x 448 call void @callee() 449 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 450 br label %return 451 452return: 453 ret void 454} 455 456; CHECK-LABEL: define void @test6d( 457; CHECK: entry: 458; CHECK: tail call ptr @llvm.objc.retain 459; CHECK: t: 460; CHECK: call void @llvm.objc.release 461; CHECK: f: 462; CHECK: call void @llvm.objc.release 463; CHECK: return: 464; CHECK: {{^}}} 465define void @test6d(ptr %x, i1 %p) nounwind { 466entry: 467 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 468 br i1 %p, label %t, label %f 469 470t: 471 store i8 3, ptr %x 472 store float 2.0, ptr %x 473 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 474 br label %return 475 476f: 477 store i32 7, ptr %x 478 call void @callee() 479 call void @llvm.objc.release(ptr %x) nounwind 480 br label %return 481 482return: 483 ret void 484} 485 486 487; retain+release pair deletion, where the retain happens on two different 488; flow paths. 489 490; CHECK-LABEL: define void @test7( 491; CHECK: entry: 492; CHECK-NOT: llvm.objc. 493; CHECK: t: 494; CHECK: call ptr @llvm.objc.retain 495; CHECK: f: 496; CHECK: call ptr @llvm.objc.retain 497; CHECK: return: 498; CHECK: call void @llvm.objc.release 499; CHECK: {{^}}} 500define void @test7(ptr %x, i1 %p) nounwind { 501entry: 502 br i1 %p, label %t, label %f 503 504t: 505 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 506 store i8 3, ptr %x 507 store float 2.0, ptr %x 508 br label %return 509 510f: 511 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 512 store i32 7, ptr %x 513 call void @callee() 514 br label %return 515 516return: 517 call void @llvm.objc.release(ptr %x) nounwind 518 ret void 519} 520 521; CHECK-LABEL: define void @test7b( 522; CHECK-NOT: @llvm.objc. 523; CHECK: {{^}}} 524define void @test7b(ptr %x, i1 %p) nounwind { 525entry: 526 br i1 %p, label %t, label %f 527 528t: 529 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 530 store i8 3, ptr %x 531 store float 2.0, ptr %x 532 br label %return 533 534f: 535 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 536 store i32 7, ptr %x 537 call void @callee() 538 br label %return 539 540return: 541 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 542 ret void 543} 544 545; Like test7, but there's a retain/retainBlock mismatch. Don't delete! 546 547; CHECK-LABEL: define void @test7c( 548; CHECK: t: 549; CHECK: call ptr @llvm.objc.retainBlock 550; CHECK: f: 551; CHECK: call ptr @llvm.objc.retain 552; CHECK: return: 553; CHECK: call void @llvm.objc.release 554; CHECK: {{^}}} 555define void @test7c(ptr %x, i1 %p) nounwind { 556entry: 557 br i1 %p, label %t, label %f 558 559t: 560 %0 = call ptr @llvm.objc.retainBlock(ptr %x) nounwind 561 store i8 3, ptr %x 562 store float 2.0, ptr %x 563 br label %return 564 565f: 566 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 567 store i32 7, ptr %x 568 call void @callee() 569 br label %return 570 571return: 572 call void @llvm.objc.release(ptr %x) nounwind 573 ret void 574} 575 576; retain+release pair deletion, where the retain and release both happen on 577; different flow paths. Wild! 578 579; CHECK-LABEL: define void @test8a( 580; CHECK: entry: 581; CHECK: t: 582; CHECK: @llvm.objc.retain 583; CHECK: f: 584; CHECK: @llvm.objc.retain 585; CHECK: mid: 586; CHECK: u: 587; CHECK: @llvm.objc.release 588; CHECK: g: 589; CHECK: @llvm.objc.release 590; CHECK: return: 591; CHECK: {{^}}} 592define void @test8a(ptr %x, i1 %p, i1 %q) nounwind { 593entry: 594 br i1 %p, label %t, label %f 595 596t: 597 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 598 store i8 3, ptr %x 599 store float 2.0, ptr %x 600 br label %mid 601 602f: 603 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 604 store i32 7, ptr %x 605 br label %mid 606 607mid: 608 br i1 %q, label %u, label %g 609 610u: 611 call void @callee() 612 call void @llvm.objc.release(ptr %x) nounwind 613 br label %return 614 615g: 616 call void @llvm.objc.release(ptr %x) nounwind 617 br label %return 618 619return: 620 ret void 621} 622 623; CHECK-LABEL: define void @test8b( 624; CHECK-NOT: @llvm.objc. 625; CHECK: {{^}}} 626define void @test8b(ptr %x, i1 %p, i1 %q) nounwind { 627entry: 628 br i1 %p, label %t, label %f 629 630t: 631 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 632 store i8 3, ptr %x 633 store float 2.0, ptr %x 634 br label %mid 635 636f: 637 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 638 store i32 7, ptr %x 639 br label %mid 640 641mid: 642 br i1 %q, label %u, label %g 643 644u: 645 call void @callee() 646 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 647 br label %return 648 649g: 650 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 651 br label %return 652 653return: 654 ret void 655} 656 657; CHECK-LABEL: define void @test8c( 658; CHECK: entry: 659; CHECK: t: 660; CHECK-NOT: @llvm.objc. 661; CHECK: f: 662; CHECK-NOT: @llvm.objc. 663; CHECK: mid: 664; CHECK: u: 665; CHECK: @llvm.objc.retain 666; CHECK: @llvm.objc.release 667; CHECK: g: 668; CHECK-NOT: @llvm.objc. 669; CHECK: return: 670; CHECK: {{^}}} 671define void @test8c(ptr %x, i1 %p, i1 %q) nounwind { 672entry: 673 br i1 %p, label %t, label %f 674 675t: 676 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 677 store i8 3, ptr %x 678 store float 2.0, ptr %x 679 br label %mid 680 681f: 682 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 683 store i32 7, ptr %x 684 br label %mid 685 686mid: 687 br i1 %q, label %u, label %g 688 689u: 690 call void @callee() 691 call void @llvm.objc.release(ptr %x) nounwind 692 br label %return 693 694g: 695 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 696 br label %return 697 698return: 699 ret void 700} 701 702; CHECK-LABEL: define void @test8d( 703; CHECK: entry: 704; CHECK: t: 705; CHECK: @llvm.objc.retain 706; CHECK: f: 707; CHECK: @llvm.objc.retain 708; CHECK: mid: 709; CHECK: u: 710; CHECK: @llvm.objc.release 711; CHECK: g: 712; CHECK: @llvm.objc.release 713; CHECK: return: 714; CHECK: {{^}}} 715define void @test8d(ptr %x, i1 %p, i1 %q) nounwind { 716entry: 717 br i1 %p, label %t, label %f 718 719t: 720 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 721 store i8 3, ptr %x 722 store float 2.0, ptr %x 723 br label %mid 724 725f: 726 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 727 store i32 7, ptr %x 728 br label %mid 729 730mid: 731 br i1 %q, label %u, label %g 732 733u: 734 call void @callee() 735 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 736 br label %return 737 738g: 739 call void @llvm.objc.release(ptr %x) nounwind 740 br label %return 741 742return: 743 ret void 744} 745 746; Trivial retain+release pair deletion. 747 748; CHECK-LABEL: define void @test9( 749; CHECK-NOT: @llvm.objc. 750; CHECK: {{^}}} 751define void @test9(ptr %x) nounwind { 752entry: 753 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 754 call void @llvm.objc.release(ptr %0) nounwind 755 ret void 756} 757 758; Retain+release pair, but on an unknown pointer relationship. Don't delete! 759 760; CHECK-LABEL: define void @test9b( 761; CHECK: @llvm.objc.retain(ptr %x) 762; CHECK: @llvm.objc.release(ptr %s) 763; CHECK: {{^}}} 764define void @test9b(ptr %x, i1 %j, ptr %p) nounwind { 765entry: 766 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 767 %s = select i1 %j, ptr %x, ptr %p 768 call void @llvm.objc.release(ptr %s) nounwind 769 ret void 770} 771 772; Trivial retain+release pair with intervening calls - don't delete! 773 774; CHECK-LABEL: define void @test10( 775; CHECK: @llvm.objc.retain(ptr %x) 776; CHECK: @callee 777; CHECK: @use_pointer 778; CHECK: @llvm.objc.release 779; CHECK: {{^}}} 780define void @test10(ptr %x) nounwind { 781entry: 782 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 783 call void @callee() 784 call void @use_pointer(ptr %x) 785 call void @llvm.objc.release(ptr %0) nounwind 786 ret void 787} 788 789; Trivial retain+autoreleaserelease pair. Don't delete! 790; Also, add a tail keyword, since llvm.objc.retain can never be passed 791; a stack argument. 792 793; CHECK-LABEL: define void @test11( 794; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 795; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]] 796; CHECK: {{^}}} 797define void @test11(ptr %x) nounwind { 798entry: 799 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 800 call ptr @llvm.objc.autorelease(ptr %0) nounwind 801 call void @use_pointer(ptr %x) 802 ret void 803} 804 805; Same as test11 but with no use_pointer call. Delete the pair! 806 807; CHECK-LABEL: define void @test11a( 808; CHECK: entry: 809; CHECK-NEXT: ret void 810; CHECK: {{^}}} 811define void @test11a(ptr %x) nounwind { 812entry: 813 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 814 call ptr @llvm.objc.autorelease(ptr %0) nounwind 815 ret void 816} 817 818; Same as test11 but the value is returned. Do not perform an RV optimization 819; since if the frontend emitted code for an __autoreleasing variable, we may 820; want it to be in the autorelease pool. 821 822; CHECK-LABEL: define ptr @test11b( 823; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 824; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]] 825; CHECK: {{^}}} 826define ptr @test11b(ptr %x) nounwind { 827entry: 828 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 829 call ptr @llvm.objc.autorelease(ptr %0) nounwind 830 ret ptr %x 831} 832 833; We can not delete this retain, release since we do not have a post-dominating 834; use of the release. 835 836; CHECK-LABEL: define void @test12( 837; CHECK-NEXT: entry: 838; CHECK-NEXT: @llvm.objc.retain(ptr %x) 839; CHECK-NEXT: @llvm.objc.retain 840; CHECK: @llvm.objc.release 841; CHECK: {{^}}} 842define void @test12(ptr %x, i64 %n) { 843entry: 844 call ptr @llvm.objc.retain(ptr %x) nounwind 845 call ptr @llvm.objc.retain(ptr %x) nounwind 846 call void @use_pointer(ptr %x) 847 call void @use_pointer(ptr %x) 848 call void @llvm.objc.release(ptr %x) nounwind 849 ret void 850} 851 852; Trivial retain,autorelease pair. Don't delete! 853 854; CHECK-LABEL: define void @test13( 855; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 856; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 857; CHECK: @use_pointer(ptr %x) 858; CHECK: call ptr @llvm.objc.autorelease(ptr %x) [[NUW]] 859; CHECK: {{^}}} 860define void @test13(ptr %x, i64 %n) { 861entry: 862 call ptr @llvm.objc.retain(ptr %x) nounwind 863 call ptr @llvm.objc.retain(ptr %x) nounwind 864 call void @use_pointer(ptr %x) 865 call ptr @llvm.objc.autorelease(ptr %x) nounwind 866 ret void 867} 868 869; Delete the retain+release pair. 870 871; CHECK-LABEL: define void @test13b( 872; CHECK-NEXT: entry: 873; CHECK-NEXT: @llvm.objc.retain(ptr %x) 874; CHECK-NEXT: @use_pointer 875; CHECK-NEXT: @use_pointer 876; CHECK-NEXT: @use_pointer 877; CHECK-NEXT: @llvm.objc.release 878; CHECK-NEXT: ret void 879; CHECK-NEXT: } 880define void @test13b(ptr %x, i64 %n) { 881entry: 882 call ptr @llvm.objc.retain(ptr %x) nounwind 883 call ptr @llvm.objc.retain(ptr %x) nounwind 884 call void @use_pointer(ptr %x) 885 call void @use_pointer(ptr %x) 886 call void @llvm.objc.release(ptr %x) nounwind 887 call void @use_pointer(ptr %x) 888 call void @llvm.objc.release(ptr %x) nounwind 889 ret void 890} 891 892; Don't delete the retain+release pair because there's an 893; autoreleasePoolPop in the way. 894 895; CHECK-LABEL: define void @test13c( 896; CHECK: @llvm.objc.retain(ptr %x) 897; CHECK: @llvm.objc.autoreleasePoolPop 898; CHECK: @llvm.objc.retain(ptr %x) 899; CHECK: @use_pointer 900; CHECK: @llvm.objc.release 901; CHECK: {{^}}} 902define void @test13c(ptr %x, i64 %n) { 903entry: 904 call ptr @llvm.objc.retain(ptr %x) nounwind 905 call void @llvm.objc.autoreleasePoolPop(ptr undef) 906 call ptr @llvm.objc.retain(ptr %x) nounwind 907 call void @use_pointer(ptr %x) 908 call void @use_pointer(ptr %x) 909 call void @llvm.objc.release(ptr %x) nounwind 910 ret void 911} 912 913; Like test13c, but there's an autoreleasePoolPush in the way, but that 914; doesn't matter. 915 916; CHECK-LABEL: define void @test13d( 917; CHECK-NEXT: entry: 918; CHECK-NEXT: @llvm.objc.retain(ptr %x) 919; CHECK-NEXT: @llvm.objc.autoreleasePoolPush 920; CHECK-NEXT: @use_pointer 921; CHECK-NEXT: @use_pointer 922; CHECK-NEXT: @use_pointer 923; CHECK-NEXT: @llvm.objc.release 924; CHECK-NEXT: ret void 925; CHECK-NEXT: } 926define void @test13d(ptr %x, i64 %n) { 927entry: 928 call ptr @llvm.objc.retain(ptr %x) nounwind 929 call ptr @llvm.objc.autoreleasePoolPush() 930 call ptr @llvm.objc.retain(ptr %x) nounwind 931 call void @use_pointer(ptr %x) 932 call void @use_pointer(ptr %x) 933 call void @llvm.objc.release(ptr %x) nounwind 934 call void @use_pointer(ptr %x) 935 call void @llvm.objc.release(ptr %x) nounwind 936 ret void 937} 938 939; Trivial retain,release pair with intervening call, and it's post-dominated by 940; another release. But it is not known safe in the top down direction. We can 941; not eliminate it. 942 943; CHECK-LABEL: define void @test14( 944; CHECK-NEXT: entry: 945; CHECK-NEXT: @llvm.objc.retain 946; CHECK-NEXT: @use_pointer 947; CHECK-NEXT: @use_pointer 948; CHECK-NEXT: @llvm.objc.release 949; CHECK-NEXT: @llvm.objc.release 950; CHECK-NEXT: ret void 951; CHECK-NEXT: } 952define void @test14(ptr %x, i64 %n) { 953entry: 954 call ptr @llvm.objc.retain(ptr %x) nounwind 955 call void @use_pointer(ptr %x) 956 call void @use_pointer(ptr %x) 957 call void @llvm.objc.release(ptr %x) nounwind 958 call void @llvm.objc.release(ptr %x) nounwind 959 ret void 960} 961 962; Trivial retain,autorelease pair with intervening call, but it's post-dominated 963; by another release. Don't delete anything. 964 965; CHECK-LABEL: define void @test15( 966; CHECK-NEXT: entry: 967; CHECK-NEXT: @llvm.objc.retain(ptr %x) 968; CHECK-NEXT: @use_pointer 969; CHECK-NEXT: @llvm.objc.autorelease(ptr %x) 970; CHECK-NEXT: @llvm.objc.release 971; CHECK-NEXT: ret void 972; CHECK-NEXT: } 973define void @test15(ptr %x, i64 %n) { 974entry: 975 call ptr @llvm.objc.retain(ptr %x) nounwind 976 call void @use_pointer(ptr %x) 977 call ptr @llvm.objc.autorelease(ptr %x) nounwind 978 call void @llvm.objc.release(ptr %x) nounwind 979 ret void 980} 981 982; Trivial retain,autorelease pair, post-dominated 983; by another release. Delete the retain and release. 984 985; CHECK-LABEL: define void @test15b( 986; CHECK-NEXT: entry: 987; CHECK-NEXT: @llvm.objc.retain 988; CHECK-NEXT: @llvm.objc.autorelease 989; CHECK-NEXT: @llvm.objc.release 990; CHECK-NEXT: ret void 991; CHECK-NEXT: } 992define void @test15b(ptr %x, i64 %n) { 993entry: 994 call ptr @llvm.objc.retain(ptr %x) nounwind 995 call ptr @llvm.objc.autorelease(ptr %x) nounwind 996 call void @llvm.objc.release(ptr %x) nounwind 997 ret void 998} 999 1000; CHECK-LABEL: define void @test15c( 1001; CHECK-NEXT: entry: 1002; CHECK-NEXT: @llvm.objc.autorelease 1003; CHECK-NEXT: ret void 1004; CHECK-NEXT: } 1005define void @test15c(ptr %x, i64 %n) { 1006entry: 1007 call ptr @llvm.objc.retain(ptr %x) nounwind 1008 call ptr @llvm.objc.autorelease(ptr %x) nounwind 1009 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1010 ret void 1011} 1012 1013; Retain+release pairs in diamonds, all dominated by a retain. 1014 1015; CHECK-LABEL: define void @test16a( 1016; CHECK: @llvm.objc.retain(ptr %x) 1017; CHECK-NOT: @objc 1018; CHECK: purple: 1019; CHECK: @use_pointer 1020; CHECK: @llvm.objc.release 1021; CHECK: {{^}}} 1022define void @test16a(i1 %a, i1 %b, ptr %x) { 1023entry: 1024 call ptr @llvm.objc.retain(ptr %x) nounwind 1025 br i1 %a, label %red, label %orange 1026 1027red: 1028 call ptr @llvm.objc.retain(ptr %x) nounwind 1029 br label %yellow 1030 1031orange: 1032 call ptr @llvm.objc.retain(ptr %x) nounwind 1033 br label %yellow 1034 1035yellow: 1036 call void @use_pointer(ptr %x) 1037 call void @use_pointer(ptr %x) 1038 br i1 %b, label %green, label %blue 1039 1040green: 1041 call void @llvm.objc.release(ptr %x) nounwind 1042 br label %purple 1043 1044blue: 1045 call void @llvm.objc.release(ptr %x) nounwind 1046 br label %purple 1047 1048purple: 1049 call void @use_pointer(ptr %x) 1050 call void @llvm.objc.release(ptr %x) nounwind 1051 ret void 1052} 1053 1054; CHECK-LABEL: define void @test16b( 1055; CHECK: @llvm.objc.retain(ptr %x) 1056; CHECK-NOT: @objc 1057; CHECK: purple: 1058; CHECK-NEXT: @use_pointer 1059; CHECK-NEXT: @use_pointer 1060; CHECK-NEXT: @llvm.objc.release 1061; CHECK: {{^}}} 1062define void @test16b(i1 %a, i1 %b, ptr %x) { 1063entry: 1064 call ptr @llvm.objc.retain(ptr %x) nounwind 1065 br i1 %a, label %red, label %orange 1066 1067red: 1068 call ptr @llvm.objc.retain(ptr %x) nounwind 1069 br label %yellow 1070 1071orange: 1072 call ptr @llvm.objc.retain(ptr %x) nounwind 1073 br label %yellow 1074 1075yellow: 1076 call void @use_pointer(ptr %x) 1077 call void @use_pointer(ptr %x) 1078 br i1 %b, label %green, label %blue 1079 1080green: 1081 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1082 br label %purple 1083 1084blue: 1085 call void @llvm.objc.release(ptr %x) nounwind 1086 br label %purple 1087 1088purple: 1089 call void @use_pointer(ptr %x) 1090 call void @use_pointer(ptr %x) 1091 call void @llvm.objc.release(ptr %x) nounwind 1092 ret void 1093} 1094 1095; CHECK-LABEL: define void @test16c( 1096; CHECK: @llvm.objc.retain(ptr %x) 1097; CHECK-NOT: @objc 1098; CHECK: purple: 1099; CHECK: @use_pointer 1100; CHECK: @llvm.objc.release 1101; CHECK: {{^}}} 1102define void @test16c(i1 %a, i1 %b, ptr %x) { 1103entry: 1104 call ptr @llvm.objc.retain(ptr %x) nounwind 1105 br i1 %a, label %red, label %orange 1106 1107red: 1108 call ptr @llvm.objc.retain(ptr %x) nounwind 1109 br label %yellow 1110 1111orange: 1112 call ptr @llvm.objc.retain(ptr %x) nounwind 1113 br label %yellow 1114 1115yellow: 1116 call void @use_pointer(ptr %x) 1117 call void @use_pointer(ptr %x) 1118 br i1 %b, label %green, label %blue 1119 1120green: 1121 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1122 br label %purple 1123 1124blue: 1125 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1126 br label %purple 1127 1128purple: 1129 call void @use_pointer(ptr %x) 1130 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1131 ret void 1132} 1133 1134; CHECK-LABEL: define void @test16d( 1135; CHECK: @llvm.objc.retain(ptr %x) 1136; CHECK: @llvm.objc 1137; CHECK: {{^}}} 1138define void @test16d(i1 %a, i1 %b, ptr %x) { 1139entry: 1140 call ptr @llvm.objc.retain(ptr %x) nounwind 1141 br i1 %a, label %red, label %orange 1142 1143red: 1144 call ptr @llvm.objc.retain(ptr %x) nounwind 1145 br label %yellow 1146 1147orange: 1148 call ptr @llvm.objc.retain(ptr %x) nounwind 1149 br label %yellow 1150 1151yellow: 1152 call void @use_pointer(ptr %x) 1153 call void @use_pointer(ptr %x) 1154 br i1 %b, label %green, label %blue 1155 1156green: 1157 call void @llvm.objc.release(ptr %x) nounwind 1158 br label %purple 1159 1160blue: 1161 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 1162 br label %purple 1163 1164purple: 1165 ret void 1166} 1167 1168; Delete no-ops. 1169 1170; CHECK-LABEL: define void @test18( 1171; CHECK-NOT: @llvm.objc. 1172; CHECK: {{^}}} 1173define void @test18() { 1174 call ptr @llvm.objc.retain(ptr null) 1175 call void @llvm.objc.release(ptr null) 1176 call ptr @llvm.objc.autorelease(ptr null) 1177 ret void 1178} 1179 1180; Delete no-ops where undef can be assumed to be null. 1181 1182; CHECK-LABEL: define void @test18b( 1183; CHECK-NOT: @llvm.objc. 1184; CHECK: {{^}}} 1185define void @test18b() { 1186 call ptr @llvm.objc.retain(ptr undef) 1187 call void @llvm.objc.release(ptr undef) 1188 call ptr @llvm.objc.autorelease(ptr undef) 1189 ret void 1190} 1191 1192; Replace uses of arguments with uses of return values, to reduce 1193; register pressure. 1194 1195; CHECK: define void @test19(ptr %y) { 1196; CHECK: %0 = tail call ptr @llvm.objc.retain(ptr %y) 1197; CHECK: call void @use_pointer(ptr %y) 1198; CHECK: call void @use_pointer(ptr %y) 1199; CHECK: call void @llvm.objc.release(ptr %y) 1200; CHECK: ret void 1201; CHECK: {{^}}} 1202define void @test19(ptr %y) { 1203entry: 1204 %0 = call ptr @llvm.objc.retain(ptr %y) nounwind 1205 call void @use_pointer(ptr %y) 1206 call void @use_pointer(ptr %y) 1207 call void @llvm.objc.release(ptr %y) 1208 ret void 1209} 1210 1211; Bitcast insertion 1212 1213; CHECK-LABEL: define void @test20( 1214; CHECK: %tmp1 = tail call ptr @llvm.objc.retain(ptr %self) [[NUW]] 1215; CHECK-NEXT: invoke 1216; CHECK: {{^}}} 1217define void @test20(ptr %self) personality ptr @__gxx_personality_v0 { 1218if.then12: 1219 %tmp1 = call ptr @llvm.objc.retain(ptr %self) nounwind 1220 invoke void @invokee() 1221 to label %invoke.cont23 unwind label %lpad20 1222 1223invoke.cont23: ; preds = %if.then12 1224 invoke void @invokee() 1225 to label %if.end unwind label %lpad20 1226 1227lpad20: ; preds = %invoke.cont23, %if.then12 1228 %tmp502 = phi ptr [ undef, %invoke.cont23 ], [ %self, %if.then12 ] 1229 %exn = landingpad {ptr, i32} 1230 cleanup 1231 unreachable 1232 1233if.end: ; preds = %invoke.cont23 1234 ret void 1235} 1236 1237; Delete a redundant retain,autorelease when forwaring a call result 1238; directly to a return value. 1239 1240; CHECK-LABEL: define ptr @test21( 1241; CHECK: call ptr @returner() 1242; CHECK-NEXT: ret ptr %call 1243; CHECK-NEXT: } 1244define ptr @test21() { 1245entry: 1246 %call = call ptr @returner() 1247 %0 = call ptr @llvm.objc.retain(ptr %call) nounwind 1248 %1 = call ptr @llvm.objc.autorelease(ptr %0) nounwind 1249 ret ptr %1 1250} 1251 1252; Move an objc call up through a phi that has null operands. 1253 1254; CHECK-LABEL: define void @test22( 1255; CHECK: B: 1256; CHECK: call void @llvm.objc.release(ptr %p) 1257; CHECK: br label %C 1258; CHECK: C: ; preds = %B, %A 1259; CHECK-NOT: @llvm.objc.release 1260; CHECK: {{^}}} 1261define void @test22(ptr %p, i1 %a) { 1262 br i1 %a, label %A, label %B 1263A: 1264 br label %C 1265B: 1266 br label %C 1267C: 1268 %h = phi ptr [ null, %A ], [ %p, %B ] 1269 call void @llvm.objc.release(ptr %h), !clang.imprecise_release !0 1270 ret void 1271} 1272 1273; Do not move an llvm.objc.release that doesn't have the clang.imprecise_release tag. 1274 1275; CHECK-LABEL: define void @test22_precise( 1276; CHECK: %[[P0:.*]] = phi ptr 1277; CHECK: call void @llvm.objc.release(ptr %[[P0]]) 1278; CHECK: ret void 1279define void @test22_precise(ptr %p, i1 %a) { 1280 br i1 %a, label %A, label %B 1281A: 1282 br label %C 1283B: 1284 br label %C 1285C: 1286 %h = phi ptr [ null, %A ], [ %p, %B ] 1287 call void @llvm.objc.release(ptr %h) 1288 ret void 1289} 1290 1291; Any call can decrement a retain count. 1292 1293; CHECK-LABEL: define void @test24( 1294; CHECK: @llvm.objc.retain(ptr %a) 1295; CHECK: @llvm.objc.release 1296; CHECK: {{^}}} 1297define void @test24(ptr %r, ptr %a) { 1298 call ptr @llvm.objc.retain(ptr %a) 1299 call void @use_pointer(ptr %r) 1300 %q = load i8, ptr %a 1301 call void @llvm.objc.release(ptr %a) 1302 ret void 1303} 1304 1305; Don't move a retain/release pair if the release can be moved 1306; but the retain can't be moved to balance it. 1307 1308; CHECK-LABEL: define void @test25( 1309; CHECK: entry: 1310; CHECK: call ptr @llvm.objc.retain(ptr %p) 1311; CHECK: true: 1312; CHECK: done: 1313; CHECK: call void @llvm.objc.release(ptr %p) 1314; CHECK: {{^}}} 1315define void @test25(ptr %p, i1 %x) { 1316entry: 1317 %f0 = call ptr @llvm.objc.retain(ptr %p) 1318 call void @callee() 1319 br i1 %x, label %true, label %done 1320 1321true: 1322 store i8 0, ptr %p 1323 br label %done 1324 1325done: 1326 call void @llvm.objc.release(ptr %p) 1327 ret void 1328} 1329 1330; Don't move a retain/release pair if the retain can be moved 1331; but the release can't be moved to balance it. 1332 1333; CHECK-LABEL: define void @test26( 1334; CHECK: entry: 1335; CHECK: call ptr @llvm.objc.retain(ptr %p) 1336; CHECK: true: 1337; CHECK: done: 1338; CHECK: call void @llvm.objc.release(ptr %p) 1339; CHECK: {{^}}} 1340define void @test26(ptr %p, i1 %x) { 1341entry: 1342 %f0 = call ptr @llvm.objc.retain(ptr %p) 1343 br i1 %x, label %true, label %done 1344 1345true: 1346 call void @callee() 1347 br label %done 1348 1349done: 1350 store i8 0, ptr %p 1351 call void @llvm.objc.release(ptr %p) 1352 ret void 1353} 1354 1355; Don't sink the retain,release into the loop. 1356 1357; CHECK-LABEL: define void @test27( 1358; CHECK: entry: 1359; CHECK: call ptr @llvm.objc.retain(ptr %p) 1360; CHECK: loop: 1361; CHECK-NOT: @llvm.objc. 1362; CHECK: done: 1363; CHECK: call void @llvm.objc.release 1364; CHECK: {{^}}} 1365define void @test27(ptr %p, i1 %x, i1 %y) { 1366entry: 1367 %f0 = call ptr @llvm.objc.retain(ptr %p) 1368 br i1 %x, label %loop, label %done 1369 1370loop: 1371 call void @callee() 1372 store i8 0, ptr %p 1373 br i1 %y, label %done, label %loop 1374 1375done: 1376 call void @llvm.objc.release(ptr %p) 1377 ret void 1378} 1379 1380; Trivial code motion case: Triangle. 1381 1382; CHECK-LABEL: define void @test28( 1383; CHECK-NOT: @llvm.objc. 1384; CHECK: true: 1385; CHECK: call ptr @llvm.objc.retain 1386; CHECK: call void @callee() 1387; CHECK: store 1388; CHECK: call void @llvm.objc.release 1389; CHECK: done: 1390; CHECK-NOT: @llvm.objc. 1391; CHECK: {{^}}} 1392define void @test28(ptr %p, i1 %x) { 1393entry: 1394 %f0 = call ptr @llvm.objc.retain(ptr %p) 1395 br i1 %x, label %true, label %done 1396 1397true: 1398 call void @callee() 1399 store i8 0, ptr %p 1400 br label %done 1401 1402done: 1403 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1404 ret void 1405} 1406 1407; Trivial code motion case: Triangle, but no metadata. Don't move past 1408; unrelated memory references! 1409 1410; CHECK-LABEL: define void @test28b( 1411; CHECK: call ptr @llvm.objc.retain 1412; CHECK: true: 1413; CHECK-NOT: @llvm.objc. 1414; CHECK: call void @callee() 1415; CHECK-NOT: @llvm.objc. 1416; CHECK: store 1417; CHECK-NOT: @llvm.objc. 1418; CHECK: done: 1419; CHECK: @llvm.objc.release 1420; CHECK: {{^}}} 1421define void @test28b(ptr %p, i1 %x, ptr noalias %t) { 1422entry: 1423 %f0 = call ptr @llvm.objc.retain(ptr %p) 1424 br i1 %x, label %true, label %done 1425 1426true: 1427 call void @callee() 1428 store i8 0, ptr %p 1429 br label %done 1430 1431done: 1432 store i8 0, ptr %t 1433 call void @llvm.objc.release(ptr %p) 1434 ret void 1435} 1436 1437; Trivial code motion case: Triangle, with metadata. Do move past 1438; unrelated memory references! And preserve the metadata. 1439 1440; CHECK-LABEL: define void @test28c( 1441; CHECK-NOT: @llvm.objc. 1442; CHECK: true: 1443; CHECK: call ptr @llvm.objc.retain 1444; CHECK: call void @callee() 1445; CHECK: store 1446; CHECK: call void @llvm.objc.release(ptr %p) [[NUW]], !clang.imprecise_release 1447; CHECK: done: 1448; CHECK-NOT: @llvm.objc. 1449; CHECK: {{^}}} 1450define void @test28c(ptr %p, i1 %x, ptr noalias %t) { 1451entry: 1452 %f0 = call ptr @llvm.objc.retain(ptr %p) 1453 br i1 %x, label %true, label %done 1454 1455true: 1456 call void @callee() 1457 store i8 0, ptr %p 1458 br label %done 1459 1460done: 1461 store i8 0, ptr %t 1462 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1463 ret void 1464} 1465 1466; Like test28. but with two releases. 1467 1468; CHECK-LABEL: define void @test29( 1469; CHECK: call ptr @llvm.objc.retain 1470; CHECK: true: 1471; CHECK: call void @callee() 1472; CHECK: store 1473; CHECK: done: 1474; CHECK: call void @llvm.objc.release 1475; CHECK: ohno: 1476; CHECK: call void @llvm.objc.release 1477; CHECK: {{^}}} 1478define void @test29(ptr %p, i1 %x, i1 %y) { 1479entry: 1480 %f0 = call ptr @llvm.objc.retain(ptr %p) 1481 br i1 %x, label %true, label %done 1482 1483true: 1484 call void @callee() 1485 store i8 0, ptr %p 1486 br i1 %y, label %done, label %ohno 1487 1488done: 1489 call void @llvm.objc.release(ptr %p) 1490 ret void 1491 1492ohno: 1493 call void @llvm.objc.release(ptr %p) 1494 ret void 1495} 1496 1497; Basic case with the use and call in a diamond 1498; with an extra release. 1499 1500; CHECK-LABEL: define void @test30( 1501; CHECK: call ptr @llvm.objc.retain 1502; CHECK: true: 1503; CHECK: call void @callee() 1504; CHECK: store 1505; CHECK: false: 1506; CHECK: done: 1507; CHECK: call void @llvm.objc.release 1508; CHECK: ohno: 1509; CHECK: call void @llvm.objc.release 1510; CHECK: {{^}}} 1511define void @test30(ptr %p, i1 %x, i1 %y, i1 %z) { 1512entry: 1513 %f0 = call ptr @llvm.objc.retain(ptr %p) 1514 br i1 %x, label %true, label %false 1515 1516true: 1517 call void @callee() 1518 store i8 0, ptr %p 1519 br i1 %y, label %done, label %ohno 1520 1521false: 1522 br i1 %z, label %done, label %ohno 1523 1524done: 1525 call void @llvm.objc.release(ptr %p) 1526 ret void 1527 1528ohno: 1529 call void @llvm.objc.release(ptr %p) 1530 ret void 1531} 1532 1533; Basic case with a mergeable release. 1534 1535; CHECK-LABEL: define void @test31( 1536; CHECK: call ptr @llvm.objc.retain(ptr %p) 1537; CHECK: call void @callee() 1538; CHECK: store 1539; CHECK: true: 1540; CHECK: call void @llvm.objc.release 1541; CHECK: false: 1542; CHECK: call void @llvm.objc.release 1543; CHECK: ret void 1544; CHECK: {{^}}} 1545define void @test31(ptr %p, i1 %x) { 1546entry: 1547 %f0 = call ptr @llvm.objc.retain(ptr %p) 1548 call void @callee() 1549 store i8 0, ptr %p 1550 br i1 %x, label %true, label %false 1551true: 1552 call void @llvm.objc.release(ptr %p) 1553 ret void 1554false: 1555 call void @llvm.objc.release(ptr %p) 1556 ret void 1557} 1558 1559; Don't consider bitcasts or getelementptrs direct uses. 1560 1561; CHECK-LABEL: define void @test32( 1562; CHECK: call ptr @llvm.objc.retain 1563; CHECK: true: 1564; CHECK: call void @callee() 1565; CHECK: store 1566; CHECK: done: 1567; CHECK: call void @llvm.objc.release 1568; CHECK: {{^}}} 1569define void @test32(ptr %p, i1 %x) { 1570entry: 1571 %f0 = call ptr @llvm.objc.retain(ptr %p) 1572 br i1 %x, label %true, label %done 1573 1574true: 1575 call void @callee() 1576 store i8 0, ptr %p 1577 br label %done 1578 1579done: 1580 call void @llvm.objc.release(ptr %p) 1581 ret void 1582} 1583 1584; Do consider icmps to be direct uses. 1585 1586; CHECK-LABEL: define void @test33( 1587; CHECK: call ptr @llvm.objc.retain 1588; CHECK: true: 1589; CHECK: call void @callee() 1590; CHECK: icmp 1591; CHECK: done: 1592; CHECK: call void @llvm.objc.release 1593; CHECK: {{^}}} 1594define void @test33(ptr %p, i1 %x, ptr %y) { 1595entry: 1596 %f0 = call ptr @llvm.objc.retain(ptr %p) 1597 br i1 %x, label %true, label %done 1598 1599true: 1600 call void @callee() 1601 %v = icmp eq ptr %p, %y 1602 br label %done 1603 1604done: 1605 call void @llvm.objc.release(ptr %p) 1606 ret void 1607} 1608 1609; Delete retain,release if there's just a possible dec and we have imprecise 1610; releases. 1611 1612; CHECK-LABEL: define void @test34a( 1613; CHECK: call ptr @llvm.objc.retain 1614; CHECK: true: 1615; CHECK: done: 1616; CHECK: call void @llvm.objc.release 1617; CHECK: {{^}}} 1618define void @test34a(ptr %p, i1 %x, ptr %y) { 1619entry: 1620 %f0 = call ptr @llvm.objc.retain(ptr %p) 1621 br i1 %x, label %true, label %done 1622 1623true: 1624 call void @callee() 1625 br label %done 1626 1627done: 1628 call void @llvm.objc.release(ptr %p) 1629 ret void 1630} 1631 1632; CHECK-LABEL: define void @test34b( 1633; CHECK-NOT: @llvm.objc. 1634; CHECK: {{^}}} 1635define void @test34b(ptr %p, i1 %x, ptr %y) { 1636entry: 1637 %f0 = call ptr @llvm.objc.retain(ptr %p) 1638 br i1 %x, label %true, label %done 1639 1640true: 1641 call void @callee() 1642 br label %done 1643 1644done: 1645 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1646 ret void 1647} 1648 1649 1650; Delete retain,release if there's just a use and we do not have a precise 1651; release. 1652 1653; Precise. 1654; CHECK-LABEL: define void @test35a( 1655; CHECK: entry: 1656; CHECK: call ptr @llvm.objc.retain 1657; CHECK: true: 1658; CHECK: done: 1659; CHECK: call void @llvm.objc.release 1660; CHECK: {{^}}} 1661define void @test35a(ptr %p, i1 %x, ptr %y) { 1662entry: 1663 %f0 = call ptr @llvm.objc.retain(ptr %p) 1664 br i1 %x, label %true, label %done 1665 1666true: 1667 %v = icmp eq ptr %p, %y 1668 br label %done 1669 1670done: 1671 call void @llvm.objc.release(ptr %p) 1672 ret void 1673} 1674 1675; Imprecise. 1676; CHECK-LABEL: define void @test35b( 1677; CHECK-NOT: @llvm.objc. 1678; CHECK: {{^}}} 1679define void @test35b(ptr %p, i1 %x, ptr %y) { 1680entry: 1681 %f0 = call ptr @llvm.objc.retain(ptr %p) 1682 br i1 %x, label %true, label %done 1683 1684true: 1685 %v = icmp eq ptr %p, %y 1686 br label %done 1687 1688done: 1689 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1690 ret void 1691} 1692 1693; Delete a retain,release if there's no actual use and we have precise release. 1694 1695; CHECK-LABEL: define void @test36a( 1696; CHECK: @llvm.objc.retain 1697; CHECK: call void @callee() 1698; CHECK-NOT: @llvm.objc. 1699; CHECK: call void @callee() 1700; CHECK: @llvm.objc.release 1701; CHECK: {{^}}} 1702define void @test36a(ptr %p) { 1703entry: 1704 call ptr @llvm.objc.retain(ptr %p) 1705 call void @callee() 1706 call void @callee() 1707 call void @llvm.objc.release(ptr %p) 1708 ret void 1709} 1710 1711; Like test36, but with metadata. 1712 1713; CHECK-LABEL: define void @test36b( 1714; CHECK-NOT: @llvm.objc. 1715; CHECK: {{^}}} 1716define void @test36b(ptr %p) { 1717entry: 1718 call ptr @llvm.objc.retain(ptr %p) 1719 call void @callee() 1720 call void @callee() 1721 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1722 ret void 1723} 1724 1725; Be aggressive about analyzing phis to eliminate possible uses. 1726 1727; CHECK-LABEL: define void @test38( 1728; CHECK-NOT: @llvm.objc. 1729; CHECK: {{^}}} 1730define void @test38(ptr %p, i1 %u, i1 %m, ptr %z, ptr %y, ptr %x, ptr %w) { 1731entry: 1732 call ptr @llvm.objc.retain(ptr %p) 1733 br i1 %u, label %true, label %false 1734true: 1735 br i1 %m, label %a, label %b 1736false: 1737 br i1 %m, label %c, label %d 1738a: 1739 br label %e 1740b: 1741 br label %e 1742c: 1743 br label %f 1744d: 1745 br label %f 1746e: 1747 %j = phi ptr [ %z, %a ], [ %y, %b ] 1748 br label %g 1749f: 1750 %k = phi ptr [ %w, %c ], [ %x, %d ] 1751 br label %g 1752g: 1753 %h = phi ptr [ %j, %e ], [ %k, %f ] 1754 call void @use_pointer(ptr %h) 1755 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 1756 ret void 1757} 1758 1759; Delete retain,release pairs around loops. 1760 1761; CHECK-LABEL: define void @test39( 1762; CHECK-NOT: @llvm.objc. 1763; CHECK: {{^}}} 1764define void @test39(ptr %p, i1 %arg) { 1765entry: 1766 %0 = call ptr @llvm.objc.retain(ptr %p) 1767 br label %loop 1768 1769loop: ; preds = %loop, %entry 1770 br i1 %arg, label %loop, label %exit 1771 1772exit: ; preds = %loop 1773 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !0 1774 ret void 1775} 1776 1777; Delete retain,release pairs around loops containing uses. 1778 1779; CHECK-LABEL: define void @test39b( 1780; CHECK-NOT: @llvm.objc. 1781; CHECK: {{^}}} 1782define void @test39b(ptr %p, i1 %arg) { 1783entry: 1784 %0 = call ptr @llvm.objc.retain(ptr %p) 1785 br label %loop 1786 1787loop: ; preds = %loop, %entry 1788 store i8 0, ptr %0 1789 br i1 %arg, label %loop, label %exit 1790 1791exit: ; preds = %loop 1792 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !0 1793 ret void 1794} 1795 1796; Delete retain,release pairs around loops containing potential decrements. 1797 1798; CHECK-LABEL: define void @test39c( 1799; CHECK-NOT: @llvm.objc. 1800; CHECK: {{^}}} 1801define void @test39c(ptr %p, i1 %arg) { 1802entry: 1803 %0 = call ptr @llvm.objc.retain(ptr %p) 1804 br label %loop 1805 1806loop: ; preds = %loop, %entry 1807 call void @use_pointer(ptr %0) 1808 br i1 %arg, label %loop, label %exit 1809 1810exit: ; preds = %loop 1811 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !0 1812 ret void 1813} 1814 1815; Delete retain,release pairs around loops even if 1816; the successors are in a different order. 1817 1818; CHECK-LABEL: define void @test40( 1819; CHECK-NOT: @llvm.objc. 1820; CHECK: {{^}}} 1821define void @test40(ptr %p, i1 %arg) { 1822entry: 1823 %0 = call ptr @llvm.objc.retain(ptr %p) 1824 br label %loop 1825 1826loop: ; preds = %loop, %entry 1827 call void @use_pointer(ptr %0) 1828 br i1 %arg, label %exit, label %loop 1829 1830exit: ; preds = %loop 1831 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !0 1832 ret void 1833} 1834 1835; Do the known-incremented retain+release elimination even if the pointer 1836; is also autoreleased. 1837 1838; CHECK-LABEL: define void @test42( 1839; CHECK-NEXT: entry: 1840; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p) 1841; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p) 1842; CHECK-NEXT: call void @use_pointer(ptr %p) 1843; CHECK-NEXT: call void @use_pointer(ptr %p) 1844; CHECK-NEXT: call void @use_pointer(ptr %p) 1845; CHECK-NEXT: call void @use_pointer(ptr %p) 1846; CHECK-NEXT: call void @llvm.objc.release(ptr %p) 1847; CHECK-NEXT: ret void 1848; CHECK-NEXT: } 1849define void @test42(ptr %p) { 1850entry: 1851 call ptr @llvm.objc.retain(ptr %p) 1852 call ptr @llvm.objc.autorelease(ptr %p) 1853 call ptr @llvm.objc.retain(ptr %p) 1854 call void @use_pointer(ptr %p) 1855 call void @use_pointer(ptr %p) 1856 call void @llvm.objc.release(ptr %p) 1857 call void @use_pointer(ptr %p) 1858 call void @use_pointer(ptr %p) 1859 call void @llvm.objc.release(ptr %p) 1860 ret void 1861} 1862 1863; Don't the known-incremented retain+release elimination if the pointer is 1864; autoreleased and there's an autoreleasePoolPop. 1865 1866; CHECK-LABEL: define void @test43( 1867; CHECK-NEXT: entry: 1868; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p) 1869; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p) 1870; CHECK-NEXT: call ptr @llvm.objc.retain 1871; CHECK-NEXT: call void @use_pointer(ptr %p) 1872; CHECK-NEXT: call void @use_pointer(ptr %p) 1873; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr undef) 1874; CHECK-NEXT: call void @llvm.objc.release 1875; CHECK-NEXT: ret void 1876; CHECK-NEXT: } 1877define void @test43(ptr %p) { 1878entry: 1879 call ptr @llvm.objc.retain(ptr %p) 1880 call ptr @llvm.objc.autorelease(ptr %p) 1881 call ptr @llvm.objc.retain(ptr %p) 1882 call void @use_pointer(ptr %p) 1883 call void @use_pointer(ptr %p) 1884 call void @llvm.objc.autoreleasePoolPop(ptr undef) 1885 call void @llvm.objc.release(ptr %p) 1886 ret void 1887} 1888 1889; Do the known-incremented retain+release elimination if the pointer is 1890; autoreleased and there's an autoreleasePoolPush. 1891 1892; CHECK-LABEL: define void @test43b( 1893; CHECK-NEXT: entry: 1894; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p) 1895; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p) 1896; CHECK-NEXT: call void @use_pointer(ptr %p) 1897; CHECK-NEXT: call void @use_pointer(ptr %p) 1898; CHECK-NEXT: call ptr @llvm.objc.autoreleasePoolPush() 1899; CHECK-NEXT: call void @use_pointer(ptr %p) 1900; CHECK-NEXT: call void @llvm.objc.release 1901; CHECK-NEXT: ret void 1902; CHECK-NEXT: } 1903define void @test43b(ptr %p) { 1904entry: 1905 call ptr @llvm.objc.retain(ptr %p) 1906 call ptr @llvm.objc.autorelease(ptr %p) 1907 call ptr @llvm.objc.retain(ptr %p) 1908 call void @use_pointer(ptr %p) 1909 call void @use_pointer(ptr %p) 1910 call ptr @llvm.objc.autoreleasePoolPush() 1911 call void @llvm.objc.release(ptr %p) 1912 call void @use_pointer(ptr %p) 1913 call void @llvm.objc.release(ptr %p) 1914 ret void 1915} 1916 1917; Do retain+release elimination for non-provenance pointers. 1918 1919; CHECK-LABEL: define void @test44( 1920; CHECK-NOT: llvm.objc. 1921; CHECK: {{^}}} 1922define void @test44(ptr %pp) { 1923 %p = load ptr, ptr %pp 1924 %q = call ptr @llvm.objc.retain(ptr %p) 1925 call void @llvm.objc.release(ptr %q) 1926 ret void 1927} 1928 1929; Don't delete retain+release with an unknown-provenance 1930; may-alias llvm.objc.release between them. 1931 1932; CHECK-LABEL: define void @test45( 1933; CHECK: call ptr @llvm.objc.retain(ptr %p) 1934; CHECK: call void @llvm.objc.release(ptr %q) 1935; CHECK: call void @use_pointer(ptr %p) 1936; CHECK: call void @llvm.objc.release(ptr %p) 1937; CHECK: {{^}}} 1938define void @test45(ptr %pp, ptr %qq) { 1939 %p = load ptr, ptr %pp 1940 %q = load ptr, ptr %qq 1941 call ptr @llvm.objc.retain(ptr %p) 1942 call void @llvm.objc.release(ptr %q) 1943 call void @use_pointer(ptr %p) 1944 call void @llvm.objc.release(ptr %p) 1945 ret void 1946} 1947 1948; Don't delete retain and autorelease here. 1949 1950; CHECK-LABEL: define void @test46( 1951; CHECK: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]] 1952; CHECK: true: 1953; CHECK: call ptr @llvm.objc.autorelease(ptr %p) [[NUW]] 1954; CHECK: {{^}}} 1955define void @test46(ptr %p, i1 %a) { 1956entry: 1957 call ptr @llvm.objc.retain(ptr %p) 1958 br i1 %a, label %true, label %false 1959 1960true: 1961 call ptr @llvm.objc.autorelease(ptr %p) 1962 call void @use_pointer(ptr %p) 1963 ret void 1964 1965false: 1966 ret void 1967} 1968 1969; Delete no-op cast calls. 1970 1971; CHECK-LABEL: define ptr @test47( 1972; CHECK-NOT: call 1973; CHECK: ret ptr %p 1974; CHECK: {{^}}} 1975define ptr @test47(ptr %p) nounwind { 1976 %x = call ptr @llvm.objc.retainedObject(ptr %p) 1977 ret ptr %x 1978} 1979 1980; Delete no-op cast calls. 1981 1982; CHECK-LABEL: define ptr @test48( 1983; CHECK-NOT: call 1984; CHECK: ret ptr %p 1985; CHECK: {{^}}} 1986define ptr @test48(ptr %p) nounwind { 1987 %x = call ptr @llvm.objc.unretainedObject(ptr %p) 1988 ret ptr %x 1989} 1990 1991; Delete no-op cast calls. 1992 1993; CHECK-LABEL: define ptr @test49( 1994; CHECK-NOT: call 1995; CHECK: ret ptr %p 1996; CHECK: {{^}}} 1997define ptr @test49(ptr %p) nounwind { 1998 %x = call ptr @llvm.objc.unretainedPointer(ptr %p) 1999 ret ptr %x 2000} 2001 2002; Do delete retain+release with intervening stores of the address value if we 2003; have imprecise release attached to llvm.objc.release. 2004 2005; CHECK-LABEL: define void @test50a( 2006; CHECK-NEXT: call ptr @llvm.objc.retain 2007; CHECK-NEXT: call void @callee 2008; CHECK-NEXT: store 2009; CHECK-NEXT: call void @llvm.objc.release 2010; CHECK-NEXT: ret void 2011; CHECK-NEXT: } 2012define void @test50a(ptr %p, ptr %pp) { 2013 call ptr @llvm.objc.retain(ptr %p) 2014 call void @callee() 2015 store ptr %p, ptr %pp 2016 call void @llvm.objc.release(ptr %p) 2017 ret void 2018} 2019 2020; CHECK-LABEL: define void @test50b( 2021; CHECK-NOT: @llvm.objc. 2022; CHECK: {{^}}} 2023define void @test50b(ptr %p, ptr %pp) { 2024 call ptr @llvm.objc.retain(ptr %p) 2025 call void @callee() 2026 store ptr %p, ptr %pp 2027 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 2028 ret void 2029} 2030 2031 2032; Don't delete retain+release with intervening stores through the 2033; address value. 2034 2035; CHECK-LABEL: define void @test51a( 2036; CHECK: call ptr @llvm.objc.retain(ptr %p) 2037; CHECK: call void @llvm.objc.release(ptr %p) 2038; CHECK: ret void 2039; CHECK: {{^}}} 2040define void @test51a(ptr %p) { 2041 call ptr @llvm.objc.retain(ptr %p) 2042 call void @callee() 2043 store i8 0, ptr %p 2044 call void @llvm.objc.release(ptr %p) 2045 ret void 2046} 2047 2048; CHECK-LABEL: define void @test51b( 2049; CHECK: call ptr @llvm.objc.retain(ptr %p) 2050; CHECK: call void @llvm.objc.release(ptr %p) 2051; CHECK: ret void 2052; CHECK: {{^}}} 2053define void @test51b(ptr %p) { 2054 call ptr @llvm.objc.retain(ptr %p) 2055 call void @callee() 2056 store i8 0, ptr %p 2057 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 2058 ret void 2059} 2060 2061; Don't delete retain+release with intervening use of a pointer of 2062; unknown provenance. 2063 2064; CHECK-LABEL: define void @test52a( 2065; CHECK: call ptr @llvm.objc.retain 2066; CHECK: call void @callee() 2067; CHECK: call void @use_pointer(ptr %z) 2068; CHECK: call void @llvm.objc.release 2069; CHECK: ret void 2070; CHECK: {{^}}} 2071define void @test52a(ptr %zz, ptr %pp) { 2072 %p = load ptr, ptr %pp 2073 %1 = call ptr @llvm.objc.retain(ptr %p) 2074 call void @callee() 2075 %z = load ptr, ptr %zz 2076 call void @use_pointer(ptr %z) 2077 call void @llvm.objc.release(ptr %p) 2078 ret void 2079} 2080 2081; CHECK-LABEL: define void @test52b( 2082; CHECK: call ptr @llvm.objc.retain 2083; CHECK: call void @callee() 2084; CHECK: call void @use_pointer(ptr %z) 2085; CHECK: call void @llvm.objc.release 2086; CHECK: ret void 2087; CHECK: {{^}}} 2088define void @test52b(ptr %zz, ptr %pp) { 2089 %p = load ptr, ptr %pp 2090 %1 = call ptr @llvm.objc.retain(ptr %p) 2091 call void @callee() 2092 %z = load ptr, ptr %zz 2093 call void @use_pointer(ptr %z) 2094 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !0 2095 ret void 2096} 2097 2098; Like test52, but the pointer has function type, so it's assumed to 2099; be not reference counted. 2100; Oops. That's wrong. Clang sometimes uses function types gratuitously. 2101; See rdar://10551239. 2102 2103; CHECK-LABEL: define void @test53( 2104; CHECK: @llvm.objc. 2105; CHECK: {{^}}} 2106define void @test53(ptr %zz, ptr %pp) { 2107 %p = load ptr, ptr %pp 2108 %1 = call ptr @llvm.objc.retain(ptr %p) 2109 call void @callee() 2110 %z = load ptr, ptr %zz 2111 call void @callee_fnptr(ptr %z) 2112 call void @llvm.objc.release(ptr %p) 2113 ret void 2114} 2115 2116; Convert autorelease to release if the value is unused. 2117 2118; CHECK-LABEL: define void @test54( 2119; CHECK: call ptr @returner() 2120; CHECK-NEXT: call void @llvm.objc.release(ptr %t) [[NUW]], !clang.imprecise_release ![[RELEASE]] 2121; CHECK-NEXT: ret void 2122; CHECK: {{^}}} 2123define void @test54() { 2124 %t = call ptr @returner() 2125 call ptr @llvm.objc.autorelease(ptr %t) 2126 ret void 2127} 2128 2129; Nested retain+release pairs. Delete them both. 2130 2131; CHECK-LABEL: define void @test55( 2132; CHECK-NOT: @objc 2133; CHECK: {{^}}} 2134define void @test55(ptr %x) { 2135entry: 2136 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind 2137 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind 2138 call void @llvm.objc.release(ptr %x) nounwind 2139 call void @llvm.objc.release(ptr %x) nounwind 2140 ret void 2141} 2142 2143; Nested retain+release pairs where the inner pair depends 2144; on the outer pair to be removed, and then the outer pair 2145; can be partially eliminated. Plus an extra outer pair to 2146; eliminate, for fun. 2147 2148; CHECK-LABEL: define void @test56( 2149; CHECK-NOT: @objc 2150; CHECK: if.then: 2151; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 2152; CHECK-NEXT: tail call void @use_pointer(ptr %x) 2153; CHECK-NEXT: tail call void @use_pointer(ptr %x) 2154; CHECK-NEXT: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE]] 2155; CHECK-NEXT: br label %if.end 2156; CHECK-NOT: @objc 2157; CHECK: {{^}}} 2158define void @test56(ptr %x, i32 %n) { 2159entry: 2160 %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind 2161 %1 = tail call ptr @llvm.objc.retain(ptr %0) nounwind 2162 %tobool = icmp eq i32 %n, 0 2163 br i1 %tobool, label %if.end, label %if.then 2164 2165if.then: ; preds = %entry 2166 %2 = tail call ptr @llvm.objc.retain(ptr %1) nounwind 2167 tail call void @use_pointer(ptr %2) 2168 tail call void @use_pointer(ptr %2) 2169 tail call void @llvm.objc.release(ptr %2) nounwind, !clang.imprecise_release !0 2170 br label %if.end 2171 2172if.end: ; preds = %entry, %if.then 2173 tail call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 2174 tail call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0 2175 ret void 2176} 2177 2178; When there are adjacent retain+release pairs, the first one is known 2179; unnecessary because the presence of the second one means that the first one 2180; won't be deleting the object. 2181 2182; CHECK-LABEL: define void @test57( 2183; CHECK-NEXT: entry: 2184; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 2185; CHECK-NEXT: call void @use_pointer(ptr %x) 2186; CHECK-NEXT: call void @use_pointer(ptr %x) 2187; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 2188; CHECK-NEXT: call void @use_pointer(ptr %x) 2189; CHECK-NEXT: call void @use_pointer(ptr %x) 2190; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]] 2191; CHECK-NEXT: ret void 2192; CHECK-NEXT: } 2193define void @test57(ptr %x) nounwind { 2194entry: 2195 call ptr @llvm.objc.retain(ptr %x) nounwind 2196 call ptr @llvm.objc.retain(ptr %x) nounwind 2197 call void @use_pointer(ptr %x) 2198 call void @use_pointer(ptr %x) 2199 call void @llvm.objc.release(ptr %x) nounwind 2200 call ptr @llvm.objc.retain(ptr %x) nounwind 2201 call void @use_pointer(ptr %x) 2202 call void @use_pointer(ptr %x) 2203 call void @llvm.objc.release(ptr %x) nounwind 2204 ret void 2205} 2206 2207; An adjacent retain+release pair is sufficient even if it will be 2208; removed itself. 2209 2210; CHECK-LABEL: define void @test58( 2211; CHECK-NEXT: entry: 2212; CHECK-NEXT: @llvm.objc.retain 2213; CHECK-NEXT: call void @use_pointer(ptr %x) 2214; CHECK-NEXT: call void @use_pointer(ptr %x) 2215; CHECK-NEXT: ret void 2216; CHECK-NEXT: } 2217define void @test58(ptr %x) nounwind { 2218entry: 2219 call ptr @llvm.objc.retain(ptr %x) nounwind 2220 call ptr @llvm.objc.retain(ptr %x) nounwind 2221 call void @use_pointer(ptr %x) 2222 call void @use_pointer(ptr %x) 2223 call void @llvm.objc.release(ptr %x) nounwind 2224 call ptr @llvm.objc.retain(ptr %x) nounwind 2225 call void @llvm.objc.release(ptr %x) nounwind 2226 ret void 2227} 2228 2229; Don't delete the second retain+release pair in an adjacent set. 2230 2231; CHECK-LABEL: define void @test59( 2232; CHECK-NEXT: entry: 2233; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]] 2234; CHECK-NEXT: call void @use_pointer(ptr %x) 2235; CHECK-NEXT: call void @use_pointer(ptr %x) 2236; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]] 2237; CHECK-NEXT: ret void 2238; CHECK-NEXT: } 2239define void @test59(ptr %x) nounwind { 2240entry: 2241 %a = call ptr @llvm.objc.retain(ptr %x) nounwind 2242 call void @llvm.objc.release(ptr %x) nounwind 2243 %b = call ptr @llvm.objc.retain(ptr %x) nounwind 2244 call void @use_pointer(ptr %x) 2245 call void @use_pointer(ptr %x) 2246 call void @llvm.objc.release(ptr %x) nounwind 2247 ret void 2248} 2249 2250; Constant pointers to objects don't need reference counting. 2251 2252@constptr = external constant ptr 2253@something = external global ptr 2254 2255; We have a precise lifetime retain/release here. We can not remove them since 2256; @something is not constant. 2257 2258; CHECK-LABEL: define void @test60a( 2259; CHECK: call ptr @llvm.objc.retain 2260; CHECK: call void @llvm.objc.release 2261; CHECK: {{^}}} 2262define void @test60a() { 2263 %t = load ptr, ptr @constptr 2264 %s = load ptr, ptr @something 2265 call ptr @llvm.objc.retain(ptr %s) 2266 call void @callee() 2267 call void @use_pointer(ptr %t) 2268 call void @llvm.objc.release(ptr %s) 2269 ret void 2270} 2271 2272; CHECK-LABEL: define void @test60b( 2273; CHECK: call ptr @llvm.objc.retain 2274; CHECK-NOT: call ptr @llvm.objc.retain 2275; CHECK-NOT: call ptr @llvm.objc.release 2276; CHECK: {{^}}} 2277define void @test60b() { 2278 %t = load ptr, ptr @constptr 2279 %s = load ptr, ptr @something 2280 call ptr @llvm.objc.retain(ptr %t) 2281 call ptr @llvm.objc.retain(ptr %t) 2282 call void @callee() 2283 call void @use_pointer(ptr %s) 2284 call void @llvm.objc.release(ptr %t) 2285 ret void 2286} 2287 2288; CHECK-LABEL: define void @test60c( 2289; CHECK-NOT: @llvm.objc. 2290; CHECK: {{^}}} 2291define void @test60c() { 2292 %t = load ptr, ptr @constptr 2293 %s = load ptr, ptr @something 2294 call ptr @llvm.objc.retain(ptr %t) 2295 call void @callee() 2296 call void @use_pointer(ptr %s) 2297 call void @llvm.objc.release(ptr %t), !clang.imprecise_release !0 2298 ret void 2299} 2300 2301; CHECK-LABEL: define void @test60d( 2302; CHECK-NOT: @llvm.objc. 2303; CHECK: {{^}}} 2304define void @test60d() { 2305 %t = load ptr, ptr @constptr 2306 %s = load ptr, ptr @something 2307 call ptr @llvm.objc.retain(ptr %t) 2308 call void @callee() 2309 call void @use_pointer(ptr %s) 2310 call void @llvm.objc.release(ptr %t) 2311 ret void 2312} 2313 2314; CHECK-LABEL: define void @test60e( 2315; CHECK-NOT: @llvm.objc. 2316; CHECK: {{^}}} 2317define void @test60e() { 2318 %t = load ptr, ptr @constptr 2319 %s = load ptr, ptr @something 2320 call ptr @llvm.objc.retain(ptr %t) 2321 call void @callee() 2322 call void @use_pointer(ptr %s) 2323 call void @llvm.objc.release(ptr %t), !clang.imprecise_release !0 2324 ret void 2325} 2326 2327; Constant pointers to objects don't need to be considered related to other 2328; pointers. 2329 2330; CHECK-LABEL: define void @test61( 2331; CHECK-NOT: @llvm.objc. 2332; CHECK: {{^}}} 2333define void @test61() { 2334 %t = load ptr, ptr @constptr 2335 call ptr @llvm.objc.retain(ptr %t) 2336 call void @callee() 2337 call void @use_pointer(ptr %t) 2338 call void @llvm.objc.release(ptr %t) 2339 ret void 2340} 2341 2342; Delete a retain matched by releases when one is inside the loop and the 2343; other is outside the loop. 2344 2345; CHECK-LABEL: define void @test62( 2346; CHECK-NOT: @llvm.objc. 2347; CHECK: {{^}}} 2348define void @test62(ptr %x, ptr %p) nounwind { 2349entry: 2350 br label %loop 2351 2352loop: 2353 call ptr @llvm.objc.retain(ptr %x) 2354 %q = load i1, ptr %p 2355 br i1 %q, label %loop.more, label %exit 2356 2357loop.more: 2358 call void @llvm.objc.release(ptr %x) 2359 br label %loop 2360 2361exit: 2362 call void @llvm.objc.release(ptr %x) 2363 ret void 2364} 2365 2366; Like test62 but with no release in exit. 2367; Don't delete anything! 2368 2369; CHECK-LABEL: define void @test63( 2370; CHECK: loop: 2371; CHECK: tail call ptr @llvm.objc.retain(ptr %x) 2372; CHECK: loop.more: 2373; CHECK: call void @llvm.objc.release(ptr %x) 2374; CHECK: {{^}}} 2375define void @test63(ptr %x, ptr %p) nounwind { 2376entry: 2377 br label %loop 2378 2379loop: 2380 call ptr @llvm.objc.retain(ptr %x) 2381 %q = load i1, ptr %p 2382 br i1 %q, label %loop.more, label %exit 2383 2384loop.more: 2385 call void @llvm.objc.release(ptr %x) 2386 br label %loop 2387 2388exit: 2389 ret void 2390} 2391 2392; Like test62 but with no release in loop.more. 2393; Don't delete anything! 2394 2395; CHECK-LABEL: define void @test64( 2396; CHECK: loop: 2397; CHECK: tail call ptr @llvm.objc.retain(ptr %x) 2398; CHECK: exit: 2399; CHECK: call void @llvm.objc.release(ptr %x) 2400; CHECK: {{^}}} 2401define void @test64(ptr %x, ptr %p) nounwind { 2402entry: 2403 br label %loop 2404 2405loop: 2406 call ptr @llvm.objc.retain(ptr %x) 2407 %q = load i1, ptr %p 2408 br i1 %q, label %loop.more, label %exit 2409 2410loop.more: 2411 br label %loop 2412 2413exit: 2414 call void @llvm.objc.release(ptr %x) 2415 ret void 2416} 2417 2418; Move an autorelease past a phi with a null. 2419 2420; CHECK-LABEL: define ptr @test65( 2421; CHECK: if.then: 2422; CHECK: call ptr @llvm.objc.autorelease( 2423; CHECK: return: 2424; CHECK-NOT: @llvm.objc.autorelease 2425; CHECK: {{^}}} 2426define ptr @test65(i1 %x) { 2427entry: 2428 br i1 %x, label %return, label %if.then 2429 2430if.then: ; preds = %entry 2431 %c = call ptr @returner() 2432 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind 2433 br label %return 2434 2435return: ; preds = %if.then, %entry 2436 %retval = phi ptr [ %s, %if.then ], [ null, %entry ] 2437 %q = call ptr @llvm.objc.autorelease(ptr %retval) nounwind 2438 ret ptr %retval 2439} 2440 2441; Don't move an autorelease past an autorelease pool boundary. 2442 2443; CHECK-LABEL: define ptr @test65b( 2444; CHECK: if.then: 2445; CHECK-NOT: @llvm.objc.autorelease 2446; CHECK: return: 2447; CHECK: call ptr @llvm.objc.autorelease( 2448; CHECK: {{^}}} 2449define ptr @test65b(i1 %x) { 2450entry: 2451 %t = call ptr @llvm.objc.autoreleasePoolPush() 2452 br i1 %x, label %return, label %if.then 2453 2454if.then: ; preds = %entry 2455 %c = call ptr @returner() 2456 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind 2457 br label %return 2458 2459return: ; preds = %if.then, %entry 2460 %retval = phi ptr [ %s, %if.then ], [ null, %entry ] 2461 call void @llvm.objc.autoreleasePoolPop(ptr %t) 2462 %q = call ptr @llvm.objc.autorelease(ptr %retval) nounwind 2463 ret ptr %retval 2464} 2465 2466; Don't move an autoreleaseReuturnValue, which would break 2467; the RV optimization. 2468 2469; CHECK-LABEL: define ptr @test65c( 2470; CHECK: if.then: 2471; CHECK-NOT: @llvm.objc.autorelease 2472; CHECK: return: 2473; CHECK: call ptr @llvm.objc.autoreleaseReturnValue( 2474; CHECK: {{^}}} 2475define ptr @test65c(i1 %x) { 2476entry: 2477 br i1 %x, label %return, label %if.then 2478 2479if.then: ; preds = %entry 2480 %c = call ptr @returner() 2481 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind 2482 br label %return 2483 2484return: ; preds = %if.then, %entry 2485 %retval = phi ptr [ %s, %if.then ], [ null, %entry ] 2486 %q = call ptr @llvm.objc.autoreleaseReturnValue(ptr %retval) nounwind 2487 ret ptr %retval 2488} 2489 2490; CHECK-LABEL: define ptr @test65d( 2491; CHECK: if.then: 2492; CHECK-NOT: @llvm.objc.autorelease 2493; CHECK: return: 2494; CHECK: call ptr @llvm.objc.autoreleaseReturnValue( 2495; CHECK: {{^}}} 2496define ptr @test65d(i1 %x) { 2497entry: 2498 br i1 %x, label %return, label %if.then 2499 2500if.then: ; preds = %entry 2501 %c = call ptr @returner() 2502 %s = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %c) nounwind 2503 br label %return 2504 2505return: ; preds = %if.then, %entry 2506 %retval = phi ptr [ %s, %if.then ], [ null, %entry ] 2507 %q = call ptr @llvm.objc.autoreleaseReturnValue(ptr %retval) nounwind 2508 ret ptr %retval 2509} 2510 2511; An llvm.objc.retain can serve as a may-use for a different pointer. 2512; rdar://11931823 2513 2514; CHECK-LABEL: define void @test66a( 2515; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]] 2516; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]] 2517; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]] 2518; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]] 2519; CHECK: {{^}}} 2520define void @test66a(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) { 2521entry: 2522 br i1 %tobool, label %cond.true, label %cond.end 2523 2524cond.true: 2525 br label %cond.end 2526 2527cond.end: ; preds = %cond.true, %entry 2528 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ] 2529 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind 2530 tail call void @llvm.objc.release(ptr %call) nounwind 2531 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar 2532 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind 2533 tail call void @llvm.objc.release(ptr %cond) nounwind 2534 ret void 2535} 2536 2537; CHECK-LABEL: define void @test66b( 2538; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]] 2539; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]] 2540; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]] 2541; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]] 2542; CHECK: {{^}}} 2543define void @test66b(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) { 2544entry: 2545 br i1 %tobool, label %cond.true, label %cond.end 2546 2547cond.true: 2548 br label %cond.end 2549 2550cond.end: ; preds = %cond.true, %entry 2551 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ] 2552 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind 2553 tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0 2554 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar 2555 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind 2556 tail call void @llvm.objc.release(ptr %cond) nounwind 2557 ret void 2558} 2559 2560; CHECK-LABEL: define void @test66c( 2561; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]] 2562; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]] 2563; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]] 2564; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]] 2565; CHECK: {{^}}} 2566define void @test66c(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) { 2567entry: 2568 br i1 %tobool, label %cond.true, label %cond.end 2569 2570cond.true: 2571 br label %cond.end 2572 2573cond.end: ; preds = %cond.true, %entry 2574 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ] 2575 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind 2576 tail call void @llvm.objc.release(ptr %call) nounwind 2577 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar 2578 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind, !clang.imprecise_release !0 2579 tail call void @llvm.objc.release(ptr %cond) nounwind 2580 ret void 2581} 2582 2583; CHECK-LABEL: define void @test66d( 2584; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]] 2585; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]] 2586; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]] 2587; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]] 2588; CHECK: {{^}}} 2589define void @test66d(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) { 2590entry: 2591 br i1 %tobool, label %cond.true, label %cond.end 2592 2593cond.true: 2594 br label %cond.end 2595 2596cond.end: ; preds = %cond.true, %entry 2597 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ] 2598 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind 2599 tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0 2600 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar 2601 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind 2602 tail call void @llvm.objc.release(ptr %cond) nounwind, !clang.imprecise_release !0 2603 ret void 2604} 2605 2606; A few real-world testcases. 2607 2608@.str4 = private unnamed_addr constant [33 x i8] c"-[A z] = { %f, %f, { %f, %f } }\0A\00" 2609@"OBJC_IVAR_$_A.myZ" = global i64 20, section "__DATA, __objc_const", align 8 2610declare i32 @printf(ptr captures(none), ...) nounwind 2611declare i32 @puts(ptr captures(none)) nounwind 2612@str = internal constant [16 x i8] c"-[ Top0 _getX ]\00" 2613 2614; FIXME: Should be able to eliminate the retain and release 2615; CHECK-LABEL: define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd) 2616; CHECK: tail call ptr @llvm.objc.retain(ptr %self) 2617; CHECK-NEXT: %call = tail call i32 (ptr, ...) @printf( 2618; CHECK: tail call void @llvm.objc.release(ptr %self) 2619; CHECK: {{^}}} 2620define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd) nounwind { 2621invoke.cont: 2622 %i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind 2623 tail call void @llvm.dbg.value(metadata ptr %self, metadata !DILocalVariable(scope: !2), metadata !DIExpression()), !dbg !DILocation(scope: !2) 2624 tail call void @llvm.dbg.value(metadata ptr %self, metadata !DILocalVariable(scope: !2), metadata !DIExpression()), !dbg !DILocation(scope: !2) 2625 %ivar = load i64, ptr @"OBJC_IVAR_$_A.myZ", align 8 2626 %add.ptr = getelementptr i8, ptr %self, i64 %ivar 2627 %tmp2 = load float, ptr %add.ptr, align 4 2628 %conv = fpext float %tmp2 to double 2629 %add.ptr.sum = add i64 %ivar, 4 2630 %tmp6 = getelementptr inbounds i8, ptr %self, i64 %add.ptr.sum 2631 %tmp7 = load float, ptr %tmp6, align 4 2632 %conv8 = fpext float %tmp7 to double 2633 %add.ptr.sum36 = add i64 %ivar, 8 2634 %tmp12 = getelementptr inbounds i8, ptr %self, i64 %add.ptr.sum36 2635 %tmp13 = load float, ptr %tmp12, align 4 2636 %conv14 = fpext float %tmp13 to double 2637 %tmp12.sum = add i64 %ivar, 12 2638 %arrayidx19 = getelementptr inbounds i8, ptr %self, i64 %tmp12.sum 2639 %tmp20 = load float, ptr %arrayidx19, align 4 2640 %conv21 = fpext float %tmp20 to double 2641 %call = tail call i32 (ptr, ...) @printf(ptr @.str4, double %conv, double %conv8, double %conv14, double %conv21) 2642 %ivar23 = load i64, ptr @"OBJC_IVAR_$_A.myZ", align 8 2643 %add.ptr24 = getelementptr i8, ptr %self, i64 %ivar23 2644 %srcval = load i128, ptr %add.ptr24, align 4 2645 tail call void @llvm.objc.release(ptr %self) nounwind 2646 %tmp29 = trunc i128 %srcval to i64 2647 %tmp30 = bitcast i64 %tmp29 to <2 x float> 2648 %tmp31 = insertvalue { <2 x float>, <2 x float> } undef, <2 x float> %tmp30, 0 2649 %tmp32 = lshr i128 %srcval, 64 2650 %tmp33 = trunc i128 %tmp32 to i64 2651 %tmp34 = bitcast i64 %tmp33 to <2 x float> 2652 %tmp35 = insertvalue { <2 x float>, <2 x float> } %tmp31, <2 x float> %tmp34, 1 2653 ret { <2 x float>, <2 x float> } %tmp35 2654} 2655 2656; FIXME: Should be able to eliminate the retain and release 2657; CHECK-LABEL: @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd) 2658; CHECK: tail call ptr @llvm.objc.retain(ptr %self) 2659; CHECK: %puts = tail call i32 @puts 2660; CHECK: tail call void @llvm.objc.release(ptr %self) 2661define i32 @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd) nounwind { 2662invoke.cont: 2663 %i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind 2664 %puts = tail call i32 @puts(ptr @str) 2665 tail call void @llvm.objc.release(ptr %self) nounwind 2666 ret i32 0 2667} 2668 2669@"\01L_OBJC_METH_VAR_NAME_" = internal global [5 x i8] c"frob\00", section "__TEXT,__cstring,cstring_literals", align 1@"\01L_OBJC_SELECTOR_REFERENCES_" = internal global ptr @"\01L_OBJC_METH_VAR_NAME_", section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2670@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip" 2671@llvm.used = appending global [3 x ptr] [ptr @"\01L_OBJC_METH_VAR_NAME_", ptr @"\01L_OBJC_SELECTOR_REFERENCES_", ptr @"\01L_OBJC_IMAGE_INFO"], section "llvm.metadata" 2672 2673; A simple loop. Eliminate the retain and release inside of it! 2674 2675; CHECK: define void @loop(ptr %x, i64 %n) { 2676; CHECK: for.body: 2677; CHECK-NOT: @llvm.objc. 2678; CHECK: @objc_msgSend 2679; CHECK-NOT: @llvm.objc. 2680; CHECK: for.end: 2681; CHECK: {{^}}} 2682define void @loop(ptr %x, i64 %n) { 2683entry: 2684 %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind 2685 %cmp9 = icmp sgt i64 %n, 0 2686 br i1 %cmp9, label %for.body, label %for.end 2687 2688for.body: ; preds = %entry, %for.body 2689 %i.010 = phi i64 [ %inc, %for.body ], [ 0, %entry ] 2690 %1 = tail call ptr @llvm.objc.retain(ptr %x) nounwind 2691 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8 2692 %call = tail call ptr (ptr, ptr, ...) @objc_msgSend(ptr %1, ptr %tmp5) 2693 tail call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !0 2694 %inc = add nsw i64 %i.010, 1 2695 %exitcond = icmp eq i64 %inc, %n 2696 br i1 %exitcond, label %for.end, label %for.body 2697 2698for.end: ; preds = %for.body, %entry 2699 tail call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0 2700 ret void 2701} 2702 2703; ObjCARCOpt can delete the retain,release on self. 2704 2705; CHECK: define void @TextEditTest(ptr %self, ptr %pboard) { 2706; CHECK-NOT: call ptr @llvm.objc.retain(ptr %tmp7) 2707; CHECK: {{^}}} 2708 2709%0 = type { ptr, ptr } 2710%1 = type opaque 2711%2 = type opaque 2712%3 = type opaque 2713%4 = type opaque 2714%5 = type opaque 2715%struct.NSConstantString = type { ptr, i32, ptr, i64 } 2716%struct._NSRange = type { i64, i64 } 2717%struct.__CFString = type opaque 2718%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] } 2719%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } 2720%struct._class_t = type { ptr, ptr, ptr, ptr, ptr } 2721%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] } 2722%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 } 2723%struct._message_ref_t = type { ptr, ptr } 2724%struct._objc_cache = type opaque 2725%struct._objc_method = type { ptr, ptr, ptr } 2726%struct._objc_protocol_list = type { i64, [0 x ptr] } 2727%struct._prop_list_t = type { i32, i32, [0 x %struct._message_ref_t] } 2728%struct._protocol_t = type { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32 } 2729 2730@"\01L_OBJC_CLASSLIST_REFERENCES_$_17" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2731@kUTTypePlainText = external constant ptr 2732@"\01L_OBJC_SELECTOR_REFERENCES_19" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2733@"\01L_OBJC_SELECTOR_REFERENCES_21" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2734@"\01L_OBJC_SELECTOR_REFERENCES_23" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2735@"\01L_OBJC_SELECTOR_REFERENCES_25" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2736@"\01L_OBJC_CLASSLIST_REFERENCES_$_26" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2737@"\01L_OBJC_SELECTOR_REFERENCES_28" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2738@"\01L_OBJC_CLASSLIST_REFERENCES_$_29" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2739@"\01L_OBJC_SELECTOR_REFERENCES_31" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2740@"\01L_OBJC_SELECTOR_REFERENCES_33" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2741@"\01L_OBJC_SELECTOR_REFERENCES_35" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2742@"\01L_OBJC_SELECTOR_REFERENCES_37" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2743@"\01L_OBJC_CLASSLIST_REFERENCES_$_38" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2744@"\01L_OBJC_SELECTOR_REFERENCES_40" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2745@"\01L_OBJC_SELECTOR_REFERENCES_42" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2746@_unnamed_cfstring_44 = external hidden constant %struct.NSConstantString, section "__DATA,__cfstring" 2747@"\01L_OBJC_SELECTOR_REFERENCES_46" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2748@"\01L_OBJC_SELECTOR_REFERENCES_48" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2749@"\01l_objc_msgSend_fixup_isEqual_" = external hidden global %0, section "__DATA, __objc_msgrefs, coalesced", align 16 2750@"\01L_OBJC_CLASSLIST_REFERENCES_$_50" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2751@NSCocoaErrorDomain = external constant ptr 2752@"\01L_OBJC_CLASSLIST_REFERENCES_$_51" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2753@NSFilePathErrorKey = external constant ptr 2754@"\01L_OBJC_SELECTOR_REFERENCES_53" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2755@"\01L_OBJC_SELECTOR_REFERENCES_55" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2756@"\01L_OBJC_CLASSLIST_REFERENCES_$_56" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8 2757@"\01L_OBJC_SELECTOR_REFERENCES_58" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2758@"\01L_OBJC_SELECTOR_REFERENCES_60" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" 2759 2760declare ptr @truncatedString(ptr, i64) 2761define void @TextEditTest(ptr %self, ptr %pboard) { 2762entry: 2763 %err = alloca ptr, align 8 2764 %tmp8 = call ptr @llvm.objc.retain(ptr %self) nounwind 2765 store ptr null, ptr %err, align 8 2766 %tmp1 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_17", align 8 2767 %tmp2 = load ptr, ptr @kUTTypePlainText, align 8 2768 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_19", align 8 2769 %call5 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp1, ptr %tmp3, ptr %tmp2) 2770 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_21", align 8 2771 %call76 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %pboard, ptr %tmp5, ptr %call5) 2772 %tmp9 = call ptr @llvm.objc.retain(ptr %call76) nounwind 2773 %tobool = icmp eq ptr %tmp9, null 2774 br i1 %tobool, label %end, label %land.lhs.true 2775 2776land.lhs.true: ; preds = %entry 2777 %tmp11 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_23", align 8 2778 %call137 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %pboard, ptr %tmp11, ptr %tmp9) 2779 %tmp10 = call ptr @llvm.objc.retain(ptr %call137) nounwind 2780 call void @llvm.objc.release(ptr null) nounwind 2781 %tmp12 = call ptr @llvm.objc.retain(ptr %call137) nounwind 2782 call void @llvm.objc.release(ptr null) nounwind 2783 %tobool16 = icmp eq ptr %call137, null 2784 br i1 %tobool16, label %end, label %if.then 2785 2786if.then: ; preds = %land.lhs.true 2787 %tmp19 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 8 2788 %call21 = call signext i8 @objc_msgSend(ptr %call137, ptr %tmp19) 2789 %tobool22 = icmp eq i8 %call21, 0 2790 br i1 %tobool22, label %if.then44, label %land.lhs.true23 2791 2792land.lhs.true23: ; preds = %if.then 2793 %tmp24 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 8 2794 %tmp26 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 8 2795 %call2822 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp24, ptr %tmp26, ptr %call137) 2796 %tmp14 = call ptr @llvm.objc.retain(ptr %call2822) nounwind 2797 call void @llvm.objc.release(ptr null) nounwind 2798 %tobool30 = icmp eq ptr %call2822, null 2799 br i1 %tobool30, label %if.then44, label %if.end 2800 2801if.end: ; preds = %land.lhs.true23 2802 %tmp32 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 8 2803 %tmp33 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 8 2804 %call35 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp32, ptr %tmp33) 2805 %tmp37 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 8 2806 %call3923 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call35, ptr %tmp37, ptr %call2822, i32 signext 1, ptr %err) 2807 %cmp = icmp eq ptr %call3923, null 2808 br i1 %cmp, label %if.then44, label %end 2809 2810if.then44: ; preds = %if.end, %land.lhs.true23, %if.then 2811 %url.025 = phi ptr [ %call2822, %if.end ], [ %call2822, %land.lhs.true23 ], [ null, %if.then ] 2812 %tmp49 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_35", align 8 2813 %call51 = call %struct._NSRange @objc_msgSend(ptr %call137, ptr %tmp49, i64 0, i64 0) 2814 %call513 = extractvalue %struct._NSRange %call51, 0 2815 %call514 = extractvalue %struct._NSRange %call51, 1 2816 %tmp52 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_37", align 8 2817 %call548 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call137, ptr %tmp52, i64 %call513, i64 %call514) 2818 %tmp55 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_38", align 8 2819 %tmp56 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_40", align 8 2820 %call58 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp55, ptr %tmp56) 2821 %tmp59 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_42", align 8 2822 %call6110 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call548, ptr %tmp59, ptr %call58) 2823 %tmp15 = call ptr @llvm.objc.retain(ptr %call6110) nounwind 2824 call void @llvm.objc.release(ptr %call137) nounwind 2825 %tmp64 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_46", align 8 2826 %call66 = call signext i8 @objc_msgSend(ptr %call6110, ptr %tmp64, ptr @_unnamed_cfstring_44) 2827 %tobool67 = icmp eq i8 %call66, 0 2828 br i1 %tobool67, label %if.end74, label %if.then68 2829 2830if.then68: ; preds = %if.then44 2831 %tmp70 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_48", align 8 2832 %call7220 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call6110, ptr %tmp70) 2833 %tmp16 = call ptr @llvm.objc.retain(ptr %call7220) nounwind 2834 call void @llvm.objc.release(ptr %call6110) nounwind 2835 br label %if.end74 2836 2837if.end74: ; preds = %if.then68, %if.then44 2838 %filename.0.in = phi ptr [ %call7220, %if.then68 ], [ %call6110, %if.then44 ] 2839 %tmp17 = load ptr, ptr @"\01l_objc_msgSend_fixup_isEqual_", align 16 2840 %call78 = call signext i8 (ptr, ptr, ptr, ...) %tmp17(ptr %call137, ptr @"\01l_objc_msgSend_fixup_isEqual_", ptr %filename.0.in) 2841 %tobool79 = icmp eq i8 %call78, 0 2842 br i1 %tobool79, label %land.lhs.true80, label %if.then109 2843 2844land.lhs.true80: ; preds = %if.end74 2845 %tmp82 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 8 2846 %call84 = call signext i8 @objc_msgSend(ptr %filename.0.in, ptr %tmp82) 2847 %tobool86 = icmp eq i8 %call84, 0 2848 br i1 %tobool86, label %if.then109, label %if.end106 2849 2850if.end106: ; preds = %land.lhs.true80 2851 %tmp88 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 8 2852 %tmp90 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 8 2853 %call9218 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp88, ptr %tmp90, ptr %filename.0.in) 2854 %tmp21 = call ptr @llvm.objc.retain(ptr %call9218) nounwind 2855 call void @llvm.objc.release(ptr %url.025) nounwind 2856 %tmp94 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 8 2857 %tmp95 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 8 2858 %call97 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp94, ptr %tmp95) 2859 %tmp99 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 8 2860 %call10119 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call97, ptr %tmp99, ptr %call9218, i32 signext 1, ptr %err) 2861 %phitmp = icmp eq ptr %call10119, null 2862 br i1 %phitmp, label %if.then109, label %end 2863 2864if.then109: ; preds = %if.end106, %land.lhs.true80, %if.end74 2865 %url.129 = phi ptr [ %call9218, %if.end106 ], [ %url.025, %if.end74 ], [ %url.025, %land.lhs.true80 ] 2866 %tmp110 = load ptr, ptr %err, align 8 2867 %tobool111 = icmp eq ptr %tmp110, null 2868 br i1 %tobool111, label %if.then112, label %if.end125 2869 2870if.then112: ; preds = %if.then109 2871 %tmp113 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_50", align 8 2872 %tmp114 = load ptr, ptr @NSCocoaErrorDomain, align 8 2873 %tmp115 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_51", align 8 2874 %call117 = call ptr @truncatedString(ptr %filename.0.in, i64 1034) 2875 %tmp118 = load ptr, ptr @NSFilePathErrorKey, align 8 2876 %tmp119 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_53", align 8 2877 %call12113 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp115, ptr %tmp119, ptr %call117, ptr %tmp118, ptr null) 2878 %tmp122 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_55", align 8 2879 %call12414 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp113, ptr %tmp122, ptr %tmp114, i64 258, ptr %call12113) 2880 %tmp23 = call ptr @llvm.objc.retain(ptr %call12414) nounwind 2881 %tmp25 = call ptr @llvm.objc.autorelease(ptr %tmp23) nounwind 2882 store ptr %tmp25, ptr %err, align 8 2883 br label %if.end125 2884 2885if.end125: ; preds = %if.then112, %if.then109 2886 %tmp127 = phi ptr [ %tmp110, %if.then109 ], [ %tmp25, %if.then112 ] 2887 %tmp126 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_56", align 8 2888 %tmp128 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_58", align 8 2889 %call13015 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp126, ptr %tmp128, ptr %tmp127) 2890 %tmp131 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_60", align 8 2891 %call13317 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call13015, ptr %tmp131) 2892 br label %end 2893 2894end: ; preds = %if.end125, %if.end106, %if.end, %land.lhs.true, %entry 2895 %filename.2 = phi ptr [ %filename.0.in, %if.end106 ], [ %filename.0.in, %if.end125 ], [ %call137, %land.lhs.true ], [ null, %entry ], [ %call137, %if.end ] 2896 %origFilename.0 = phi ptr [ %call137, %if.end106 ], [ %call137, %if.end125 ], [ %call137, %land.lhs.true ], [ null, %entry ], [ %call137, %if.end ] 2897 %url.2 = phi ptr [ %call9218, %if.end106 ], [ %url.129, %if.end125 ], [ null, %land.lhs.true ], [ null, %entry ], [ %call2822, %if.end ] 2898 call void @llvm.objc.release(ptr %tmp9) nounwind, !clang.imprecise_release !0 2899 call void @llvm.objc.release(ptr %url.2) nounwind, !clang.imprecise_release !0 2900 call void @llvm.objc.release(ptr %origFilename.0) nounwind, !clang.imprecise_release !0 2901 call void @llvm.objc.release(ptr %filename.2) nounwind, !clang.imprecise_release !0 2902 call void @llvm.objc.release(ptr %self) nounwind, !clang.imprecise_release !0 2903 ret void 2904} 2905 2906declare i32 @__gxx_personality_v0(...) 2907 2908declare i32 @llvm.objc.sync.enter(ptr) 2909declare i32 @llvm.objc.sync.exit(ptr) 2910 2911; Make sure that we understand that objc_sync_{enter,exit} are IC_User not 2912; IC_Call/IC_CallOrUser. 2913 2914; CHECK-LABEL: define void @test67( 2915; CHECK-NEXT: call i32 @llvm.objc.sync.enter(ptr %x) 2916; CHECK-NEXT: call i32 @llvm.objc.sync.exit(ptr %x) 2917; CHECK-NEXT: ret void 2918; CHECK-NEXT: } 2919define void @test67(ptr %x) { 2920 call ptr @llvm.objc.retain(ptr %x) 2921 call i32 @llvm.objc.sync.enter(ptr %x) 2922 call i32 @llvm.objc.sync.exit(ptr %x) 2923 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0 2924 ret void 2925} 2926 2927; CHECK-LABEL: define void @test68( 2928; CHECK-NOT: call 2929; CHECK: call void @callee2( 2930; CHECK-NOT: call 2931; CHECK: ret void 2932 2933define void @test68(ptr %a, ptr %b) { 2934 call ptr @llvm.objc.retain(ptr %a) 2935 call ptr @llvm.objc.retain(ptr %b) 2936 call void @callee2(ptr %a, ptr %b) 2937 call void @llvm.objc.release(ptr %b), !clang.imprecise_release !0 2938 call void @llvm.objc.release(ptr %a), !clang.imprecise_release !0 2939 ret void 2940} 2941 2942!llvm.module.flags = !{!1} 2943!llvm.dbg.cu = !{!3} 2944 2945!0 = !{} 2946!1 = !{i32 1, !"Debug Info Version", i32 3} 2947!2 = distinct !DISubprogram(unit: !3) 2948!3 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", 2949 file: !4, 2950 isOptimized: true, flags: "-O2", 2951 splitDebugFilename: "abc.debug", emissionKind: 2) 2952!4 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") 2953!5 = !{i32 2, !"Debug Info Version", i32 3} 2954 2955; CHECK: attributes [[NUW]] = { nounwind } 2956; CHECK: ![[RELEASE]] = !{} 2957