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